如何在使用 docker 时为多个项目共享(公开)端口 80

How to share(expose) port 80 for multiple projects while using docker

我最近决定将我的开发环境从本机 mac 迁移到 docker mac,并且我希望多个项目公开相同的端口 80,以便我可以在浏览器中简单地输入http://app1.dev/ and http://app2.dev/而不用记住几十个端口号

我无需在本机环境中执行任何操作即可实现此目的。但由于现在 nginx 在每个容器中单独运行,它们在端口暴露方面存在冲突。 我也知道我可以使用外部 link 到外部容器,但我不想拆开我的 docker-compose.yml 文件,我只想把所有东西都放在一起。

docker-compose.yml 在 ~/demo1/

version: '3'
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
# ... 

docker-compose.yml 在 ~/demo2/

version: '3'
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
# ...

当我在 demo2 中发出命令 docker-compose up -d 时,我得到:

Creating network "demo2_default" with the default driver
Creating demo2_web_1 ... error

ERROR: for demo2_web_1  Cannot start service web: driver failed 
programming external connectivity on endpoint demo2_web_1 
(cbfebd1550e944ae468a1118eb07574029a6109409dd34799bfdaf72cdeb3d35): 
Bind for 0.0.0.0:80 failed: port is already allocated

ERROR: for web  Cannot start service web: driver failed programming 
external connectivity on endpoint demo2_web_1 
(cbfebd1550e944ae468a1118eb07574029a6109409dd34799bfdaf72cdeb3d35): 
Bind for 0.0.0.0:80 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.

有没有办法让它们共享同一个端口,或者在不使用额外命令创建外部容器的情况下将端口从主机重新映射到容器? 或者有没有办法在 docker-compose.yml 文件中创建外部容器?

您不能将多个容器端口映射到同一个主机端口。无论第一个出现的容器都将绑定到端口 80,如果您尝试绑定同一个端口,第二个容器将抛出已在使用的端口。

要解决此问题,您可以 运行 另一个虚拟 Nginx,它只是 proxy_passdemo1demo2。在这种情况下,http://app 将是 Nginx 的父级,/dev1proxy_passdemo1 并且 /dev2proxy_passdemo2

这里,你只需要将父级Nginx的端口绑定到主机即可。如果将所有这些连接到同一个网络并使用 docker service discovery. If you follow these then you will hit ,则不需要绑定子 Nginx 的端口,即:Nginx 将缓存使用服务发现解析的容器的 IP,并将始终使用该 IP 访问容器。一旦子容器重新启动,子容器的 IP 地址可能会更改,因此父 Nginx 抛出 502。要解决这个问题,每次重启 demo1demo2 时都必须重启父级 Nginx。要解决此问题,您必须使用 resolver 作为 127.0.0.11 并在父 Nginx 中具有有效性。所以每次 Nginx 都会根据有效性尝试解析 IP 地址 post 上次解析。

我添加了虚拟配置文件,总结了以上所有要点。

父级 Nginx 组合:

version: '3'
services:
  parent:
    image: nginx:alpine
    volume:
         - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
         - 80:80
networks:
  default:
    external:
      name: dev

父级 Nginx 配置 (./nginx.conf):

server {
    listen 80;

    resolver 127.0.0.11 valid=5s; #this is local docker DNS and the internal IP getting resolved will be valid only for 5 seconds.

    location /app/dev1 {
        proxy_pass http://dev1:80;
    }

    location /app/dev2 {
        proxy_pass http://dev2:80;
    }
}

docker-compose.yml 在 ~/demo1/

version: '3'
services:
  web:
    image: nginx:alpine
  networks:
    default:
       aliases:
          - dev1
networks:
  default:
    external:
      name: dev

docker-compose.yml 在 ~/demo2/

version: '3'
services:
  web:
    image: nginx:alpine
  networks:
    default:
       aliases:
          - dev2
networks:
  default:
    external:
      name: dev

现在您可以通过点击 URL http://app/dev1 and demo2 by using http://app/dev2.

来使用 demo1

参考文献:

  1. NGINX Reverse Proxy
  2. NGINX proxy_pass
  3. NGINX resolver
  4. Docker container networking