Cert-Manager Kubernetes 证书签发与管理详解

在 Kubernetes 集群上通过 Helm 从零安装 cert-manager,签发并与自动续期自签名/Let's Encrypt 证书,覆盖 issuer/certificate CR 结构与 Duration、RenewBefore 配置及 kubectl 验证。

证书管理证书管理Cert-Manager2026/10/08

Cert-Manager Kubernetes 证书签发与管理详解

目标:在已有 Kubernetes 集群上通过 Helm 从零安装 cert-manager,并签发由集群内部 CA、以及 Let's Encrypt 自动续期的 TLS 证书,覆盖 Issuer / Certificate 自定义资源的含义、Duration 与 RenewBefore 控制续期时机的配置,以及 kubectl 全流程验证与 CLI 速查。

cert-manager 是 Kubernetes 生态中最常用的证书签发与自动化续期组件。它通过声明式自定义资源(CRD)把「证书申请」抽象为一种资源:你只需描述「我要一张给哪个域名、由谁签发的证书」,cert-manager 便会在后台申请、验收并在到期前自动续期,证书内容以 Secret 形式供 Ingress 等引用。

⚠️ 前置说明:cert-manager 是一款只运行在 Kubernetes 之上的控制器组件,正文整套命令均在「已可用的 Kubernetes 集群」上执行。部署前需先准备好可用的 Kubernetes 集群(含 kubectl 管理端),并已安装 cert-manager 所需的 CustomResourceDefinitions(CRD);若集群通过 Helm 安装则相关 CRD 会一并装入。

环境信息

  • Kubernetes 集群:Kubernetes v1.28+(已通过 kubectl 可访问)
  • Helm 版本:v3.12 及以上(安装 cert-manager 主程序)
  • cert-manager 版本:v1.15 系列
  • 目标命名空间:cert-manager(控制面组件自身)
  • 示例应用命名空间:myapp(业务证书)
  • 签发对象:集群自签名 CA(ClusterIssuer)、Let's Encrypt 说明(章节四)
  • 相关自定义资源:Issuer、ClusterIssuer、Certificate、CertificateRequest

一、版本选型与获取

cert-manager 以 Helm Chart 方式发布,Chart 仓库位于 Jetstack:

helm repo add jetstack https://charts.jetstack.io
helm repo update

查询可用的 cert-manager 版本:

helm search repo jetstack/cert-manager --versions
版本发布说明推荐度
v1.15.x当前稳定主线,支持 k8s 1.28+,API 资源版本稳定推荐
v1.14.x前序稳定版本兼容期
更旧版本依赖较老 k8s不建议新部署

💡 说明:cert-manager 主程序为 Go 二进制,默认堆内存不大;日常有限资源集群可通过 Helm --set controller.resources.limits.memory=256Mi --set controller.resources.limits.cpu=200m 限制使用(见 2.3)。它不依赖 JVM,无需配置 -Xmx 之类参数。

二、在集群上安装 cert-manager

2.1 前置检查

确认 kubectl 可连接集群:

kubectl cluster-info
kubectl get nodes

确认 Helm 已就绪:

helm version

2.2 安装 cert-manager CRD 与控制器

⚠️ 前置:cert-manager 依赖其 CRD(Issuer、ClusterIssuer、Certificate、CertificateRequest、Challenge、Order)。安装过程会同时建立 CRD,若希望与 Helm package 生命周期解耦,可先单独应用 CRD 清单(使用 kubectl apply 到 crds.cert-manager.io 复用现有 CRD,避免重复安装)。以下为标准安装:

创建命名空间并安装:

kubectl create namespace cert-manager
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --version v1.15.3 \
  --set installCRDs=true

⚠️ 注意:--set installCRDs=true 会在 Helm 安装时一并创建 cert-manager 的全部 CRD。生产环境建议显式以 kubectl apply 单独管理 CRD 版本再安装控制器,并把该参数保持 true 以保证首次可用。

实测预期回显(helm install 成功):

NAME: cert-manager
LAST DEPLOYED: Wed Oct  8 12:58:00 2026
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager has been deployed successfully!
(省略 Chart NOTES 正文中其余说明)

2.3 查看控制器 Pod 与状态

kubectl get pods -n cert-manager

预期回显:

NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-7d8f9d6f6b-abc12              1/1     Running   0          2m
cert-manager-cainjector-6d7df5cd8f-xyz34   1/1     Running   0          2m
cert-manager-webhook-5c7c6f6f8b-qr56       1/1     Running   0          2m

💡 说明:cert-manager(控制器)、cert-manager-cainjector(注入 CA BUNDLE)、cert-manager-webhook(校验 CR)三个 Deployment 各就一位即表示正常。

