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

cho*_*gv3 4 port nginx docker

我最近决定将我的开发环境从原生 mac 迁移到 docker for mac,我希望多个项目公开相同的 80 端口,这样我就可以简单地输入http://app1.dev/http://浏览器中的app2.dev/而不记得几十个端口号。

我不必在本机环境上做任何事情来实现这一点。但是由于现在 nginx 在每个容器中单独运行,它们在端口公开上发生冲突。我也知道我可以使用指向外部容器的外部链接,但我不想拆散我的 docker-compose.yml 文件,我只想将所有内容合而为一。

docker-compose.yml 在 ~/demo1/

version: '3'
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
# ... 
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml 在 ~/demo2/

version: '3'
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
# ...
Run Code Online (Sandbox Code Playgroud)

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

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.
Run Code Online (Sandbox Code Playgroud)

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

Man*_*ani 5

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

为了解决这个问题,你可以运行另一个虚拟的Nginx它只是做proxy_passdemo1的DEMO2。在这种情况下,http://app将父母的Nginx和/dev1意志proxy_passdemo1的/dev2proxy_passDEMO2

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

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

父 Nginx 组成:

version: '3'
services:
  parent:
    image: nginx:alpine
    volume:
         - ./nginx.conf:/etc/nginx/nginx.conf
    ports:
         - 80:80
networks:
  default:
    external:
      name: dev
Run Code Online (Sandbox Code Playgroud)

父 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml 在 ~/demo1/

version: '3'
services:
  web:
    image: nginx:alpine
  networks:
    default:
       aliases:
          - dev1
networks:
  default:
    external:
      name: dev
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml 在 ~/demo2/

version: '3'
services:
  web:
    image: nginx:alpine
  networks:
    default:
       aliases:
          - dev2
networks:
  default:
    external:
      name: dev
Run Code Online (Sandbox Code Playgroud)

现在您可以通过使用http://app/dev2 访问URL http://app/dev1demo2来使用demo1

参考:

  1. NGINX 反向代理
  2. NGINX proxy_pass
  3. NGINX 解析器
  4. docker DNS 的必要性
  5. Docker 容器网络