cert-manager:Kubernetes 自动 TLS 证书管理

cert-manager:Kubernetes 自动 TLS 证书管理

在现代云原生应用中,HTTPS 已经是基本要求而非可选项。手动申请、续期、部署 TLS 证书不仅繁琐,更容易因为证书过期导致服务中断。cert-manager 是 Kubernetes 生态中事实标准的证书管理器,它通过与 Let's Encrypt、Vault、Venafi 等 CA 对接,实现证书的全自动申请与续期,彻底解放运维人员的双手。本文将带你从零开始,在 K3s 集群上部署 cert-manager,配置 Let's Encrypt 颁发机构,并为 Ingress 自动签发受信任的 HTTPS 证书。


服务器配置

本教程假设你已经有一个运行中的 K3s 集群。cert-manager 本身资源消耗较小,但需要为集群节点预留足够的资源。推荐配置如下:

组件 规格
CPU 2 核
内存 4 GB
系统盘 40 GB SSD
操作系统 Ubuntu 22.04 LTS
网络 公网 IP(HTTP01 challenge 必须)

如果你还没有合适的云服务器,可考虑 雨云服务器 rainyun 。注册填 2026off 领 5 折,2 核 4GB 机型完全满足 K3s 单节点集群的运行需求。

确认集群就绪:

bash 复制代码
kubectl get nodes
# NAME          STATUS   ROLES                  AGE   VERSION
# k3s-master    Ready    control-plane,master   1d    v1.29.0+k3s1

安装

添加 Helm 仓库

bash 复制代码
helm repo add jetstack https://charts.jetstack.io
helm repo update

安装 cert-manager

cert-manager 依赖多个 CRD(Custom Resource Definition),推荐使用 --set installCRDs=true 在安装时一并部署:

bash 复制代码
kubectl create namespace cert-manager

helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --version v1.14.0 \
  --set installCRDs=true \
  --set global.leaderElection.namespace=cert-manager

验证安装

bash 复制代码
kubectl get pods -n cert-manager
# NAME                                      READY   STATUS    RESTARTS   AGE
# cert-manager-7d9f5b6b8-xk9pv             1/1     Running   0          2m
# cert-manager-cainjector-6b9b4f9b8-lmn2p  1/1     Running   0          2m
# cert-manager-webhook-5b97f97b4-qrs7t      1/1     Running   0          2m

三个 Pod 全部 Running 后即安装成功。


核心概念

cert-manager 通过以下几个 CRD 来管理证书生命周期:

ClusterIssuer / Issuer

Issuer 是命名空间级别的证书颁发机构配置,ClusterIssuer 是集群级别的,可跨命名空间使用。生产环境推荐使用 ClusterIssuer。

