在Docker环境中,我们需要手动管理每个应用暴露的端口,特别是使用 Docker Swarm 集群时应用几十上百个,维护暴露端口变得十分困难,因此我们可以通过 Traefik 作为统一网关,自动服务发现和负载均衡,顺带解决 SSL申请问题
一、安装 Traefik
1. 创建专用网络
在单机 Docker 环境中
docker network create traefik
在 Docker Swarm 集群环境中
docker network create -d overlay traefik
2. 准备DNS服务商的KEY
先拥有一个域名,并配置 dns 例如 *.traefik.example.com 映射到你的服务器 IP。
同时准备服务商相关的 API KEY,其实使用tsl或http轮训也是可以,但稳定性不佳且容易触发免费证书商的频率限制,所以推荐直接配置 API KEY 更好。
本文以 Cloudflare 为例,其他服务商例如阿里云或 DNSPod,请自行查看文档 traefik/https/acme/#providers,找到对应的 Provider Code 和所需的环境变量
3. 启动 Traefik
- 创建证书缓存目录例如
/root/apps/traefik/cert,可自行更改任意位置,替换下方的yml即可 - 修改
version: '3.8'
services:
reverse-proxy:
image: traefik:v3.2
restart: always
environment:
# 自行替换为 Provider Code 所需的环境变量
- CF_API_EMAIL=seepine@example.com
- CF_DNS_API_TOKEN=yourDnsApiToken
command:
- --api.insecure=true
- --providers.docker
- --providers.docker.exposedByDefault=false
- --providers.docker.network=traefik
# 若非 docker swarm 这三行可去掉
- --providers.swarm.endpoint=unix:///var/run/docker.sock
- --providers.swarm.exposedByDefault=false
- --providers.swarm.network=traefik
# 暴露端口
- --entrypoints.web.address=:80 # 暴露http
- --entrypoints.websecure.address=:443 # 暴露https
- --entryPoints.tcp.address=:18080 # 暴露tcp
- --entryPoints.udp.address=:18080/udp # 暴露udp
# ssl 相关
- --certificatesresolvers.myresolver.acme.dnschallenge=true
- --certificatesresolvers.myresolver.acme.dnsChallenge.provider=cloudflare # 修改为自己的 Provider Code
- --certificatesresolvers.myresolver.acme.email=admin@example.com
- --certificatesresolvers.myresolver.acme.storage=/cert/acme.json
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /root/apps/traefik/cert:/cert
networks:
- traefik
networks:
traefik:
external: true
4. 访问面板
云服务器安全组放行 80/443/8080 端口,此时访问 http://你的公网ip:8080 进入 Traefik 面板说明启动成功。
此面板开放是不安全的,后续调试完记得修改 - --api.insecure=false 和去除所有 8080 端口暴露
二、部署应用
1. 部署客户端
此处以 Traefik 官方示例 whoami 来演示,实际生产中自行替换为自己的应用即可。
version: "3"
services:
whoami:
image: traefik/whoami
# docker_start - 若是单机 docker compose,使用此部分配置
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`) # 域名可自行修改为自己的
- traefik.http.services.whoami.loadbalancer.server.port=80 # 端口不配也会自动扫描,但建议自行配置为实际的,因此处镜像是whoami,默认端口为80端口
- traefik.http.routers.whoami.tls.certresolver=myresolver
# docker_end
# docker_swarm_start -- 若是 docker swarm 集群,使用此部分配置
deploy:
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`)
- traefik.http.services.whoami.loadbalancer.server.port=80
- traefik.http.routers.whoami.tls.certresolver=myresolver
mode: replicated
replicas: 3 # 此处部署3个实例测试负载均衡
# docker_swarm_end
networks:
- traefik
networks:
traefik:
external: true
2. 验证
查看 Traefik 面板可以看到应用
访问域名可以访问到信息
3. 注意A:每个应用的名称需要不同
即下方标签中的 <your_app_name> 需要全局唯一,实际中自行决断即可。
- traefik.http.routers.<your_app_name>.rule=Host(`whoami.traefik.example.com`) # 域名可自行修改为自己的
- traefik.http.services.<your_app_name>.loadbalancer.server.port=80 # 端口可自行修改为实际的,此处镜像是whoami,端口为80端口
- traefik.http.routers.<your_app_name>.tls.certresolver=myresolver
4. 注意B:多个端口暴露
version: "3"
services:
whoami:
image: traefik/whoami
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`)
- traefik.http.services.whoami.loadbalancer.server.port=8080
- traefik.http.routers.whoami.tls.certresolver=myresolver
# app_name 和域名端口改为不同即可
- traefik.http.routers.whoami_b.rule=Host(`whoami_b.traefik.example.com`)
- traefik.http.services.whoami_b.loadbalancer.server.port=8090
- traefik.http.routers.whoami_b.tls.certresolver=myresolver
三、进阶
1. 通配符
生产环境建议使用通配符证书解决 SSL 问题,可以有效避免域名过多 Let's Encrypt 证书申请速率被限制。
version: "3"
services:
whoami:
image: traefik/whoami
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=Host(`whoami.traefik.example.com`)
- traefik.http.services.whoami.loadbalancer.server.port=80
- traefik.http.routers.whoami.tls.certresolver=myresolver
- traefik.http.routers.whoami.tls.domains[0].main=*.traefik.example.com # 添加此行即可
2. 速率限制
可查看文档 traefik/middlewares/http/ratelimit
当超出限制会返回 429 Too Many Requests
version: "3"
services:
whoami:
image: traefik/whoami
# docker_start - 若是单机 docker compose,使用此部分配置
labels:
- traefik.enable=true
# 定义名为 whoami-route 的路由
- traefik.http.routers.whoami-route.rule=Host(`whoami.traefik.example.com`)
# ...
# step.1 定义名为 whoami-mw 的中间件
- traefik.http.middlewares.whoami-mw.ratelimit.average=100 # 表示每秒钟平均处理100个请求
- traefik.http.middlewares.whoami-mw.ratelimit.burst=150 # 表示每秒钟突发处理150个请求
- traefik.http.middlewares.whoami-mw.ratelimit.period=10s # 表示基准单位10秒,也可改为1m即一分钟等等,不填默认1秒
# step.2 将 whoami-mw 中间价应用到 whoami-route 路由上
- traefik.http.routers.whoami-route.middlewares=whoami-mw
3. 请求体限制
可查看文档 traefik/middlewares/http/buffering
version: "3"
services:
whoami:
image: traefik/whoami
# docker_start - 若是单机 docker compose,使用此部分配置
labels:
- traefik.enable=true
# 定义名为 whoami-route 的路由
- traefik.http.routers.whoami-route.rule=Host(`whoami.traefik.example.com`)
# ...
# step.1 定义名为 whoami-bf-mw 的中间件
- traefik.http.middlewares.whoami-bf-mw.buffering.maxRequestBodyBytes=2000000 # 设置最大请求体2MB 即 2*1024*1024
- traefik.http.middlewares.whoami-bf-mw.buffering.memRequestBodyBytes=1048576 # 设置内存中缓存的请求体1M,多余的请求体会使用磁盘缓存,避免traefik占据过多内存
# step.2 将 whoami-bf-mw 中间价应用到 whoami-route 路由上
- traefik.http.routers.whoami-route.middlewares=whoami-bf-mw # 若有多个插件可用逗号隔开,例如 =whoami-mw,whoami-bf-mw
4. 重定向https
可查看文档 traefik/middlewares/http/redirectscheme
version: "3"
services:
whoami:
image: traefik/whoami
# docker_start - 若是单机 docker compose,使用此部分配置
labels:
- traefik.enable=true
# 定义名为 whoami-route 的路由
- traefik.http.routers.whoami-route.rule=Host(`whoami.traefik.example.com`)
# ...
# step.1 定义名为 whoami-rd-mw 的中间件
- traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https
- traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true
- traefik.http.middlewares.test-redirectscheme.redirectscheme.port=443 # 默认443,若你的ssl非443端口,此配置很有用
# step.2 将 whoami-rd-mw 中间价应用到 whoami-route 路由上
- traefik.http.routers.whoami-route.middlewares=whoami-rd-mw
5. UDP路由
version: "3"
services:
whoami:
image: traefik/whoami
# docker_start - 若是单机 docker compose,使用此部分配置
labels:
- traefik.enable=true
- traefik.udp.routers.derper-udp.entrypoints=udp
- traefik.udp.routers.derper-udp.service=derper-udp
- traefik.udp.services.derper-udp.loadbalancer.server.port=3478 # 指向容器内udp端
博客内容遵循:署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 协议
本文永久链接是:seepine.com/docker/trae…