下面说明基于 Kubernetes v1.24+、cert-manager v1.13+、Ingress-Nginx v1.8+,为生产环境设计的步骤。
一、为什么需要自动化 SSL 证书?
在生产环境中,手动为 Ingress 配置 SSL证书面临三大挑战:
证书有效期短:Let's Encrypt 等免费证书的有效期通常只有 90 天,手动更新极易出错。
操作繁琐:每次申请、更新证书都需要生成密钥、创建 Secret、修改 Ingress 配置,无法规模化。
业务风险高:证书过期将直接导致 HTTPS 访问失败,影响线上业务。
Cert-Manager 作为 Kubernetes 生态的标准证书管理工具,通过 ACME(自动证书管理环境)协议,能与 Let's Encrypt 等证书颁发机构(CA)无缝对接,实现证书的**自动申请、部署和续期,全程零人工介入。
二、核心技术组件
Cert-Manager:Kubernetes 原生的证书生命周期管理控制器,自动处理证书的申请、续期和存储。
Let's Encrypt:提供免费、自动化、受浏览器信任的 SSL/TLS 证书,支持 ACME 协议。
ACME 挑战:证书申请时的域名所有权验证方式。最常用的是 HTTP-01 挑战(通过域名上的特定 HTTP 路径验证)和 DNS-01 挑战(通过 DNS TXT 记录验证)。
三、实施步骤(生产级配置)
步骤 1:安装 Ingress Controller
Cert-Manager 需要配合 Ingress Controller 工作,这里以最主流的 Ingress-Nginx 为例。
bash
添加 Helm 仓库并安装 Ingress-Nginx
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.service.type=LoadBalancer # 根据环境调整 Service 类型
安装完成后,通过 `kubectl get svc -n ingress-nginx` 获取 **EXTERNAL-IP,将你的域名(如 `example.com`)通过 A 记录解析到该 IP 地址。
步骤 2:安装 Cert-Manager
使用 Helm 安装 Cert-Manager,并启用其 CRD(自定义资源定义):
bash
# 添加 Jetstack 仓库(Cert-Manager 官方维护)
helm repo add jetstack https://charts.jetstack.io
helm repo update
# 安装 Cert-Manager(指定版本以兼容生产环境)
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.14.3 \
--set installCRDs=true
验证安装成功:
bash
kubectl get pods -n cert-manager
# 应看到三个 Pod 均处于 Running 状态:cert-manager-xxx, cert-manager-cainjector-xxx, cert-manager-webhook-xxx
步骤 3:创建 ClusterIssuer(集群级证书签发器)
ClusterIssuer 是 Cert-Manager 的核心配置,定义了如何与 Let's Encrypt 交互。强烈建议先配置 Staging 环境进行测试,再切换到 Production,避免因配置错误触发速率限制。
创建 `cluster-issuer.yaml` 文件:
yaml
# 测试环境 ClusterIssuer(用于验证配置)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: your-email@example.com # ⚠️ 替换为你的邮箱,用于接收证书过期提醒
privateKeySecretRef:
name: letsencrypt-staging-account-key
solvers:
- http01:
ingress:
class: nginx # 必须与 Ingress Controller 的 IngressClass 名称一致
# 生产环境 ClusterIssuer(稳定后使用)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: your-email@example.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginx
应用配置:
bash
kubectl apply -f cluster-issuer.yaml
步骤 4:为 Ingress 配置自动 HTTPS
Cert-Manager 提供了两种自动签发证书的方式,各有适用场景:
方式 描述 适用场景
方式一:Ingress Annotation 在 Ingress 中添加 `cert-manager.io/cluster-issuer` 注解,Cert-Manager 自动创建证书 简单域名,证书仅在 Ingress 中使用
方式二:Certificate 资源 创建独立的 Certificate CRD,声明证书的域名和 Secret 名称 需要精细化控制证书配置、跨 Ingress 复用证书等
方式一:通过 Annotation 自动签发(推荐,最简单)
创建 `ingress.yaml`:
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod" # 指定使用生产环境签发器
kubernetes.io/ingress.class: "nginx" # 指定 Ingress Controller
spec:
tls:
- hosts:
- example.com
- www.example.com
secretName: example-com-tls # Cert-Manager 会自动创建此 Secret
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80
应用 Ingress 后,Cert-Manager 会自动检测到 `cert-manager.io/cluster-issuer` 注解,在几分钟内完成证书申请、验证并创建 `Secret`。
方式二:通过 Certificate 资源管理证书
对于复杂场景(如多 Ingress 共用同一证书),可以显式创建 Certificate 资源:
yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-cert
namespace: default
spec:
secretName: example-com-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- example.com
- www.example.com
然后在 Ingress 中直接引用该 Secret:
yaml
spec:
tls:
- hosts:
- example.com
- www.example.com
secretName: example-com-tls
四、自动续期机制
Cert-Manager 会主动监控已颁发证书的过期时间。对于 Let's Encrypt 的 90 天证书,Cert-Manager 默认在到期前 30 天自动发起续期请求,无需任何人工干预。
你可以通过以下命令查看证书状态和续期历史:
bash
kubectl get certificate -A
kubectl describe certificate example-com-cert
五、验证 HTTPS 配置
1. 检查 Certificate 资源状态:
bash
kubectl get certificate -A
kubectl describe certificate example-com-cert
正常状态下,`READY` 列应为 `True`,`AGE` 列会显示证书创建时间。
2. 检查 Secret 是否成功创建:
bash
kubectl get secret example-com-tls -o yaml
应看到 `tls.crt` 和 `tls.key` 字段。
3. 测试 HTTPS 访问:
bash
curl -v https://example.com
应返回证书信息及 HTTP 200 状态码。也可以使用浏览器访问 `https://example.com`,确认地址栏出现安全锁标志。
五、备选方案:轻量级替代工具
如果 Cert-Manager 对你来说过于复杂,可以考虑以下轻量级替代品:
工具 特点 适用场景
KCert 配置精简,只需约 100 行 YAML,整个程序轻量部署 | 小型项目、边缘集群
Go 原生替代品 仅 23KB 二进制,支持 ACME + 私有 CA + Secret 自动轮转 资源受限的边缘设备
六、常见问题与解决方案
问题现象 可能原因 解决方案
`kubectl get certificate` 显示 `READY=False` Ingress 中指定的 `secretName` 与 Certificate 不一致;域名 DNS 未正确解析到 Ingress IP 检查 Secret 名称一致性;确保域名 A 记录已指向 LoadBalancer IP
Cert-Manager 日志报 `acme: error: 429` Let's Encrypt 速率限制(Staging 环境每域名每小时 5 次失败尝试) 切换至 Staging 环境调试,或等待限制解除
HTTP-01 挑战失败(`/.well-known/acme-challenge/` 无法访问) Ingress Controller 强制 HTTP→HTTPS 重定向,导致验证请求被拦截 为 Ingress 添加注解 `nginx.ingress.kubernetes.io/ssl-redirect: "false"` 临时放行
Ingress 未自动获取证书 未添加 `cert-manager.io/cluster-issuer` 注解 在 Ingress 的 `metadata.annotations` 中添加正确注解
Ingress Controller IngressClass 不匹配 ClusterIssuer 中 `ingress.class` 与实际不符 通过 `kubectl get ingressclass` 确认正确的 IngressClass,并同步配置
七、生产环境最佳实践
先 Staging 后 Production:务必先在 Let's Encrypt Staging 环境验证所有配置,避免触发生产环境的速率限制。
监控证书状态:通过 Prometheus + Alertmanager 监控 `cert-manager` 的指标,及时获知证书申请或续期失败的情况。
HTTP 强转 HTTPS:在 Ingress 中添加注解 `nginx.ingress.kubernetes.io/ssl-redirect: "true"`,将所有 HTTP 流量永久重定向至 HTTPS。
启用 HSTS:在 Ingress 中添加注解 `nginx.ingress.kubernetes.io/hsts: "true"`,强制浏览器在未来一段时间内仅使用 HTTPS 访问。
定期备份:定期备份 Certificate 和 Secret 资源,避免集群故障导致证书丢失。
通过上述配置,你的 Kubernetes Ingress 即可实现 SSL证书的全自动管理,告别手动续期的繁琐与风险。如果你在实施过程中遇到具体问题,欢迎随时提出,我们可以一起排查!