背景

我的Deployment绑定了很多子域名,但每次在腾讯云中申请证书只有90天,还需要手动更换大量证书,所以我想使用Traefik自动续签证书,而且使用腾讯云的DNS验证方式,这样就不用每次都手动更换证书了。

环境

traefik: v2.9.10
kubernetes: v1.24.6+k3s1

准备工作

域名绑定

在腾讯云中,我们需要将泛域名(*.yourdomain.com)解析到我们的服务器IP上,这样Traefik才能通过DNS验证方式自动续签证书,其中:

  • 主机记录:*
  • 记录类型:A
  • 记录值:你的服务器IP

泛域名绑定成功后,后面我们任何子域名都可以通过这个泛域名来验证并访问,例如:(test1.yourdomain.com、test2.yourdomain.com)。

申请DNSPOD API密钥

因为我的域名在腾讯的DNSPOD中,因此我们需要申请API密钥,用于Traefik自动续签证书,申请地址如下:

1
https://console.dnspod.cn/account/token/token

Traefik配置

创建pv

接下来我们需要将/data/acme.json持久化,如果不持久化,重启后,acme.json会被删除,导致每次重启都需要申请一个新的证书,168小时内申请证书过多,会导致1天的封禁,因此我们需要持久化 acme.json 文件。

新建目录 /home/k3s/data/traefik,并授予读写权限:

1
2
mkdir -p /home/k3s/data/traefik
chmod a+w+r /home/k3s/data/traefik

创建pv文件 /var/lib/rancher/k3s/server/manifests/traefik-pv.yaml

1
touch /var/lib/rancher/k3s/server/manifests/traefik-pv.yaml

内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: PersistentVolume
metadata:
name: traefik-pv
labels:
type: local
spec:
storageClassName: traefik-config
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/home/k3s/data/traefik"

创建pv持久化卷:

1
kubectl apply -f /var/lib/rancher/k3s/server/manifests/traefik-pv.yaml

配置自动证书

接下来我们需要修改K3s中,Traefik的配置文件,添加证书自动续签的配置,这里我们使用HelmChartConfig的方式修改Traefik的配置。

在路径/var/lib/rancher/k3s/server/manifests/traefik-config.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
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
websecure:
tls:
enabled: true
certResolver: "le"
additionalArguments:
- "--entrypoints.websecure.http.tls.domains[0].main=yourdomain.com"
- "--entrypoints.websecure.http.tls.domains[0].sans=*.yourdomain.com"
- "--certificatesresolvers.le.acme.email=youremail@example.com"
- "--certificatesresolvers.le.acme.storage=/data/acme.json"
- "--certificatesresolvers.le.acme.dnschallenge=true"
- "--certificatesresolvers.le.acme.dnschallenge.provider=dnspod"
env:
- name: "DNSPOD_API_KEY"
value: "<YOUR DNSPOD ID>,<YOUR DNSPOD TOKEN>"
- name: "DNSPOD_HTTP_TIMEOUT"
value: "150"
- name: "DNSPOD_POLLING_INTERVAL"
value: "5"
- name: "DNSPOD_PROPAGATION_TIMEOUT"
value: "300"
persistence:
enabled: true #开启数据持久化
name: data
accessMode: ReadWriteOnce
storageClass: "traefik-config"
path: /data

首先,我们更改 traefik-config.yaml 而不是更改 traefik.yaml 的原因是,K3S会周期性的执行 /var/lib/rancher/k3s/server/manifests 目录下的所有yaml,而如果我们修改了默认的traefik.yaml,K3S会自动恢复默认文件,所以我们这里需要新建一个yaml文件,用HelmChartConfig的方式修改traefik安装的配置即可。

yourdomain.com 更改为你的域名,<YOUR DNSPOD ID> 为刚刚创建的API ID,<YOUR DNSPOD TOKEN> 为刚刚创建的API TOKEN,youremail@example.com 为你的邮箱地址。

DNSPod 有以下两个问题:

  • 我们从管理界面生成的 ID 和 TOKEN 需要以 DNSPOD_API_KEY=, 的格式使用。
  • 由于解析生效时间比较慢,因此建议延长 Timeout 时间。

上述内容都配置完毕后,会自动执行一个helm job,用于安装traefik,安装完成后,我们通过kubectl get pods -n kube-system命令查看是否安装成功。

P.S. 请注意,由于acme的缘故,replicas似乎不支持修改,关于更多helm chart配置,可以参考官方文档:https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.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
cat << EOF > whoami.yml
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
ports:
- protocol: TCP
name: web
port: 80
selector:
app: whoami
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami
labels:
app: whoami
spec:
replicas: 1
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
ports:
- name: web
containerPort: 80
EOF

创建应用:

1
kubectl apply -f whoami.yml

接下来我们创建一个ingress,用于访问这个Deployment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat << EOF > ingress-whoami.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test.yourdomain.com
namespace: default
spec:
rules:
- host: test.yourdomain.com
http:
paths:
- backend:
service:
name: whoami
port:
number: 80
path: /
pathType: Prefix
EOF
1
kubectl apply -f ingress-whoami.yml

访问通过https访问这个域名:https://test.yourdomain.com,如果你看到了默认页面,证明证书已经生效,此时你可以点击浏览器的锁图标查看证书信息,你会看到证书的有效期是90天,服务商为Let's Encrypt,证明证书已经创建成功。

强制HTTPS

如果你想强制所有的请求都使用HTTPS,可以在Traefik的配置文件中添加如下配置:

1
2
3
4
5
6
7
8
9
10
cat << EOF > redirect.yml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: redirect-https
namespace: default
spec:
redirectScheme:
scheme: https
EOF
1
kubectl apply -f redirect.yml

然后在 ingress-whoami.yml 中,添加Middle Ware即可:

1
2
3
4
5
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
...

此时流量会先经过defalut命名空间下的redirect-https中间件,将所有的请求重定向到https

结语

很早就知道Traefik支持自动证书的申请,奈何初学时先自己配置的证书,现在证书由一年改为了90天,更改的成本就增加了,今天抽空学习了一下,网上资料比较少,所以写了这篇文章,希朝对大家有所帮助。

参考资料: