一、简介
在 Kubernetes 中,HTTPS已经成为对外服务的标准要求,例如,上篇文章中介绍的开源CI&CD工具-Drone,在个人学习环境中使用域名https://drone.fzwtest.xyz/时,手动申请和更新证书既繁琐又容易出错。
我们可以借助一些免费的自动化工具来简化这一过程。类似于在Linux服务器上使用certbot的方式,cert-manager是一个适用于Kubernetes的开源工具,支持通过ACME协议(如 Let's Encrypt)自动签发免费证书,并可实现自动续期。本文将基于HTTP‑01验证方式,结合 Ingress‑NGINX控制器,演示完整的自动证书签发与续期流程。

二、关键概念
1.Issuer/ClusterIssuer
用于定义证书的签发来源(如 Let's Encrypt、Vault、自签)。
2.Certificate
用于声明需要签发的域名、密钥、Secret名称等信息。
3.HTTP-01 & DNS-01
HTTP-01:通过自动、临时创建的Ingress暴露一个HTTP 路径 /.well-known/acme-challenge/... 给 Let's Encrypt等验证。优点是配置简单,但不支持泛域名。
DNS-01:通过在DNS提供商处自动添加TXT记录验证,支持泛域名但配置复杂。
三、组件介绍
1.cert-manager(核心控制器主进程)
这是 cert-manager 的"大脑",负责所有核心逻辑:
| 功能 | 说明 |
|---|---|
| 监控 Issuer/ClusterIssuer | 当你创建Issuer/ClusterIssuer时,它负责创建对应的ACME客户端 |
| 监控Certificate | 检测证书是否存在、是否过期、是否需要续期 |
| 创建ACME Order/Challenge | ACME协议核心步骤 |
| 自动处理续期 | 默认提前 30 天开始续约 |
| 写入 Secret(TLS) | ACME返回证书后写入Secret |
2.cert-manager-cainjector(CA注入器)
这个组件将CA根证书自动注入到相关资源中,场景包括:
-
ValidatingWebhookConfiguration(用于cert-manager自身)
-
MutatingWebhookConfiguration
-
CRD注释中的
cert-manager.io/inject-ca-from -
在某些Issuer类型中,为内部CA自动注入trust chain
由于cert-manager使用webhook校验CRD,如果不自动注入CA,K8S apiserver会拒绝无效证书的Webhook。
3.cert-manager-webhook(准入控制/校验器)
该组件作用:
(1)CRD 准入校验(Validation)
(2)Mutation(自动填充默认值)
(3)提供cert-manager与API交互过程中所需的TLS服务
四、环境准备
我在个人学习环境中做简单演示,环境是自建的K8S,也没有使用负载均衡,并且缺少一些安全控制措施**(不适用于生产环境)**。
1.安装并运行ingress-nginx-controller
按照官方文档安装ingress-nginx-controller,然后把网络模式设置为hostNetwork: true,直接监听443端口;并通过nodeSelector等参数把pod固定在某台node节点上。检查运行状态:
kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-controller-75777c6945-sh86x 1/1 Running 9 (14h ago) 9d
netstat -antlp |grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 3713752/nginx: node1
2.配置域名解析
以drone.fzwtest.xyz为例:

3.配置网络策略
防火墙放行80端口:

五、配置部署
1.安装组件
安装基本组件,比较简单:
wget https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
vim cert-manager.yaml
kubectl apply -f cert-manager.yaml
kubectl get pod -n cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-6468fc8f56-67jwr 1/1 Running 0 12s
cert-manager-cainjector-7fd85dcc7-2nr7q 1/1 Running 0 15s
cert-manager-webhook-57df45f686-ggv7l 1/1 Running 1 17s
2.创建ClusterIssuer
创建ClusterIssuer,指定从letsencrypt申请免费证书,并指定跟ingress-nginx-controller做集成:
vim cluster-issuer.yaml
kubectl apply -f cluster-issuer.yaml
kubectl get clusterissuer
NAME READY AGE
letsencrypt-prod True 178s
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: xxxxx # 邮箱,用于接收过期提醒等
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
class: nginx #你的Ingress Controller类型,这里我们用的nginx
3.创建ingress
为测试域名创建一个Ingress,指定使用的ClusterIssuer以及自动生成的secret的名称:
vim drone-ingress.yaml
kubectl apply -f drone-ingress.yaml
kubectl get ingress -n drone
NAME CLASS HOSTS ADDRESS PORTS AGE
drone-ingress nginx drone.fzwtest.xyz 10.110.30.86 80, 443 145s
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: drone-ingress
namespace: drone
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- drone.fzwtest.xyz
secretName: drone-tlss
rules:
- host: drone.fzwtest.xyz
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: drone-server
port:
number: 80
4.验证状态
查看自动生成的CR资源和secret资源:
kubectl -n drone get certificates
NAME READY SECRET AGE
drone-tlss True drone-tlss 149s
kubectl -n drone get certificaterequests
NAME APPROVED DENIED READY ISSUER REQUESTER AGE
drone-tlss-1 True True letsencrypt-prod system:serviceaccount:cert-manager:cert-manager 145s
kubectl -n drone get secret
NAME TYPE DATA AGE
drone-tlss kubernetes.io/tls 2 151s
访问域名,可以看到已经自动挂载了免费证书(虽然只有三个月有效期,但cert-manager会自动续签证书,不再需要手动做任何操作)。
