如何在使用Docker的同时为多个项目共享(暴露)端口80 [英] How to share(expose) port 80 for multiple projects while using docker
问题描述
我最近决定将开发环境从本地Mac迁移到Mac的Docker,并且我希望多个项目公开相同的端口80,以便我可以简单地键入 http://app2 .dev/在浏览器中,而不会记住数十个端口号.
I am recently decided to migrate my dev environment from native mac to docker for mac, and I would like to have multiple projects expose the same port 80, so that I can simply type http://app1.dev/ and http://app2.dev/ in the browser without remembering dozens of port numbers.
我无需在本机环境上执行任何操作即可达到此目的.但是,由于现在nginx在每个容器中分别运行,因此它们在端口公开时会发生冲突. 我也知道我可以使用到外部容器的外部链接,但我不想拆开docker-compose.yml文件,我只想将所有内容都打包在一起.
I don't have to do anything on native environment to achieve this. But since now nginx runs separately in each container they are conflicted on port exposing. I also know that I can use an external link to an external container but I don't want to tear apart my docker-compose.yml file, I just want everything in one piece.
version: '3'
services:
web:
image: nginx:alpine
ports:
- "80:80"
# ...
〜/demo2/
中的docker-compose.yml
docker-compose.yml in ~/demo2/
version: '3'
services:
web:
image: nginx:alpine
ports:
- "80:80"
# ...
当我在demo2中发出命令docker-compose up -d
时,我得到了:
When I issue command docker-compose up -d
in demo2 I got:
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文件中创建外部容器?
Is there any way to make them share them same port or maybe remap ports from host to container without using extra commands to create external containers? Or is there a way to create external containers within the docker-compose.yml file?
推荐答案
您不能将多个容器端口映射到同一主机端口.如果首先尝试绑定同一端口,则首先出现的任何容器都将绑定到端口80,第二个容器将抛出已经在使用中的端口.
You cannot map multiple container ports to the same host port. Whatever container that comes up first will get binded to port 80 and the second container will throw port already in use if you try binding the same port.
要解决此问题,您可以运行另一个虚拟 Nginx ,只需对 demo1 和 demo2 进行proxy_pass
即可.在这种情况下,http://app
将是父Nginx,/dev1
将是proxy_pass
到 demo1 ,而/dev2
将是proxy_pass
到 demo2 .
To Address this issue you can run another dummy Nginx which simply does proxy_pass
to demo1 and demo2. In this case, http://app
will be parent Nginx and /dev1
will proxy_pass
to demo1 and /dev2
will proxy_pass
to demo2.
在这里,您只需要将父Nginx的端口绑定到主机即可.如果您将所有子Nginx的端口连接到同一网络并使用另一个问题,即:Nginx将缓存使用服务发现解决的容器的IP,并将使用该IP IP总是会碰到容器.重新启动子容器后,子容器的IP地址可能会更改,因此父Nginx会抛出 502 .为了解决这个问题,您每次重新启动 demo1 或 demo2 时,都必须重新启动父Nginx.为了解决这个问题,您必须在父Nginx中使用resolver
作为127.0.0.11
并具有有效性.因此,每次Nginx尝试根据有效性尝试解析IP地址后解析.
Here, You just need to bind parent Nginx's port to host. You don't need to bind ports of child Nginx if you connect all these to the same network and use docker service discovery. If you follow these then you will hit another problem i.e: Nginx will cache IP of containers resolved using service discovery and will use that IP to hit the containers always. Once the child container is restarted there is a possibility that the child's IP address might get changed, So parent Nginx throws 502. To solve this you have to restart parent Nginx each time whenever you restart demo1 or demo2. To solve this you have to use resolver
as 127.0.0.11
with validity in parent Nginx. So each time Nginx will try resolving the IP address post last resolution according to validity.
我添加了虚拟配置文件,总结了以上所有要点.
I've added dummy config files summarising all the above points.
父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/
version: '3'
services:
web:
image: nginx:alpine
networks:
default:
aliases:
- dev1
networks:
default:
external:
name: dev
〜/demo2/
version: '3'
services:
web:
image: nginx:alpine
networks:
default:
aliases:
- dev2
networks:
default:
external:
name: dev
现在,您可以通过点击URL http://app/dev1 来使用demo1,并通过使用 http://app/dev2 .
Now you can use demo1 by hitting URL http://app/dev1 and demo2 by using http://app/dev2.
参考文献:
- NGINX Reverse Proxy
- NGINX proxy_pass
- NGINX resolver
- Necessity of docker DNS
- Docker container networking
这篇关于如何在使用Docker的同时为多个项目共享(暴露)端口80的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!