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

时间:2018-12-21 09:27:22

标签: docker nginx port

我最近决定将开发环境从本地Mac迁移到Mac的docker,我希望多个项目公开相同的端口80,以便我可以简单地键入http://app1.dev/和{{3} },而不会记住数十个端口号。

我无需在本机环境上执行任何操作即可达到此目的。但是,由于现在nginx在每个容器中分别运行,因此它们在端口公开时会发生冲突。 我也知道我可以使用到外部容器的外部链接,但我不想拆开docker-compose.yml文件,我只想将所有内容都打包在一起。

〜/ demo1 /

中的docker-compose.yml
version: '3'
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
# ... 

〜/ demo2 /

中的docker-compose.yml
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文件中创建外部容器?

1 个答案:

答案 0 :(得分:2)

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

要解决此问题,您可以运行另一个虚拟 Nginx ,只需对{strong> demo1 和 demo2 proxy_pass。在这种情况下,http://app将是父Nginx,/dev1将是proxy_pass demo1 ,而/dev2将是proxy_pass demo2

在这里,您只需要将父Nginx的端口绑定到主机即可。如果将所有这些端口都连接到同一网络并使用docker service discovery,则不需要绑定子Nginx的端口。如果遵循这些规则,那么您将命中another problem,即:Nginx将缓存使用服务发现解决的容器的IP,并将始终使用该IP来访问容器。重新启动子容器后,子容器的IP地址可能会更改,因此父Nginx会抛出 502 。为了解决这个问题,您每次重新启动 demo1 demo2 时,都必须重新启动父级Nginx。为了解决这个问题,您必须在父Nginx中使用resolver作为127.0.0.11并具有有效性。因此,每次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

父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;
    }
}

〜/ demo1 /

中的docker-compose.yml
version: '3'
services:
  web:
    image: nginx:alpine
  networks:
    default:
       aliases:
          - dev1
networks:
  default:
    external:
      name: dev

〜/ demo2 /

中的docker-compose.yml
version: '3'
services:
  web:
    image: nginx:alpine
  networks:
    default:
       aliases:
          - dev2
networks:
  default:
    external:
      name: dev

现在,您可以通过点击URL http://app/dev1来使用demo1,而使用http://app/dev2来访问demo2。

参考文献:

  1. NGINX Reverse Proxy
  2. NGINX proxy_pass
  3. NGINX resolver
  4. Necessity of docker DNS
  5. Docker container networking