项目设计

项目规划

当前结合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 。

001

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