060.Kubernetes cert-manager ACME DNS01实战
文章目录
项目设计
项目规划
当前结合ACME实现证书自动化管理,使用 DNS01 验证方案,总体规划如下:
| 证书类型 | 业务域名 | 命名空间 | Issuer类型 | 申请邮箱 | secret名称 | 有效期 | 前置续期 |
|---|---|---|---|---|---|---|---|
| Let’s Encrypt免费证书 | flask.linuxsb.com | test | ClusterIssuer | x120952576@126.com | flask-linuxsb-com-tls | 90天 | 10天 |
项目实施
前置准备
正式项目实施前,建议检查相关环境情况。
- cert-manager 安装情况
[root@master01 ~]# kubectl -n cert-manager get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cert-manager-746886b79c-l2ldj 1/1 Running 3 (2d14h ago) 6d8h 10.10.5.19 worker01 <none> <none>
cert-manager-cainjector-5664b56fc6-7w59h 1/1 Running 3 (2d14h ago) 6d8h 10.10.30.123 worker02 <none> <none>
cert-manager-webhook-7f644f6b8f-w9bnt 1/1 Running 3 (2d14h ago) 6d8h 10.10.30.91 worker02 <none> <none>
[root@master01 ~]# kubectl get crd | grep cert-manager.io
certificaterequests.cert-manager.io 2026-03-05T07:28:38Z
certificates.cert-manager.io 2026-03-05T07:28:38Z
challenges.acme.cert-manager.io 2026-03-05T07:28:38Z
clusterissuers.cert-manager.io 2026-03-05T07:28:38Z
issuers.cert-manager.io 2026-03-05T07:28:38Z
orders.acme.cert-manager.io 2026-03-05T07:28:38Z
- Nginx ingress 安装情况
[root@master01 ~]# kubectl -n ingress-nginx get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-controller-cqktt 1/1 Running 9 (2d14h ago) 84d 10.10.241.112 master01 <none> <none>
ingress-nginx-controller-s92m7 1/1 Running 9 (2d14h ago) 84d 10.10.235.50 master03 <none> <none>
ingress-nginx-controller-wxqcs 1/1 Running 9 (2d14h ago) 84d 10.10.59.227 master02 <none> <none>
[root@master01 ~]# kubectl -n ingress-nginx get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ingress-nginx-controller NodePort 10.20.60.120 <none> 80:80/TCP,443:443/TCP 89d app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
ingress-nginx-controller-admission ClusterIP 10.20.191.221 <none> 443/TCP 89d app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
[root@master01 ~]# kubectl get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 89d
webhook安装
DNS01验证部分域名托管商已经内置在cert-manager中,但国内的需要额外安装webhook。国内主要是基于阿里云和腾讯云为主,如下为两个托管商的不同webhook安装。
alidns
- 解析说明
假设域名托管在阿里云上,DNS01 验证需要 cert-manager 调用阿里云 DNS API,自动创建 TXT 记录给 Let’s Encrypt 验证。
因此需要 aliyun的 AccessKey ID 和 AccessKey Secret,建议配置子RAM账号。
子RAM账号信息:
AccessKey ID:LTAI5t8t3SHMfXJXXXXXX
AccessKey Secret:W4D33tVCFMK6SZrrMMtXXXXXXX
同时对于业务域名 flask.linuxsb.com ,需要保证解析已正确。
[root@master01 ~]# dig +short flask.linuxsb.com
106.75.222.82
- 安装webhook
需要参考 alidns github 安装alidns-webhook。
[root@master01 ~]# kubectl apply -f https://raw.githubusercontent.com/pragkent/alidns-webhook/master/deploy/bundle.yaml
[root@master01 ~]# kubectl get apiservice | grep -i alidns
v1alpha1.acme.yourcompany.com cert-manager/alidns-webhook True 10m
[root@master01 ~]# kubectl -n cert-manager get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
alidns-webhook-844d4fccf7-8sx8g 1/1 Running 0 10m 10.10.19.82 worker03 <none> <none>
cert-manager-746886b79c-zrf8v 1/1 Running 0 68m 10.10.30.76 worker02 <none> <none>
cert-manager-cainjector-5664b56fc6-7kgpd 1/1 Running 0 68m 10.10.5.11 worker01 <none> <none>
cert-manager-webhook-7f644f6b8f-xzdgl 1/1 Running 0 68m 10.10.19.78 worker03 <none> <none>
- 创建阿里云凭据
Secret 放在 cert-manager 命名空间。
方式一:直接命令行创建
[root@master01 test]# kubectl create secret generic alidns-secret \
-n cert-manager \
--from-literal=access-key='LTAI5t8t3SHMfXxxxxxxxxx' \
--from-literal=secret-key='W4D33tVCFMK6xxxxxxxxxxxxxx'
方式二:yaml文件创建
对于yaml文件创建,需要做base64转换。
[root@master01 test]# echo -n 'LTAI5t8t3SHMfXxxxxxxxxx' | base64
[root@master01 test]# echo -n 'W4D33tVCFMK6SZrrxxxxxxxxxxxxxx' | base64
[root@master01 test]# vim alidns-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
name: alidns-secret
namespace: cert-manager
data:
access-key: TFRBSTV0OHQzU0hNZlhKWVFxxxxxxxxxx
secret-key: VzREMzN0VkNGTUs2U1pyck1NdHpxxxxxxxxx
[root@master01 test]# kubectl apply -f alidns-secret.yaml
dnspod
- 解析说明
假设域名托管在腾讯云上,DNS01 验证需要 cert-manager 调用阿里云 DNSPod API,自动创建 TXT 记录给 Let’s Encrypt 验证。
因此需要 腾讯云 的 DNSPod Token ,建议配置子RAM账号。
腾讯云密钥创建可参考:密钥管理
Token信息:
名称 :cert证书申请
ID:619xxx
Token:ef7a62ec99bea531d03047xxxxxxxx
同时对于业务域名 flask.linuxsb.com ,需要保证解析已正确。
[root@master01 ~]# dig +short flask.linuxsb.com
106.75.222.82
- 安装webhook
参考一:使用 cert-manager 为 DNSPod 的域名签发免费证书 。
参考二:cert-manager-webhook-dnspod
。
[root@master01 ~]# git clone --depth 1 https://github.com/qqshfox/cert-manager-webhook-dnspod.git
[root@master01 ~]# cd cert-manager-webhook-dnspod/
[root@master01 cert-manager-webhook-dnspod]# ll
total 124K
drwxr-xr-x 3 root root 4.0K Mar 17 16:36 deploy
-rw-r--r-- 1 root root 413 Mar 17 16:36 Dockerfile
-rw-r--r-- 1 root root 271 Mar 17 16:36 go.mod
-rw-r--r-- 1 root root 67K Mar 17 16:36 go.sum
-rw-r--r-- 1 root root 12K Mar 17 16:36 LICENSE
-rw-r--r-- 1 root root 8.9K Mar 17 16:36 main.go
-rw-r--r-- 1 root root 578 Mar 17 16:36 main_test.go
-rw-r--r-- 1 root root 534 Mar 17 16:36 Makefile
-rw-r--r-- 1 root root 1.7K Mar 17 16:36 README.md
drwxr-xr-x 2 root root 4.0K Mar 17 16:36 scripts
drwxr-xr-x 3 root root 4.0K Mar 17 16:36 testdata
[root@master01 cert-manager-webhook-dnspod]# vim myvalues.yaml
secrets:
apiID: 610000
apiToken: ef7a62ec99bea531d03040000000000000
clusterIssuer: # 同步创建clusterIssuer
enabled: true
email: x120952576@126.com
image:
repository: registry.cn-hangzhou.aliyuncs.com/xhyimages/cert-manager-webhook-dnspod # 镜像改为国内
tag: v1.0.1
[root@master01 cert-manager-webhook-dnspod]# helm upgrade --install cert-manager-webhook-dnspod ./deploy/cert-manager-webhook-dnspod --namespace cert-manager --create-namespace -f myvalues.yaml
[root@master01 cert-manager-webhook-dnspod]# helm -n cert-manager list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
cert-manager cert-manager 1 2026-03-17 15:54:02.1586179 +0800 CST deployed cert-manager-v1.20.0 v1.20.0
cert-manager-webhook-dnspod cert-manager 1 2026-03-17 17:53:26.301553551 +0800 CST deployed cert-manager-webhook-dnspod-0.3.3 0.2.0
[root@master01 cert-manager-webhook-dnspod]# kubectl get apiservice | grep -i dnspod
v1alpha1.acme.mycompany.com cert-manager/cert-manager-webhook-dnspod True 25s
[root@master01 cert-manager-webhook-dnspod]# kubectl -n cert-manager get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
cert-manager-cainjector-d8fc7bd86-252jd 1/1 Running 0 120m 10.62.5.230 phy-d2000-01 <none> <none>
cert-manager-f988bfb47-9r8qs 1/1 Running 0 120m 10.62.5.231 phy-d2000-01 <none> <none>
cert-manager-webhook-6dfffb76df-m6ptm 1/1 Running 0 120m 10.62.5.232 phy-d2000-01 <none> <none>
cert-manager-webhook-dnspod-8544fd487b-hmxz7 1/1 Running 0 48s 10.62.1.192 phy-d2000-04 <none> <none>
正式申请
创建命名空间
[root@master01 ~]# mkdir test
[root@master01 ~]# cd test/
[root@master01 test]# kubectl create namespace test
创建ClusterIssuer
提示:若使用 dnspods ,则在安装webhook的时候已经创建了clusterIssuer,可跳过此步骤。
- 创建请求
[root@master01 test]# vim clusterissuer-letsencrypt-prod-ali.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-issuer-prod-ali
spec:
acme:
email: x120952576@126.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-accountkey-prod-ali
solvers:
- dns01:
webhook:
groupName: acme.yourcompany.com
solverName: alidns
config:
region: ""
accessKeySecretRef:
name: alidns-secret
key: access-key
secretKeySecretRef:
name: alidns-secret
key: secret-key
[root@master01 test]# kubectl apply -f clusterissuer-letsencrypt-prod-ali.yaml
- 确认验证
[root@master01 test]# kubectl get clusterissuer
NAME READY AGE
letsencrypt-issuer-prod-ali True 56s
[root@master01 test]# kubectl describe clusterissuers.cert-manager.io letsencrypt-issuer-prod-ali
证书使用
方式一:证书注解申请
配置 ingress调用从 ingress-shim 自动创建的 Certificate ,采用注解的方式,直接一步到位,省去了些证书申请的过程。
- 配置ingress
主要配置ingress部分。
[root@master01 test]# vim test-flask-demo.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-flask-dp
namespace: test
spec:
selector:
matchLabels:
name: hello-flask
template:
metadata:
name: hello-flask
labels:
name: hello-flask
spec:
containers:
- name: hello-flask
image: registry.cn-hangzhou.aliyuncs.com/xhyimages/hello-flask:v1.0.0
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: hello-flask-svc
namespace: test
spec:
selector:
name: hello-flask
ports:
- port: 80
targetPort: 5000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-flask-ingress
namespace: test
annotations:
cert-manager.io/cluster-issuer: letsencrypt-issuer-prod-ali
cert-manager.io/duration: 2160h
cert-manager.io/renew-before: 240h
cert-manager.io/private-key-algorithm: RSA
cert-manager.io/private-key-size: "2048"
cert-manager.io/private-key-rotation-policy: Always
spec:
ingressClassName: nginx
tls:
- hosts:
- flask.linuxsb.com
secretName: flask-linuxsb-com-tls
rules:
- host: flask.linuxsb.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-flask-svc
port:
number: 80
释义:
如上注解主要是实现:
- cert-manager 注解:告诉 ingress-shim 用哪个 ClusterIssuer
- tls 配置:告诉它证书域名和 Secret 名称
- 正式创建
正式创建测试环境。
[root@master01 test]# kubectl apply -f test-flask-demo.yaml
[root@master01 test]# kubectl -n test get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
hello-flask-dp-cd7fc68b-wbbjl 1/1 Running 0 17s 10.10.5.14 worker01 <none> <none>
[root@master01 test]# kubectl -n test get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
hello-flask-svc ClusterIP 10.20.28.147 <none> 80/TCP 24s name=hello-flask
[root@master01 test]# kubectl -n test get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
hello-flask-ingress nginx flask.linuxsb.com 10.20.127.248 80, 443 27s
方式二:证书手动申请
如果ingress已存在,或者不方便修改ingress注解,可独立创建证书申请,然后ingress中引用即可。
- 创建证书申请
[root@master01 test]# vim certificate-flask-linuxsb-com.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: hello-flask-certificate
namespace: test
spec:
secretName: flask-linuxsb-com-tls
issuerRef:
name: letsencrypt-issuer-prod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- flask.linuxsb.com
duration: 2160h # 90天
renewBefore: 240h # 提前10天续期
privateKey:
algorithm: RSA
size: 2048
rotationPolicy: Always
usages:
- digital signature
- key encipherment
- server auth
[root@master01 test]# kubectl apply -f certificate-flask-linuxsb-com.yaml
- 创建测试业务
不需要任何注解,只需要引用证书申请后创建的tls secret。
[root@master01 test]# vim test-flask-demo.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-flask-dp
namespace: test
spec:
selector:
matchLabels:
name: hello-flask
template:
metadata:
name: hello-flask
labels:
name: hello-flask
spec:
containers:
- name: hello-flask
image: registry.cn-hangzhou.aliyuncs.com/xhyimages/hello-flask:v1.0.0
ports:
- containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: hello-flask-svc
namespace: test
spec:
selector:
name: hello-flask
ports:
- port: 80
targetPort: 5000
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-flask-ingress
namespace: test
spec:
ingressClassName: nginx
tls:
- hosts:
- flask.linuxsb.com
secretName: flask-linuxsb-com-tls
rules:
- host: flask.linuxsb.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: hello-flask-svc
port:
number: 80
[root@master01 test]# kubectl apply -f test-flask-demo.yaml
- 两种区别
| 对比项 | Ingress 注解方式 | 显式 Certificate 方式 |
|---|---|---|
| 证书触发入口 | Ingress | Certificate |
| 是否需要手工写 Certificate | 否 | 是 |
| Ingress 是否承担证书元数据 | 是 | 否 |
| 配置清晰度 | 中 | 高 |
| 自动化便捷性 | 高 | 中 |
| GitOps 可控性 | 中 | 高 |
| 排障可读性 | 中 | 高 |
| 适合场景 | 简单网站、快速接入 | 生产标准化、平台化 |
确认验证
确认证书申请和ingress业务。
[root@master01 test]# kubectl -n test get secrets -o wide
NAME TYPE DATA AGE
flask-linuxsb-com-tls kubernetes.io/tls 2 55s
[root@master01 test]# kubectl -n test get certificate
NAME READY SECRET AGE
flask-linuxsb-com-tls True flask-linuxsb-com-tls 2m21s
[root@master01 test]# kubectl -n test describe certificate flask-linuxsb-com-tls
#……
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 2m26s cert-manager-certificates-trigger Issuing certificate as Secret does not exist
Normal Generated 2m26s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "flask-linuxsb-com-tls-7tp58"
Normal Requested 2m25s cert-manager-certificates-request-manager Created new CertificateRequest resource "flask-linuxsb-com-tls-1"
Normal Issuing 64s cert-manager-certificates-issuing The certificate has been successfully issued
[root@master01 test]# kubectl -n test describe ingress hello-flask-ingress
Name: hello-flask-ingress
Labels: <none>
Namespace: test
Address: 10.20.127.248
Ingress Class: nginx
Default backend: <default>
TLS:
flask-linuxsb-com-tls terminates flask.linuxsb.com
Rules:
Host Path Backends
---- ---- --------
flask.linuxsb.com
/ hello-flask-svc:80 (10.10.5.14:5000)
Annotations: cert-manager.io/cluster-issuer: letsencrypt-issuer-prod-ali
cert-manager.io/duration: 2160h
cert-manager.io/private-key-algorithm: RSA
cert-manager.io/private-key-rotation-policy: Always
cert-manager.io/private-key-size: 2048
cert-manager.io/renew-before: 240h
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateCertificate 3m10s cert-manager-ingress-shim Successfully created Certificate "flask-linuxsb-com-tls"
Normal Sync 3m6s (x2 over 3m10s) nginx-ingress-controller Scheduled for sync
还可以通过如下查看申请过程:
[root@master01 test]# kubectl -n test get certificaterequests.cert-manager.io flask-linuxsb-com-tls-1
NAME APPROVED DENIED READY ISSUER REQUESTER AGE
flask-linuxsb-com-tls-1 True True letsencrypt-issuer-prod-ali system:serviceaccount:cert-manager:cert-manager 3m40s
[root@master01 test]# kubectl -n test describe certificaterequests.cert-manager.io flask-linuxsb-com-tls-1
浏览器访问 https://flask.linuxsb.com 。

更多推荐

所有评论(0)