0%

Traefik-V2.x & Docker-Compose & Https 最佳实践

介绍说明

先记录,其他后面补!

具体部署文档

./traefik/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
version: '3.7'
services:
traefik:
image: traefik:v2.3.4
restart: always
environment:
# https://developer.aliyun.com/endpoints#service_alidns
# https://github.com/aliyun/alibaba-cloud-sdk-go/blob/master/README-CN.md
- ALICLOUD_REGION_ID=cn-hangzhou
- ALICLOUD_ACCESS_KEY=XXXXXXXX
- ALICLOUD_SECRET_KEY=XXXXXXXX
command:
- "--log.level=INFO"
- "--api.insecure=true"
- "--api.dashboard=true"
- "--providers.docker.swarmMode=false"
- "--providers.docker.useBindPortIP=true"
- "--providers.docker.network=net-traefik"
- "--providers.docker.exposedbydefault=false"
- "--providers.file.directory=/etc/traefik/"
- "--providers.file.watch=true"
- "--entrypoints.http.address=:80"
- "--entrypoints.https.address=:443"
# 配置 ACME 相关
# https://doc.traefik.io/traefik/https/acme/
- "--certificatesresolvers.acme-resolver.acme.email=username@domain.org"
- "--certificatesresolvers.acme-resolver.acme.storage=/etc/traefik/acme.json"
# - "--certificatesresolvers.acme-resolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.acme-resolver.acme.preferredchain=ISRG Root X1"
- "--certificatesresolvers.acme-resolver.acme.keytype=RSA4096"
- "--certificatesresolvers.acme-resolver.acme.dnschallenge.provider=alidns"
- "--certificatesresolvers.acme-resolver.acme.dnschallenge.delaybeforecheck=0"
- "--certificatesresolvers.acme-resolver.acme.dnschallenge.resolvers=223.5.5.5:53,114.114.114.114:53,8.8.8.8:53"
- "--certificatesresolvers.acme-resolver.acme.dnschallenge.disablepropagationcheck=true"
logging:
driver: json-file
options:
max-size: "200k"
max-file: "10"
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik_http.rule=Host(`traefik.domain.org`)"
- "traefik.http.routers.traefik_http.entrypoints=http"
- "traefik.http.routers.traefik_http.middlewares=gzip,auth"
- "traefik.http.routers.traefik_https.rule=Host(`traefik.domain.org`)"
- "traefik.http.routers.traefik_https.entrypoints=https"
- "traefik.http.routers.traefik_https.middlewares=gzip,auth"
- "traefik.http.routers.traefik_https.tls=true"
# 定义共享证书
- "traefik.http.routers.traefik_https.tls.certresolver=acme-resolver"
- "traefik.http.routers.traefik_https.tls.domains[0].main=domain.org"
- "traefik.http.routers.traefik_https.tls.domains[0].sans=domain.org,*.domain.org"
# 使用 Swarm 模式要显式定义 service 否则不会被路由
- "traefik.http.services.traefik.loadbalancer.server.port=8080"
# 定义共享中间件
- "traefik.http.middlewares.gzip.compress=true"
- "traefik.http.middlewares.ssl.headers.sslRedirect=true"
- "traefik.http.middlewares.auth.basicauth.users=XXXXXXXX"
networks:
- traefik
ports:
- '80:80'
- "443:443"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "/path/:/etc/traefik/:rw"
networks:
traefik:
name: net-traefik

