docker 的 nginx 没有正确代理到我的 ruby 应用程序

nginx with docker not proxying onto my ruby application correctly

我有两个 Docker 容器(由自定义配置的 nginx 和 Ruby 图像构建),当我 运行 容器并发出请求时,它们似乎将请求代理到正确的位置(但被代理到的服务之一不能正确处理请求)。

即当我尝试代理到我的 Ruby 容器时,我要么收到 "Sinatra doesn't recognise this ditty" 错误,要么收到“301 重定向”?

Note: code can be found here as well https://github.com/Integralist/Docker-Examples/tree/master/Nginx

下面是 nginx 的Docker文件:

FROM ubuntu

# install nginx
RUN apt-get update && apt-get install -y nginx
RUN rm -rf /etc/nginx/sites-enabled/default

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

下面是 Ruby 应用程序的 Docker 文件:

FROM ruby:2.1-onbuild
CMD ["ruby", "app.rb"]

Note:
Someone asked how my app.rb and other dependencies were being loaded (as my docker run wasn't mounting them and the Dockerfile doesn't appear to add them). If you look at the ruby "onbuild" tagged version of the image you'll see it COPY's all those files for us https://github.com/docker-library/ruby/2.0/onbuild/Dockerfile

Ruby 应用程序如下所示:

require "sinatra"

set :bind, "0.0.0.0"

get "/" do
  "Hello World"
end

nginx.conf 文件如下所示:

user nobody nogroup;
worker_processes auto;          # auto-detect number of logical CPU cores

events {
  worker_connections 512;       # set the max number of simultaneous connections (per worker process)
}

http {
  upstream app {
    server app:4567;            # app is automatically defined inside /etc/hosts by Docker
  }

  server {
    listen *:80;                # Listen for incoming connections from any interface on port 80
    server_name "";             # Don't worry if "Host" HTTP Header is empty or not set
    root /usr/share/nginx/html; # serve static files from here

    location /app/ {            # catch any requests that start with /app/
      proxy_pass http://app;    # proxy requests onto our app server (i.e. a different container)
    }
  }
}

我运行 Ruby 容器是这样的:

docker run --name ruby-app -p 4567:4567 -d my-ruby-app

我运行 nginx 容器是这样的:

docker run --name nginx-container \
  -v $(pwd)/html:/usr/share/nginx/html:ro \
  -v $(pwd)/docker-nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
  --link ruby-app:app \
  -P -d my-nginx

如果我 运行 curl http://$(boot2docker ip):32785/app/ 我返回 "Sinatra doesn't know this ditty" 错误;如果我 运行 curl http://$(boot2docker ip):32785/app 我收到 301 Moved Permanently 消息?

我确定我遗漏了一些非常明显的东西(也许 Sinatra 是如何配置的?比如我需要设置一个 /app 路由吗?或者我应该使用一个 alias 指令在 nginx.conf 一些如何)

感谢任何帮助。

所以我认为您正在设置的内容和正在测试的内容存在一些基本问题。

首先你在 nginx 中说,"When you get /app/, proxy it to the container running sinatra":

location /app/ {            # catch any requests that start with /app/
  proxy_pass http://app;    # proxy requests onto our app server (i.e. a different container)
}

所以这将被传递给 sinatra,请求 URI 为 /app/

由于您的 sinatra 应用程序没有定义该路由,这就是为什么您会收到“Sinatra 不知道这个小东西”的原因。

当您在没有尾部斜杠的情况下尝试它时得到 301 的原因是因为 sinatra 会自动重定向任何没有尾部斜杠的内容。

正如德克提到的,击球时你得到 'Hello world' 的原因:

curl http://$(boot2docker ip):4567/

是因为你的sinatra路由中定义了那个路由,如果你点击:

curl http://$(boot2docker ip):4567

那么你应该得到一个 301 重定向到 /.

要解决您的问题,您需要:

  1. 将您在 sinatra 中的路由更改为“/app”。
  2. 将您的 nginx 位置更改为 / 而不是 /app/。

选项 2 将是最灵活的,因为对 nginx 容器的任何请求都将直接映射到 sinatra 容器,就像你添加了另一条路由一样,你需要再次更新 nginx 配置才能添加这条路由代理到 sinatra 容器。

所以看起来答案似乎是 nginx 位置块如何工作的一个微妙之处...

如果你没有在上游名称的末尾加上正斜杠 /,你会发现 nginx 将请求作为 /app/ 而不仅仅是 /

在上游名称后加上 / 意味着它更像 alias 指令。

所以,这有效...

location /app/ {
  proxy_pass http://app/; # this is what I want
}

但这行不通...

location /app/ {
  proxy_pass http://app; # this ISN'T what I want
}