支持的颁发机构类型:

  • ACME(Let's Encrypt):最常用,支持 HTTP01 和 DNS01 两种 challenge
  • CA:使用集群内部的 CA 证书签发
  • Vault:对接 HashiCorp Vault
  • Venafi:企业级证书管理

Certificate

Certificate 资源描述了你想要的证书规格(域名、有效期、存储的 Secret 名称等),cert-manager 会根据此资源自动向颁发机构申请证书,并将结果存入指定的 Kubernetes Secret。

CertificateRequest

CertificateRequest 是 cert-manager 内部创建的中间资源,代表一次具体的证书申请动作,通常不需要手动创建,由 Certificate 控制器自动管理。

Challenge / Order

ACME 协议中,cert-manager 会创建 OrderChallenge 资源来完成域名所有权验证。HTTP01 challenge 会在集群中临时创建一个 Pod 来响应 Let's Encrypt 的验证请求;DNS01 challenge 则通过修改 DNS 记录来验证。


实战示例

1. 配置 ClusterIssuer(HTTP01 Challenge)

HTTP01 是最简单的验证方式,Let's Encrypt 会向 http://<your-domain>/.well-known/acme-challenge/<token> 发起请求,要求集群能从公网访问。

yaml 复制代码
# cluster-issuer-http01.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # Let's Encrypt 生产环境
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: traefik   # K3s 默认使用 Traefik,nginx 集群改为 nginx
bash 复制代码
kubectl apply -f cluster-issuer-http01.yaml

# 验证状态
kubectl get clusterissuer letsencrypt-prod
# NAME               READY   AGE
# letsencrypt-prod   True    30s

2. 配置 ClusterIssuer(DNS01 Challenge with Cloudflare)

DNS01 适合通配符证书或无法从公网访问的内网集群:

yaml 复制代码
# cluster-issuer-dns01.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns01
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@example.com
    privateKeySecretRef:
      name: letsencrypt-dns01-account-key
    solvers:
    - dns01:
        cloudflare:
          email: your-cloudflare-email@example.com
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

首先创建 Cloudflare API Token Secret:

bash 复制代码
# 在 Cloudflare 控制台创建具有 Zone:DNS:Edit 权限的 API Token
kubectl create secret generic cloudflare-api-token-secret \
  --namespace cert-manager \
  --from-literal=api-token=YOUR_CLOUDFLARE_API_TOKEN
bash 复制代码
kubectl apply -f cluster-issuer-dns01.yaml

3. 手动创建 Certificate 资源

yaml 复制代码
# my-app-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-app-tls
  namespace: default
spec:
  secretName: my-app-tls-secret   # cert-manager 将证书存入此 Secret
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: app.example.com
  dnsNames:
  - app.example.com
  - www.app.example.com
  duration: 2160h      # 90 天
  renewBefore: 360h    # 提前 15 天续期
bash 复制代码
kubectl apply -f my-app-certificate.yaml

# 观察证书申请过程
kubectl describe certificate my-app-tls -n default
kubectl get certificaterequest -n default

4. 通过 Ingress 注解自动签发证书

这是最常用的方式,只需在 Ingress 上加一个注解,cert-manager 会自动创建 Certificate 资源:

yaml 复制代码
# my-app-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  namespace: default
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod   # 指定 ClusterIssuer
    # 如果使用命名空间级别的 Issuer:
    # cert-manager.io/issuer: letsencrypt-prod
spec:
  ingressClassName: traefik
  tls:
  - hosts:
    - app.example.com
    secretName: my-app-tls-secret   # cert-manager 会自动填充此 Secret
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-service
            port:
              number: 80
bash 复制代码
kubectl apply -f my-app-ingress.yaml

常用命令

查看证书状态

bash 复制代码
# 列出所有命名空间的证书
kubectl get certificate -A

# 查看某个证书详情(包含事件和状态)
kubectl describe certificate my-app-tls -n default

# 查看证书实际内容(过期时间等)
kubectl get secret my-app-tls-secret -n default -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -dates

排查申请失败问题

bash 复制代码
# 查看 CertificateRequest 状态
kubectl get certificaterequest -n default
kubectl describe certificaterequest my-app-tls-xxxxx -n default

# 查看 ACME Order 状态
kubectl get order -n default
kubectl describe order my-app-tls-xxxxx -n default

# 查看 Challenge 状态
kubectl get challenge -n default
kubectl describe challenge my-app-tls-xxxxx -n default

# 查看 cert-manager 控制器日志
kubectl logs -n cert-manager deploy/cert-manager -f

# 查看 webhook 日志
kubectl logs -n cert-manager deploy/cert-manager-webhook -f

手动触发证书续期

bash 复制代码
# 方法1:删除 CertificateRequest,cert-manager 会自动重新申请
kubectl delete certificaterequest my-app-tls-xxxxx -n default

# 方法2:使用 cmctl 工具强制续期
cmctl renew my-app-tls -n default

安装 cmctl(cert-manager CLI)

bash 复制代码
curl -L -o cmctl https://github.com/cert-manager/cmctl/releases/latest/download/cmctl_linux_amd64
chmod +x cmctl
sudo mv cmctl /usr/local/bin/

# 检查 cert-manager 健康状态
cmctl check api
cmctl status certificate my-app-tls -n default

常见故障排查

bash 复制代码
# Challenge 一直处于 pending 状态:检查 Ingress/DNS 是否可公网访问
kubectl get challenge -n default -o wide

# 证书 READY=False:查看 conditions 字段
kubectl get certificate my-app-tls -n default -o yaml | grep -A 10 conditions

# 速率限制:Let's Encrypt 有每域名每周 5 次的证书申请限制,测试时使用 staging 环境
# staging server: https://acme-staging-v02.api.letsencrypt.org/directory

cert-manager 将繁琐的 TLS 证书运维工作完全自动化,是 Kubernetes 生产集群不可或缺的组件。配合 Let's Encrypt 的免费证书,你可以零成本实现全站 HTTPS,且无需担心证书过期问题。

相关推荐
阿里云云原生1 小时前
【5.29北京】智驭运维,Agentic Ops可观测工作坊限时报名!
云原生·agent
卧室小白4 小时前
docker容器
运维·docker·容器
Benszen4 小时前
Docker容器化解决方案
运维·docker·容器
LT10157974444 小时前
2026年云原生RPA选型指南:云端协同与弹性部署适配
云原生·rpa
姚不倒5 小时前
Go 语言基础入门:从零到实战,一篇文章掌握核心语法
云原生·golang
仙柒4155 小时前
Namespace
运维·docker·容器
nan madol6 小时前
openEuler部署 Kubernetes v1.35.5 集群
云原生·容器·kubernetes
木雷坞6 小时前
K8s containerd 镜像源配置:用 1ms-helper 处理 ImagePullBackOff
云原生·容器·kubernetes
pigs20186 小时前
Docker容器中Kingbase数据库授权到期更换解决方案
数据库·docker·容器