![Traefik 路由到一个 Docker 容器中的两个端口](https://linux22.com/image/791712/Traefik%20%E8%B7%AF%E7%94%B1%E5%88%B0%E4%B8%80%E4%B8%AA%20Docker%20%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%9A%84%E4%B8%A4%E4%B8%AA%E7%AB%AF%E5%8F%A3.png)
我想从单个 Docker 容器提供两个 Web 服务器,并使用 Traefik 代理服务器通过两个端口公开它们。
我发现一个例子docker compose 文件,为两个 web 服务器提供服务两个独立的Docker容器:
version: "3"
services:
# The `proxy` service set up two entrypoints (read that as
# "listeners") for traefik, one on port 80 and one on port 9090.
proxy:
image: traefik:latest
command:
- --api.insecure=true
- --providers.docker
- --entrypoints.ep1.address=:80
- --entrypoints.ep2.address=:9090
# We need to publish ports 80 and 9090. Here I'm also
# publishing port 8080, which is the Traefik dashboard, but
# that's not necessary.
ports:
- "80:80"
- "8080:8080"
- "9090:9090"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# We bind container `app1` to entrypoint `ep1`, with a `Host`
# rule matching `example.com`. I'm setting `...server.port` here
# because the `darkhttpd` container listens on port 8080.
app1:
image: docker.io/alpinelinux/darkhttpd:latest
volumes:
- type: bind
source: ./www80
target: /var/www/localhost/htdocs
labels:
- traefik.enable=true
- traefik.http.services.app1.loadbalancer.server.port=8080
- traefik.http.routers.app1.rule=Host(`example.com`)
- traefik.http.routers.app1.entrypoints=ep1
# We bind container `app2` to entrypoint `ep2`, with a `Host`
# rule matching `example.com`.
app2:
image: docker.io/alpinelinux/darkhttpd:latest
volumes:
- type: bind
source: /home/don/Documents/docker-test/www9090
target: /var/www/localhost/htdocs
labels:
- traefik.enable=true
- traefik.http.services.app2.loadbalancer.server.port=8080
- traefik.http.routers.app2.rule=Host(`example.com`)
- traefik.http.routers.app2.entrypoints=ep2
我补充example.com
说/etc/hosts
:
127.0.0.1 example.com
当我请求http://example.com
和时,这可以正常工作http://example.com:9090
,但是我如何才能从单身的容器?
我尝试使用脚本从同一个容器启动两个服务器:
#!/usr/bin/env sh
darkhttpd /var/www/localhost/htdocs9090 --port 9090 &
darkhttpd /var/www/localhost/htdocs --port 8080
然后我合并两个容器定义:
version: "3"
services:
# The `proxy` service set up two entrypoints (read that as
# "listeners") for traefik, one on port 80 and one on port 9090.
proxy:
image: traefik:latest
command:
- --api.insecure=true
- --providers.docker
- --entrypoints.ep1.address=:80
- --entrypoints.ep2.address=:9090
# We need to publish ports 80 and 9090. Here I'm also
# publishing port 8080, which is the Traefik dashboard, but
# that's not necessary.
ports:
- "80:80"
- "8080:8080"
- "9090:9090"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# We bind container `app1` to both entrypoints `ep1` and `ep2`, with a `Host`
# rule matching `example.com`. The launch script launches two darkhttpd
# processes that listen on ports 8080 and 9090.
app1:
image: docker.io/alpinelinux/darkhttpd:latest
volumes:
- type: bind
source: www80
target: /var/www/localhost/htdocs
- type: bind
source: www9090
target: /var/www/localhost/htdocs9090
- type: bind
source: launcher
target: /var/www/localhost/launcher
labels:
- traefik.enable=true
- traefik.http.services.app1.loadbalancer.server.port=8080
- traefik.http.routers.app1.rule=Host(`example.com`)
- traefik.http.routers.app1.entrypoints=ep1
- traefik.http.services.app2.loadbalancer.server.port=9090
- traefik.http.routers.app2.rule=Host(`example.com`)
- traefik.http.routers.app2.entrypoints=ep2
entrypoint: /var/www/localhost/launcher/launch.sh
当我运行时docker compose
,它抱怨服务太多:
traefik-two-ports-proxy-1 | time="2023-12-22T23:35:03Z" level=error msg="Could not define the service name for the router: too many services" routerName=app2 providerName=docker
如何在不扰乱docker的情况下将服务合并到一个容器中?
答案1
经过一番搜索,我发现你需要明确名称当容器中有多个服务时。
version: "3"
services:
# The `proxy` service set up two entrypoints (read that as
# "listeners") for traefik, one on port 80 and one on port 9090.
proxy:
image: traefik:latest
command:
- --api.insecure=true
- --providers.docker
- --entrypoints.ep1.address=:80
- --entrypoints.ep2.address=:9090
# We need to publish ports 80 and 9090. Here I'm also
# publishing port 8080, which is the Traefik dashboard, but
# that's not necessary.
ports:
- "80:80"
- "8080:8080"
- "9090:9090"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# We bind container `app1` to both entrypoints `ep1` and `ep2`, with a `Host`
# rule matching `example.com`. The launch script launches two darkhttpd
# processes that listen on ports 8080 and 9090.
# When a service container holds more than one service, you have to explicitly
# name the service for each router.
app1:
image: docker.io/alpinelinux/darkhttpd:latest
volumes:
- type: bind
source: www80
target: /var/www/localhost/htdocs
- type: bind
source: www9090
target: /var/www/localhost/htdocs9090
- type: bind
source: launcher
target: /var/www/localhost/launcher
labels:
- traefik.enable=true
- traefik.http.services.app1.loadbalancer.server.port=8080
- traefik.http.routers.app1.service=app1
- traefik.http.routers.app1.rule=Host(`example.com`)
- traefik.http.routers.app1.entrypoints=ep1
- traefik.http.services.app2.loadbalancer.server.port=9090
- traefik.http.routers.app2.service=app2
- traefik.http.routers.app2.rule=Host(`example.com`)
- traefik.http.routers.app2.entrypoints=ep2
entrypoint: /var/www/localhost/launcher/launch.sh
现在,我可以再次点击这两个按钮http://example.com
,http://example.com:9090
同时只运行一个 Web 服务器容器。