【问题标题】:How to configure nginx with multiple docker-compose.yml files?如何使用多个 docker-compose.yml 文件配置 nginx?
【发布时间】:2021-12-03 03:19:04
【问题描述】:

如果我想用我的 docker 容器设置 nginx,一种选择是在我的docker-compose.yml 中设置 nginx 实例,并将 nginx 容器链接到所有应用程序容器。

然而,这种方法的缺点是docker-compose.yml 变成了服务器级别,因为只有一个 nginx 容器可以将端口 80/443 暴露给互联网。

我对能够在同一台服务器上定义多个 docker-compose.yml 文件感兴趣,但仍然可以通过单个服务器特定的 nginx 容器轻松地在每个 compose 文件中公开面向公众的容器。

我觉得这应该很容易,但我一直找不到很好的资源或示例。

【问题讨论】:

  • 你想要一个用于 NGINX 的 docker-compose.yml,一个用于容器集 #1,另一个用于容器集 #2 等等,这样你就可以启动和停止一些容器集而不影响其他容器集?
  • 没错。因此,即使它们存在于不同的网络上,NGINX 也会反向代理其中的应用程序容器。或者 NGINX 可能存在于没有 compose 的默认网络上——这并不重要。

标签: docker nginx docker-compose


【解决方案1】:

首先,您需要为 nginx 和代理容器创建一个网络:

docker network create nginx_network

接下来,在 compose 文件中配置 nginx 容器,如下所示:

services:
  nginx:
    image: your_nginx_image
    ports:
      - "80:80"
      - "443:443"
    networks:
      - nginx_network
networks:
  nginx_network:
    external: true

之后您可以运行代理容器:

services:
  webapp1:
    image: ...
    container_name: mywebapp1
    networks:
      - nginx_network      # proxy and app must be in same network
      - webapp1_db_network # you can use additional networks for some stuff
  database:
    image: ...
    networks:
      - webapp1_db_network
networks:
  nginx_network:
    external: true
  webapp1_db_network: ~ # this network won't be accessible from outside

另外,为了使这项工作你需要正确配置你的 nginx:

server {
    listen 80;
    server_name your_app.example.com;
    
    # Docker DNS
    resolver 127.0.0.11;
  
    location / {
        # hack to prevent nginx to resolve container's host on start up
        set $docker_host "mywebapp1";
        proxy_pass http://$docker_host:8080;
    }
}

您需要告诉 nginx 使用 Docker 的 DNS,这样它才能通过容器名称访问容器。

但请注意,如果您在其他容器之前运行 nginx 容器,那么 nginx 将尝试解析另一个容器的主机并失败,因为其他容器尚未运行。您可以使用 hack 将主机放入变量中。有了这个 hack,nginx 在收到请求之前不会尝试解析主机。

通过这种组合,您可以让 nginx 始终启动,同时独立启动和停止代理应用程序。

更新:

如果你想要一个更动态的解决方案,你可以修改 nginx 配置如下:

server {
    listen 80;
    resolver 127.0.0.11;
    
    # define server_name with regexp which will read subdomain into variable
    server_name ~^(?<webapp>.+)\.example\.com;

    location / {
        # use variable from regexp to pass request to desired container
        proxy_pass http://$webapp:8080;
    }
}

使用此配置,对 webapp1.example.com 的请求将被传递到容器“webapp1”,webapp2.example.com 到“webapp2”等。您只需添加 DNS 记录并使用正确名称运行应用程序容器。

【讨论】:

  • 嗯,这个解决方案的问题是每个应用程序的撰写文件都需要引用该服务器特定的设置。这似乎不是很动态。如果我们假设我不能编辑应用程序编写文件,而只能控制它们何时/如何执行 - 以及 NGINX 编写文件。这可行吗?
  • 不要在proxy_pass http://$docker_host 的末尾添加斜线非常重要,如果添加它,您将始终获得每个请求的索引文件。错误映射proxy_pass http://$docker_host/
