简单配置
最简单的docker-compose
配置 文件名为 docker-compose.base.yaml
1 2 3 4 5 6 7 8 9
| services: traefik: image: traefik:v3.5 ports: - "8080:8080" command: - "--api=true" - "--api.dashboard=true" - "--api.insecure=true"
|
访问 http://localhost:8080/dashboard
就能看到后台管理界面,以及能够访问到api
路由,具体文档见官网](https://doc.traefik.io/traefik/reference/install-configuration/api-dashboard/#endpoints)
重定向Dashboard到localhost
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| services: traefik: image: traefik:v3.5 ports: - "80:81" - "8080:8080" command: - "--api.dashboard=true" - "--api.insecure=true" - "--entrypoints.web.address=:81" - "--providers.docker=true" labels: - "traefik.http.routers.traefik.rule=Host(`localhost`)" - "traefik.http.routers.traefik.entrypoints=web" - "traefik.http.routers.traefik.service=api@internal" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro
|
静态配置(command)
--entrypoints.web.address=:81
→ 定义一个名为 web
的入口,监听容器内部的 81
端口。
ports: "80:81"
→ 把宿主机的 80
映射到容器的 81
,所以外部访问 http://localhost:80
实际进入 Traefik 的 web
entrypoint。
--providers.docker=true
→ 让 Traefik 从 Docker labels 里动态加载路由规则。
动态配置(labels)
traefik.http.routers.traefik.rule=Host(
localhost)
→ 匹配请求的 Host
头是 localhost
的流量。
traefik.http.routers.traefik.entrypoints=web
→ 绑定到 web
入口(即 :81
端口)。
traefik.http.routers.traefik.service=api@internal
→ 把流量转发到 Traefik 内置的 Dashboard API 服务。
flowchart LR
A["外部请 localhost:80"] --> B["Traefik 81端口 (entrypoint:web)"]
B --> C{"Router"}
C -->|"Host = localhost"| D["Router: traefik"]
D -->|"service = api@internal"| E["Dashboard 服务"]
Note: 范围的时候必须使用localhost访问,使用127.0.0.1 路由规则会匹配失效.
Traefix 使用自定义域名
wsl 配置
笔者使用的环境是wsl,所以有些操作和可能会和macos/linux
上的配置有写不同. 如果运行出现失败请自己动手解决.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| services: traefik: image: traefik:v3.5 ports: - "80:81" - "8080:8080" command: - "--api.dashboard=true" - "--api.insecure=true" - "--entrypoints.web.address=:81" - "--providers.docker=true" labels: - "traefik.http.routers.traefik.rule=Host(`docker.local`)" - "traefik.http.routers.traefik.entrypoints=web" - "traefik.http.routers.traefik.service=api@internal" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro
|
- 和上使用
localhost
域名相比,只改动了一个docker.local
的域名
- 由于
docker.local
在公共DNS 中查询不到,需要手动配置
如果没有特殊指定,docker-compose 中拆创建的网络格式为{project_name}_default
1 2 3
| ❯ docker network ls NETWORK ID NAME DRIVER SCOPE 26659d36dd60 traefik-demo_default bridge local
|
使用命令查看网关
1 2
| docker network inspect 26659d36dd60 | jq -r '.[0].IPAM.Config[0].Gateway' 172.19.0.1
|
将这个地址写入/etc/hosts
并手动检查联通性
1 2
| echo "$(docker network inspect traefil | jq -r '.[0].IPAM.Config[0].Gateway') docker.local" >> /etc/hosts ping docker.local -c 5
|
没有问题之后手动访问docker.local
就可以跳转到dashboard
页面
这种配置有一个问题,就是docker 分配网络是随机分配未占用的网络给容器使用,一旦wsl 重启,或者执行docker compose down
之后,再运行这个compose,docker 分配的ip 地址就可能会改变,相对应的/etc/host
中的自定义地址需要相对应地做出修改.
docker-compose IP改变的对应之策
为了解决容器IP变更问题,我有以下思路.
在docker compose 之外创建网络
1
| docker network create traefik
|
网络不使用docker-compose 自动创建得,而是自行维护,docker-compose 在执行down 子命令得时候,不会删除该网络.
同时在对应的yaml 中配置network要使用external
关键字. 在 Docker Compose 的网络配置中,external
用于指定该网络是在 Compose 之外手动创建和管理的。设置 external: true
后,Compose 不会尝试创建这个网络,而是会查找并连接到已经存在的同名网络。如果该网络不存在,则会报错.
1 2 3 4
| networks: traefik: name: traefik external: true
|
创建网络的时候指定IP和网关
1 2 3 4 5 6 7 8
| networks: traefik: driver: bridge ipam: driver: default config: - subnet: 172.19.0.0/24 gateway: 172.19.0.1
|
这种方式创建的网络在重启之后,还会是指定的IP和网关地址.
Traefix 自签名证书
配置参考官方文档
首先生成docker.local
泛域名证书.
1 2 3 4
| openssl req -x509 -nodes -newkey rsa:2048 -days 3650 \ -keyout key.pem -out cert.pem \ -subj "/C=CN/ST=Shanghai/L=Shanghai/O=Dev/OU=Dev/CN=docker.local" \ -addext "subjectAltName=DNS:docker.local,DNS:*.docker.local"
|
创建证书tls.yaml文件内容如下
1 2 3 4
| tls: certificates: - certFile: /ca/cert.pem keyFile: /ca/key.pem
|
创建docker-compose.yaml 文件,内容如下.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| services: traefik: image: traefik:v3.5 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true
networks: - traefik
ports: - "80:80" - "443:443" - "8080:8080"
volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./ca:/ca:ro
command: - "--entrypoints.http.address=:80" - "--entrypoints.http.http.redirections.entrypoint.to=https" - "--entrypoints.http.http.redirections.entrypoint.scheme=https" - "--entrypoints.http.http.redirections.entrypoint.permanent=true" - "--entrypoints.https.address=:443" - "--entrypoints.https.http.tls=true"
- "--providers.file.filename=/ca/tls.yaml" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=traefik"
- "--api.dashboard=true" - "--api.insecure=false"
labels: - "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`dashboard.docker.local`)" - "traefik.http.routers.dashboard.entrypoints=https" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.tls=true"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$JTAIcybX$$SftqEr2Mq301.opQyUoHo." - "traefik.http.routers.dashboard.middlewares=dashboard-auth@docker"
whoami: image: traefik/whoami container_name: whoami restart: unless-stopped networks: - traefik labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.docker.local`)" - "traefik.http.routers.whoami.entrypoints=https" - "traefik.http.routers.whoami.tls=true"
networks: traefik: name: traefik external: true
|
1 2 3 4 5 6
| ├── ca │ ├── cert.pem │ ├── key.pem │ └── tls.yaml ├── docker-compose.self-signed.yaml └── sign-ca.sh
|
添加whoami
到hosts 文件
1
| echo "$(docker network inspect traefik | jq -r '.[0].IPAM.Config[0].Gateway') whoami.docker.local" >> /etc/hosts
|
信任证书
1 2
| cp ./ca/cert.pem /usr/local/share/ca-certificates/docker.local.crt update-ca-certificates
|
使用 curl 查看接口使用正常工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ❯ curl whoami.docker.local -L Hostname: c2eb174645c1 IP: 127.0.0.1 IP: ::1 IP: 172.17.0.3 RemoteAddr: 172.17.0.2:56402 GET / HTTP/1.1 Host: whoami.docker.local User-Agent: curl/7.81.0 Accept: */* Accept-Encoding: gzip X-Forwarded-For: 172.17.0.1 X-Forwarded-Host: whoami.docker.local X-Forwarded-Port: 443 X-Forwarded-Proto: https X-Forwarded-Server: 183b22a98bed X-Real-Ip: 172.17.0.1
|
使用插件和动态配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| services: traefik: image: traefik:v3.5 container_name: traefik command: - --api.insecure=true - --providers.docker=true - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --experimental.plugins.real-ip.modulename=github.com/Paxxs/traefik-get-real-ip - --experimental.plugins.real-ip.version=v1.0.3 ports: - "80:80" - "8080:8080" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro labels: - "traefik.enable=true"
whoami1: image: traefik/whoami:v1.10 labels: - "traefik.enable=true" - "traefik.http.routers.who.rule=Host(`who.localhost`)" - "traefik.http.routers.who.entrypoints=web" - "traefik.http.routers.who.service=who-svc" - "traefik.http.services.who-svc.loadbalancer.server.port=80" - "traefik.http.routers.who.middlewares=realip@docker" - "traefik.http.middlewares.realip.plugin.real-ip.Proxy.0.proxyHeadername=X-From-Cdn" - "traefik.http.middlewares.realip.plugin.real-ip.Proxy.0.proxyHeadervalue=cf-foo" - "traefik.http.middlewares.realip.plugin.real-ip.Proxy.0.realIP=Cf-Connecting-Ip" - "traefik.http.middlewares.realip.plugin.real-ip.Proxy.1.proxyHeadername=*" - "traefik.http.middlewares.realip.plugin.real-ip.Proxy.1.realIP=RemoteAddr"
whoami2: image: traefik/whoami:v1.10 labels: - "traefik.enable=true" - "traefik.http.routers.who.rule=Host(`who.localhost`)" - "traefik.http.routers.who.entrypoints=web" - "traefik.http.routers.who.service=who-svc" - "traefik.http.services.who-svc.loadbalancer.server.port=80" - "traefik.http.routers.who.middlewares=realip@docker"
|
查看容器日志
1 2
| docker logs 9f8b38cda238 # [get-realip] ☃️ Config loaded.(1) &{[{ false}]}
|
请求负载均衡地址
1
| curl -H "Host: who.localhost" http://localhost/
|
模拟携带请求头
1 2 3 4 5
| curl -i \ -H "Host: who.localhost" \ -H "X-From-Cdn: cf-foo" \ -H "Cf-Connecting-Ip: 203.0.113.9" \ http://localhost/
|