介绍
提供一个在 Kubernetes 中使用 cert-manager + Cloudflare 自动签发并自动更新 Let’s Encrypt 证书的完整思路与示例(DNS-01 验证),方便你在集群内自动化 TLS 证书更新。
前置条件
- Kubernetes 集群:可正常访问外网。不做网络环境配置的教程,具体可以去看其他文章
- Cloudflare 账号:已将你的域名托管到 Cloudflare。使用 Cloudflare 做
dns-01 挑战
- kubectl:已连接到集群。最基本的条件,保证k8s能正常访问
- helm:推荐用 Helm 安装 cert-manager。使用helm安装,方便干净
安装
官方推荐用 Helm,这里我使用 1.18.2 的版本,在我这个时间点这个版本还是比较新的
安装 cert-manager
1# 安装 cert-manager CRDs
2kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.crds.yaml
1## Add the Jetstack Helm repository
2helm repo add jetstack https://charts.jetstack.io --force-update
1## Install the cert-manager helm chart
2helm install cert-manager --namespace cert-manager --version v1.18.2 jetstack/cert-manager
验证:
1kubectl get pods -n cert-manager
准备 Cloudflare API Token
- My Profile → API Tokens → Create Token。
模板选:
Edit zone DNS
权限:
- Zone → DNS → Edit
- Zone → Zone → Read
Zone Resources: 选择需要签发证书的域名。
保存 token,例如:
CF_API_TOKEN=xxxxxxxxxx
创建 Secret 存放 Token
1kubectl create secret generic cloudflare-api-token-secret \
2 --from-literal=api-token=CF_API_TOKEN \
3 -n cert-manager
配置 ClusterIssuer
cluster-issuer.yaml
1apiVersion: cert-manager.io/v1
2kind: ClusterIssuer
3metadata:
4 name: letsencrypt-dns
5spec:
6 acme:
7 # 生产环境地址
8 server: https://acme-v02.api.letsencrypt.org/directory
9 email: your-email@example.com # 接收过期提醒
10 privateKeySecretRef:
11 name: letsencrypt-dns-key
12 solvers:
13 - dns01:
14 cloudflare:
15 email: your-email@example.com # 或留空(若使用 API token 可不填 email)
16 apiTokenSecretRef:
17 name: cloudflare-api-token-secret
18 key: api-token
部署yaml
1kubectl apply -f cluster-issuer.yaml
申请证书
在需要证书的命名空间下创建 Certificate 对象,例如 Nginx Ingress 的域名 example.com
:certificate.yaml
1apiVersion: cert-manager.io/v1
2kind: Certificate
3metadata:
4 name: example-com
5 namespace: default
6spec:
7 secretName: example-com-tls # 生成的 secret 名称
8 issuerRef:
9 name: letsencrypt-dns
10 kind: ClusterIssuer
11 commonName: example.com
12 dnsNames:
13 - example.com
14 - "*.example.com" # 可选:通配符
部署yaml
1kubectl apply -f certificate.yaml
在 Ingress 中引用
1apiVersion: networking.k8s.io/v1
2kind: Ingress
3metadata:
4 name: example-ingress
5 annotations:
6 kubernetes.io/ingress.class: nginx
7 cert-manager.io/cluster-issuer: letsencrypt-dns # 配置证书自动生成
8spec:
9 tls:
10 - hosts:
11 - example.com
12 secretName: example-com-tls #修改成自己要使用的tls名称会自动生成
13 rules:
14 - host: example.com
15 http:
16 paths:
17 - path: /
18 pathType: Prefix
19 backend:
20 service:
21 name: web
22 port:
23 number: 80
cert-manager 会在证书到期前约 30 天 自动续期。
查看状态
1kubectl describe certificate example-com -n default
复用证书
因为证书只能部署在制定的 namespace下,因此我写了一个脚本,把default
命名空间下的 example-com-tls
Secret复制到 argocd
、longhorn-system
、cattle-system
等多个命名空间。
1#!/bin/bash
2# 文件名:copy-example-cert.sh
3# 作用:将 default 命名空间下的 example-com-tls Secret
4# 复制到 argocd、longhorn-system、cattle-system
5
6SRC_NS="default"
7SECRET_NAME="example-com-tls"
8TARGET_NAMESPACES=("argocd" "longhorn-system" "cattle-system")
9
10for ns in "${TARGET_NAMESPACES[@]}"; do
11 echo ">>> 正在复制到命名空间: $ns"
12 kubectl get secret "$SECRET_NAME" -n "$SRC_NS" -o yaml \
13 | sed "s/namespace: $SRC_NS/namespace: $ns/" \
14 | kubectl apply -f -
15done
16
17echo "✅ 复制完成"
执行
1./copy-example-cert.sh
脚本会依次输出
1>>> 正在复制到命名空间: argocd
2secret/example-com-tls created
3>>> 正在复制到命名空间: longhorn-system
4secret/example-com-tls created
5>>> 正在复制到命名空间: cattle-system
6secret/example-com-tls created
7✅ 复制完成