./service/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
version: '3.7'
services:
service1:
image: 6xyun/whoami
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik_http.entrypoints=http"
- "traefik.http.routers.traefik_http.rule=Host(`service.domain.org`)"
- "traefik.http.routers.traefik_http.middlewares=gzip"
- "traefik.http.routers.traefik_https.entrypoints=https"
- "traefik.http.routers.traefik_https.rule=Host(`service.domain.org`)"
- "traefik.http.routers.traefik_https.middlewares=gzip"
# - "traefik.http.routers.cltfile_https.tls.certresolver=acme-resolver"
- "traefik.http.routers.traefik_https.tls=true"
- "traefik.http.services.service.loadbalancer.server.port=80"
- "traefik.http.services.service.loadbalancer.healthCheck.path=/"
- "traefik.http.services.service.loadbalancer.healthCheck.port=80"
- "traefik.http.services.service.loadbalancer.healthCheck.interval=10s"
- "traefik.http.services.service.loadbalancer.healthCheck.timeout=3s"
networks:
- traefik
service2:
image: 6xyun/whoami
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik_http.entrypoints=http"
- "traefik.http.routers.traefik_http.rule=Host(`service.domain.org`)"
- "traefik.http.routers.traefik_http.middlewares=gzip"
- "traefik.http.routers.traefik_https.entrypoints=https"
- "traefik.http.routers.traefik_https.rule=Host(`service.domain.org`)"
- "traefik.http.routers.traefik_https.middlewares=gzip"
# - "traefik.http.routers.cltfile_https.tls.certresolver=acme-resolver"
- "traefik.http.routers.traefik_https.tls=true"
- "traefik.http.services.service.loadbalancer.server.port=80"
- "traefik.http.services.service.loadbalancer.healthCheck.path=/"
- "traefik.http.services.service.loadbalancer.healthCheck.port=80"
- "traefik.http.services.service.loadbalancer.healthCheck.interval=10s"
- "traefik.http.services.service.loadbalancer.healthCheck.timeout=3s"
networks:
- traefik
networks:
traefik:
name: net-traefik
external: true

关于 HTTPS 配置

证书池

  • 先说一下 Traefik 证书大概的规则吧,Traefik 只有一个证书池。
  • 虽然每个服务都定义了 tls 配置, 但最终获得/生成的证书都被 Traefik 加载并全局使用,例如上面的例子,Traefik 的配置里面配置了 Let's Encrypt 的泛域名证书支持,其他的服务里面就不必在写 certresolver 属性, 只需要配置 tls=true 开启 TLS 就可以了,Traefik 检测到服务需要 TLS支持会在全局的证书池里面去寻找并匹配,匹配上了就能直接使用,没有匹配到就会使用默认证书(开启 Let's Encrypt 后如果没匹配上会自动进行签发)。

使用 Let's Encrypt 证书

  • 完全可以参照官方文档进行配置,但是有一点小细节还是需要记录一下。
  • Let's Encrypt 是免费的,并且理论上支持无限续期。
  • Let's Encrypt 只允许通过 dnschallenge 方式认证的域名申请泛域名证书。
  • 2021年10月 之后颁发的证书由于 Root CA 切换可能在一些低版本系统中不被信任(例如:Windows XP、Android 7以下)。

使用本地证书

  • 这个问题由于我没有仔细阅读文档导致我踩坑踩了两天。
  • 如同我上面贴出来的服务,注意里面的 providers.file.directory 属性,这就是关键了。
  • 原始文档里面说明了:除了 k8s 环境以外,其他环境使用本地证书只能通过 file provider 的方式加载。

https://doc.traefik.io/traefik/https/tls/#user-defined

  • 而在 Docker/Swarm 中开启 Traefikfile provider 就需要配置 providers.file.directory,让 Traefik 能够从这个配置对应的目录中去读取配置。

https://doc.traefik.io/traefik/providers/file/#provider-configuration

  • 完成上面的操作之后, 只需要在对应的目录中创建好配置文件,就能让 Traefik 加载上本地证书了。附一份配置示例:
1
2
3
4
5
6
7
# filename:cert.yaml
tls:
certificates:
- certFile: /path/to/domain.cert
keyFile: /path/to/domain.key
- certFile: /path/to/other-domain.cert
keyFile: /path/to/other-domain.key

本地证书链配置方式

  • 这个文档里面好像确实没有。本人也是依照别的组件配置试验出来的。
  • 用常用的 .pem 格式证书举例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(A:服务证书)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(B:签发A证书的CA证书)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(C:签发B证书的CA证书)
-----END CERTIFICATE-----
...
-----BEGIN CERTIFICATE-----
MIIXXXXXXXXXXXXXXX....(ROOT CA)
-----END CERTIFICATE-----

如上内容所示,这就是一个证书链格式了,其中需要注意的是证书顺序,按照级别从低到高的顺序进行排序(第一个是服务证书,最后一个一般是 ROOT CAROOT CA 的下一级证书)。

警告:证书文件当中不要包含私钥。

  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/85
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!