本文档基于实战经验,详细记录了在 Kubernetes 集群中使用 cert-manager 和 cert-manager-webhook-dnspod 为 EMQX 自动申请和续签 Let's Encrypt 通配符证书的完整步骤。特别涵盖了配置过程中常见的陷阱及解决方案,包括跨命名空间证书自动同步,确保证书续签后 EMQX 能自动加载新证书。
1. 环境要求
- Kubernetes 集群 1.19+
kubectl已配置,能正常访问集群- 拥有一个托管在腾讯云 DNSPod 的域名(如
mqtt.conststar.com) - 腾讯云 API 密钥(SecretId/SecretKey),具备操作 DNSPod 的权限(至少
CreateRecord、DescribeRecordList、DeleteRecord) - (可选)Helm 3 已安装
2. 安装 cert-manager
cert-manager 是整个自动化的核心,建议使用 Helm 安装最新版本。
# 添加 Jetstack Helm 仓库
helm repo add jetstack https://charts.jetstack.io
helm repo update
# 安装 cert-manager,并安装 CRDs
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set installCRDs=true
等待 Pod 就绪:
kubectl get pods -n cert-manager -w
3. 安装 cert-manager-webhook-dnspod
由于官方 Helm 仓库可能失效,我们从 GitHub Releases 下载 Chart 包进行安装。
3.1 下载 Chart
访问 cert-manager-webhook-dnspod releases 获取最新版本号(例如 1.5.2),然后在服务器上执行:
wget https://github.com/imroc/cert-manager-webhook-dnspod/releases/download/cert-manager-webhook-dnspod-1.5.2/cert-manager-webhook-dnspod-1.5.2.tgz
3.2 安装
helm install cert-manager-webhook-dnspod ./cert-manager-webhook-dnspod-1.5.2.tgz \
--namespace cert-manager \
--set groupName=acme.dnspod.com
注意:
groupName可以是任意域名格式,不需要真实存在,但必须与 ClusterIssuer 中的值一致。
4. 创建腾讯云 API 密钥 Secret
将你的真实 SecretId 和 SecretKey 存入 Kubernetes Secret(注意键名必须与后续配置一致):
kubectl create secret generic dnspod-secret -n cert-manager \
--from-literal=secretId=<你的真实SecretId> \
--from-literal=secretKey=<你的真实SecretKey>
验证 Secret 是否创建成功:
kubectl describe secret dnspod-secret -n cert-manager
5. 创建 ClusterIssuer
编写 issuer.yaml 文件,注意使用 secretIdRef/secretKeyRef 格式(这是 webhook 要求的正确格式,不同于某些文档中的 secretIdSecretRef):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
email: 1164442003@qq.com # 你的真实邮箱
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- dns01:
webhook:
groupName: acme.dnspod.com
solverName: dnspod
config:
secretIdRef:
name: dnspod-secret
key: secretId
secretKeyRef:
name: dnspod-secret
key: secretKey
应用配置:
kubectl apply -f issuer.yaml
6. 申请通配符证书(带跨命名空间同步注解)
创建 mqtt-cert.yaml,关键点在于 secretTemplate 中必须包含以下三个 Reflector 注解,否则证书续签后无法自动同步到 emqx 命名空间:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: mqtt-tls
namespace: cert-manager
spec:
secretName: mqtt-tls-secret
secretTemplate:
annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "emqx"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
privateKey:
algorithm: ECDSA # 指定算法为 ECDSA
size: 256 # 使用 P-256 曲线 (256位)
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "mqtt.conststar.com"
应用并监控状态:
kubectl apply -f mqtt-cert.yaml
kubectl get certificate -n cert-manager -w
等待几分钟,READY 列变为 True 即表示证书签发成功。
同理要申请其他证书,也就是再添加一个 xxx-cert.yaml,例如iconfig:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: iconfig-tls
namespace: cert-manager
spec:
secretName: iconfig-tls-secret
secretTemplate:
annotations:
# 必须:允许该 Secret 被 Reflector 管理
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
# 必须:指定允许同步到的目标命名空间(多个用逗号分隔)
reflector.v1.k8s.emberstack.com/reflection-allowed-namespaces: "emqx,nginx"
# 必须:开启自动同步开关
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "mqtt.conststar.com" # 替换为你的真实域名
7. 安装 Reflector 实现跨命名空间自动同步
Reflector 是一个专门用于同步 Kubernetes 资源的控制器,它会根据注解自动将 Secret(或 ConfigMap)同步到指定的命名空间。
7.1 安装 Reflector
推荐使用 Helm 安装(可自定义日志级别):
helm upgrade --install reflector oci://ghcr.io/emberstack/helm-charts/reflector -n kube-system
7.2 验证 Reflector 运行状态
kubectl get pods -n kube-system -l app.kubernetes.io/name=reflector
7.3 验证自动同步
证书签发成功后,Reflector 会自动将 cert-manager 命名空间中的 mqtt-tls-secret 同步到 emqx 命名空间:
kubectl get secret mqtt-tls-secret -n emqx
8. EMQX中使用证书
8.1 挂载证书
证书已同步到 emqx 命名空间,现在修改 EMQX StatefulSet 挂载该 Secret,并配置 SSL 监听器。
# 编辑 EMQX StatefulSet
kubectl edit statefulset emqx -n emqx
# 添加以下内容
spec:
template:
spec:
volumes:
- name: tls-certs
secret:
secretName: mqtt-tls-secret # 使用同步后的 Secret
containers:
- name: emqx
volumeMounts:
- name: tls-certs
mountPath: /opt/emqx/certs # EMQX 默认证书路径
readOnly: true
保存退出后,StatefulSet 会自动滚动更新 Pod。
8.2 设置证书路径
在EMQX Dashboard的监听器中设置ssl、wss的证书路径。
{
ssl_options {
certfile = "/opt/emqx/certs/tls.crt"
keyfile = "/opt/emqx/certs/tls.key"
}
}
9. 验证 EMQX SSL 监听器
进入任意 EMQX Pod 查看监听器状态:
kubectl exec -it emqx-0 -n emqx -- emqx_ctl listeners | grep ssl
如果 reflector 未自动同步,手动复制 Secret 到 emqx 命名空间:
kubectl get secret mqtt-tls-secret -n cert-manager -o yaml | sed 's/namespace: cert-manager/namespace: emqx/' | kubectl apply -f -