ConstStar
发布于 2026-03-25 / 4 阅读 / 0 评论 / 0 点赞

Kubernetes 上为 EMQX 配置 Let's Encrypt 证书(DNSPod DNS-01)

本文档基于实战经验,详细记录了在 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 的权限(至少 CreateRecordDescribeRecordListDeleteRecord
  • (可选)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 -

评论