【解决方案2】:

公认的答案很好,但由于我现在正处于这个问题的困境中,我将通过我的调试步骤对其进行扩展,希望它可以帮助某人(我自己在未来?)

Docker-compose 项目经常使用 nginx 作为反向代理来将 http 流量路由到其他 docker 服务。 nginx 是我的projectfolder/docker-compose.yml 中的一个服务,它连接到两个 docker 网络。

一个是我在projectfolder/docker-compose.yml 上使用docker-compose up 时创建的默认网络(它被命名为projectfolder_default 并且服务默认连接到它,除非您有一个networks 属性用于您的服务与另一个网络,然后确保将 - default 添加到列表中)。当我运行 docker network ls 时,我在列表中看到了 projectfolder_default,当我运行 docker network inspect projectfolder_default 时,我看到了 nginx 容器,所以一切都很好。

另一个是我自己建立的名为my_custom_network 的网络。我有一个启动脚本,如果它不存在使用 https://stackoverflow.com/a/53052379/13815107 创建它,我需要它来与 otherproject/docker-compose.yml 中的 web 服务对话。我已将my_custom_network 正确添加到:

  • nginxprojectfolder/docker-compose.yml 的服务网络列表
  • 底部projectfolder/docker-compose.yml
  • webotherproject/docker-compose.yml 中的服务网络
  • 底部otherproject/docker-compose.yml

网络出现并使用docker network lsdocker network inspect my_custom_network 拥有正确的容器

但是,我假设 server.conf 中的 proxy_pass 到 http://web 将映射到 docker 服务 web.projectfolder_default。我错了。为了测试这一点,我在 nginx 容器 (docker exec -it nginx sh) 上打开了 shell。当我使用ping web(可能需要apt-get updateapt-get install iputils-ping)时它成功了,但是它打印了一个带有my_custom_network的url,这就是我发现错误的方式。

更新:我尝试在server.conf.template 中使用http://web.my_custom_network,它的路由效果很好,但是我的webapp(基于Django)被url 中的下划线阻塞了。我在otherproject/docker-compose.yml 中将web 重命名为web2,然后使用docker stop otherproject_webdocker rm otherproject_web 之类的东西来摆脱坏的。

项目文件夹/docker-compose.yml

  services:
    # http://web did NOT map to this service!! Use http://web.main_default or change the names
    web:
      ... 
    nginx:
        ...
      links:
        - web
      networks:
        - default
        - my_custom_network
    ...
  networks:
    - my_custom_network
      external: true

其他项目/docker-compose.yml

  services:
    # http://web connected to this service instead. You could use http://web.my_custom_network to call it out instead
    web:
      ... 
      networks:
        - default
        - my_custom_network
    ...
  networks:
    - my_custom_network
      external: true

projectfolder/.../nginx/server.conf.template(在 Dockerfile 旁边) ...

server {

    ...

    location /auth {
        internal;
        # This routed to wrong 'web'
        proxy_pass              http://web:9001;
        proxy_pass_request_body off;
        proxy_set_header        Content-Length "";
    }

    location / {
        alias /data/dist/;
    }

    location /robots.txt {
        alias /robots.txt;
    }

    # Project Folder backend
    location ~ ^/(api|login|logout)/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
        # This routed to wrong 'web'
        proxy_pass http://web:9001;
    }

    # Other project UI
    location /other-project {
        alias /data/other-project-client/dist/;
    }

    # Other project Django server
    location ~ ^/other-project/(rest)/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
        # nginx will route, but won't work some frameworks like django (it doesn't like underscores)
        # I would rename this web2 in yml and use http://web2
        proxy_pass http://web.my_custom_network:8000;
    }
}

【讨论】:

    猜你喜欢
    • 2021-09-26
    • 2021-08-18
    • 1970-01-01
    • 2019-11-27
    • 2022-08-08
    • 1970-01-01
    • 2019-06-09
    • 1970-01-01
    • 2017-06-18
    相关资源
    最近更新 更多