校验 CRD 已安装:

kubectl get crd | grep cert-manager.io

预期回显(kubectl get crd 会列出该命名空间下的全部 CRD,此处仅过滤 cert-manager.io 相关,并省略列宽):

certificates.cert-manager.io
certificaterequests.cert-manager.io
challenges.acme.cert-manager.io
clusterissuers.cert-manager.io
issuers.cert-manager.io
orders.acme.cert-manager.io

2.4 systemd 说明

⚠️ 注意:cert-manager 作为控制面组件本身运行在 Kubernetes 工作负载内,由 Kubernetes 调度并保持,不通过 Linux 宿主机的 systemd 托管。承载 Kubernetes 节点的 Linux 主机上,Pod 运行时与 kubelet 由各自 systemd 单元管理,本文不再赘述。

三、签发集群自签名 CA 证书

3.1 创建自签名 ClusterIssuer

创建一个自签名的 ClusterIssuer(颁发主体自身),用于为集群内部签发测试证书:

# cluster-issuer-selfsigned.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
kubectl apply -f cluster-issuer-selfsigned.yaml
kubectl get clusterissuer selfsigned-issuer -o wide

预期回显:

NAME                TYPE          STATUS   AGE
selfsigned-issuer   SelfSigned    True     5s

3.2 创建由该 Issuer 签发的 Certificate 资源

通过 Certificate 资源申请一张给 myapp 命名空间下服务的证书:

# myapp-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: myapp-tls
  namespace: myapp
spec:
  secretName: myapp-tls
  issuerRef:
    name: selfsigned-issuer
    kind: ClusterIssuer
  commonName: myapp.example.com
  dnsNames:
    - myapp.example.com
  duration: 2160h      # 90 天
  renewBefore: 360h    # 到期前 15 天续期

⚠️ 前置:myapp 命名空间须已存在(kubectl create namespace myapp)。

kubectl create namespace myapp
kubectl apply -f myapp-certificate.yaml
kubectl get certificate -n myapp myapp-tls -o wide

预期回显:

NAME         READY   SECRET          ISSUER                STATUS   AGE
myapp-tls    True    myapp-tls       selfsigned-issuer     Ready    10s

3.3 Duration 与 RenewBefore 续期配置说明

参数含义默认值示例
spec.duration证书有效期90 天(2160h)2160h、720h
spec.renewBefore到期前多久触发续期30 天(720h)360h(提前 15 天)
spec.renewBeforePercent按生命周期比例触发无60(剩余 60% 时续期)

⚠️ 注意:renewBefore 不得大于或等于 duration,否则 cert-manager 会持续触发续期并报错。为资源手动改名不会重新签发,需要续期时机调整应直接改这两个字段,cert-manager 会按到达时间自动重签。

3.4 验证签发的 Secret 与证书内容

查看 Secret 是否被自动填充:

kubectl get secret -n myapp myapp-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -subject -dates -ext subjectAltName

预期回显(subject 到期时间来自 3.2 的 duration):

subject=CN = myapp.example.com
notBefore=Oct  8 12:59:00 2026 GMT
notAfter=Jan  6 12:59:00 2027 GMT
X509v3 Subject Alternative Name:
    DNS:myapp.example.com

💡 说明:证书以 tls.crt、tls.key 两把键存放在 myapp-tls Secret 内,Ingress 可通过 secretName: myapp-tls 直接引用。

四、签发 Let's Encrypt 证书(外网签发说明)

Let's Encrypt 提供受公共信任的证书,适合对外 Ingress。流程与自签名一致,区别在 Issuer 改为 ACME 类型,并需要域名解析可用验证(HTTP-01 默认校验)。

⚠️ 前置:使用 Let's Encrypt 需要

  • 待签发域名(如 app.example.com)能正确解析到集群 Ingress 的对外地址;
  • 集群能出网访问 https://acme-v02.api.letsencrypt.org/directory(暂不生产可用时,可用预演环境 LE_STAGING URL 测试);
  • 已部署并配置 Ingress Controller 以暴露 .well-known/acme-challenge。

