问题
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.
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.
docker-compose.yml in ~/demo1/
version: '3'
services:
web:
image: nginx:alpine
ports:
- "80:80"
# ...
docker-compose.yml in ~/demo2/
version: '3'
services:
web:
image: nginx:alpine
ports:
- "80:80"
# ...
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.
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?
回答1:
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.
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.
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.
Parent Nginx compose:
version: '3'
services:
parent:
image: nginx:alpine
volume:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- 80:80
networks:
default:
external:
name: dev
Parent Nginx config (./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 in ~/demo1/
version: '3'
services:
web:
image: nginx:alpine
networks:
default:
aliases:
- dev1
networks:
default:
external:
name: dev
docker-compose.yml in ~/demo2/
version: '3'
services:
web:
image: nginx:alpine
networks:
default:
aliases:
- dev2
networks:
default:
external:
name: dev
Now you can use demo1 by hitting URL http://app/dev1 and demo2 by using http://app/dev2.
References:
- NGINX Reverse Proxy
- NGINX proxy_pass
- NGINX resolver
- Necessity of docker DNS
- Docker container networking
来源:https://stackoverflow.com/questions/53882200/how-to-shareexpose-port-80-for-multiple-projects-while-using-docker