4.1 创建 ClusterIssuer(Let's Encrypt 生产)

# letsencrypt-prod.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
      - http01:
          ingress:
            class: nginx
kubectl apply -f letsencrypt-prod.yaml
kubectl get clusterissuer letsencrypt-prod -o wide

预期回显:

NAME                TYPE   STATUS   AGE
letsencrypt-prod    ACME   True     5s

4.2 通过 Let's Encrypt 签发证书

# app-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: app-tls
  namespace: myapp
spec:
  secretName: app-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - app.example.com
  duration: 2160h
  renewBefore: 360h
kubectl apply -f app-certificate.yaml
kubectl get certificate -n myapp app-tls -o wide

预期回显(首次出站验证需要时间):

NAME      READY   SECRET    ISSUER             STATUS   AGE
app-tls   True    app-tls   letsencrypt-prod   Ready    45s

💡 说明:签发过程中会先生成 CertificateRequest 与 ACME Challenge/Order,验证通过后 Ready=True。可用 kubectl describe certificate -n myapp app-tls 查看事件详情。

五、查看签发请求与资源

5.1 查看 CertificateRequest

每个 Certificate 生成时都会创建对应的 CertificateRequest 资源:

kubectl get certificaterequest -n myapp

预期回显:

NAME          APPROVED   DENIED   READY   ISSUER             REQUESTOR                AGE
myapp-tls-pk   True                True    selfsigned-issuer  system:serviceaccount:cert-manager:cert-manager   5m

5.2 查看全部资源类型

kubectl api-resources | grep cert-manager.io

预期回显:

certificates                            cert.cert-manager.io/v1
certificaterequests                     cert.cert-manager.io/v1
challenges                              acme.cert-manager.io/v1
clusterissuers                          cert-manager.io/v1
issuers                                 cert-manager.io/v1
orders                                  acme.cert-manager.io/v1

5.3 更新 Certificate 资源触发重签

修改 duration 或 dnsNames 后 kubectl apply 即可,cert-manager 会按新的配置重新签发:

kubectl apply -f myapp-certificate.yaml
kubectl get certificate -n myapp myapp-tls -o wide

六、常用 CLI 命令速查

因为 cert-manager 是 Kubernetes 里的控制器,它的「CLI」实际就是通过 kubectl 操作其自定义资源:

操作命令
查看 ClusterIssuerkubectl get clusterissuer -o wide
查看 Issuerkubectl get issuer -A
查看证书kubectl get certificate -A -o wide
查看签发请求kubectl get certificaterequest -A
查看 ACME 订单/挑战kubectl get orders,challenges -A
查看证书事件kubectl describe certificate -n <ns> <name>
查看控制器日志kubectl logs -n cert-manager deploy/cert-manager
查看所有已发证书 Secretkubectl get secret -n <ns> --field-selector type=kubernetes.io/tls

6.1 查看证书到期时间(续期生效检验)

kubectl get secret -n myapp myapp-tls -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -enddate

预期回显:

notAfter=Jan  6 12:59:00 2027 GMT

💡 说明:证书到期时间由 spec.duration(有效期)决定;当系统时间距 notAfter 的差值小于 spec.renewBefore 时,cert-manager 会自动用对应 Issuer 续期并覆盖 Secret 中的 tls.crt/tls.key。

七、常见问题(FAQ)

Q1:CRD 版本与控制器版本不匹配导致 no matches for kind?

多数是因 CRD 未正确安装。解决办法:确认 kubectl get crd | grep cert-manager.io 列表完整(见 2.3),并以对应版本重新安装 CRD 后重启控制器 Deployment。

Q2:Certificate 一直 READY=False,如何排查?

先用 kubectl describe certificate -n <ns> <name> 查看事件;定位到 CertificateRequest 失败时,接着查看 kubectl get certificaterequest、kubectl describe certificaterequest 与 kubectl get orders,challenges。ACME 常见失败为域名解析/校验不通过。

Q3:Let's Encrypt 验证总是失败?

三处核对:域名 A/AAAA 记录是否解析到 Ingress 对外 IP;Ingress Controller 是否覆盖 /.well-known/acme-challenge 与 HTTP 80 通道;集群是否可出网访问 ACME 目录。 可用预演环境(staging)先在 Issuer.spec.acme.server 指向 https://acme-staging-v02.api.letsencrypt.org/directory 排查,确认通过后再切生产地址。

Q4:证书续期了但 notAfter 没变化?

确认 spec.duration 是否被修改;同时检查 renewBefore < duration。若二者不符,cert-manager 会持续触发新 Order 且证书可能被频繁替换。

Q5:卸载 cert-manager?

先删除所有 Certificate、Issuer/ClusterIssuer 资源,再卸载 Helm release:

kubectl delete certificate,issuer,clusterissuer,certificaterequest -A --all
helm uninstall cert-manager -n cert-manager
kubectl delete namespace cert-manager

若 CRD 是单独以 kubectl 管理而需一并移除,可执行:

kubectl delete crd certificates.cert-manager.io certificaterequests.cert-manager.io challenges.acme.cert-manager.io clusterissuers.cert-manager.io issuers.cert-manager.io orders.acme.cert-manager.io

生产谨慎,删除 CRD 会移除其全部资源定义。

八、参考链接