Kubernetes多环境并行部署时cert-manager无法获取Let's Encrypt证书
问题背景
我编写了bash脚本,结合helm和kubectl在Kubernetes集群中自动化部署应用,通过cert-manager自动化管理应用所需的、由Let's Encrypt签发的TLS证书的申请与续期。
该脚本支持将应用部署到测试(test)、生产(prod)等不同环境,每个环境对应独立命名空间:
- 生产环境使用Let's Encrypt正式ACME服务器,测试环境使用预发布服务器
- 不同环境请求证书的主机名不同,所有环境使用同一联系邮箱
测试环境Issuer配置
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-staging spec: acme: email: operations@mysite.tld server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-staging-issuer-private-key solvers: - http01: ingress: class: public-test-it-it
生产环境Issuer配置
apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: letsencrypt-production spec: acme: email: operations@mysite.tld server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: letsencrypt-production-issuer-private-key solvers: - http01: ingress: class: public-prod-it-it
问题现象
首次部署单个环境时一切正常,cert-manager成功获取证书。但并行部署另一环境后,CertificateRequest->Order->Challenge流程在Challenge环节停滞,报错如下:
kubectl describe challenge xyz-tls-certificate ... Status: Presented: true Processing: true Reason: Waiting for HTTP-01 challenge propagation: wrong status code '404', expected '200' State: pending Events: <none>
curl测试外部挑战URL返回404,导致Let's Encrypt无法签发证书。调试发现集群内可正常访问挑战资源,但外部无法访问,疑似HAProxytech/kubernetes-ingress控制器问题。查看cert-manager日志:
kubectl logs -n cert-manager cert-manager-... I0721 13:27:45.517637 1 ingress.go:99] cert-manager/challenges/http01/selfCheck/http01/ensureIngress "msg"="found one existing HTTP01 solver ingress" "dnsName"="xyz.test.mysite.tld" "related_resource_kind"="Ingress" "related_resource_name"="cm-acme-http-solver-8668s" "related_resource_namespace"="app-test-it-it" "related_resource_version"="v1" "resource_kind"="Challenge" "resource_name"="xyz-tls-certificate-hwvjf-2516368856-1193545890" "resource_namespace"="app-test-it-it" "resource_version"="v1" "type"="HTTP-01" E0721 13:27:45.527238 1 sync.go:186] cert-manager/challenges "msg"="propagation check failed" "error"="wrong status code '404', expected '200'" "dnsName"="xyz.test.mysite.tld" "resource_kind"="Challenge" "resource_name"="xyz-tls-certificate-hwvjf-2516368856-1193545890" "resource_namespace"="app-test-it-it" "resource_version"="v1" "type"="HTTP-01"
已确认首次部署后相关资源已删除,无重复冲突。
问题原因分析
1. HAProxy Ingress控制器并发同步延迟
并行部署时,cert-manager会为两个环境同时创建临时HTTP-01挑战Ingress。如果HAProxy控制器的同步周期较长,或者集群资源负载较高,控制器可能无法及时同步所有Ingress规则,导致外部请求无法匹配到新的挑战路径,返回404。
2. Ingress类与控制器绑定冲突
检查public-test-it-it和public-prod-it-it两个IngressClass是否正确绑定到对应的HAProxy实例。如果两个IngressClass指向同一HAProxy控制器,可能存在规则优先级冲突或资源竞争,导致其中一个环境的挑战Ingress规则未被正确加载。
3. HAProxy路径匹配优先级问题
如果已有环境的Ingress规则中包含宽泛的路径匹配(比如/*),这类规则的优先级可能高于挑战路径/.well-known/acme-challenge/xxx,导致外部请求被已有规则拦截,返回404。
4. DNS解析延迟(低概率)
虽然不同环境域名不同,但如果并行部署时新域名的DNS解析尚未完全生效,Let's Encrypt的验证服务器可能无法正确解析到集群入口,导致挑战请求失败。不过从集群内访问正常的现象来看,这个可能性较低。
验证与解决建议
- 检查Ingress同步状态:执行
kubectl get ingress -A查看两个环境的挑战Ingress是否都处于READY状态;查看HAProxy控制器日志,排查是否有Ingress同步失败的报错。 - 调整控制器同步参数:缩短HAProxy控制器的
--sync-period参数值(默认30s),或者增加控制器的CPU/内存配额,提升并发处理能力。 - 确认IngressClass绑定:验证
public-test-it-it和public-prod-it-it分别绑定到独立的HAProxy实例,避免规则冲突。 - 强制刷新HAProxy配置:重启HAProxy控制器Pod,手动触发配置重新加载,验证是否能加载新的挑战Ingress规则。
- 调整路径匹配优先级:确保挑战路径
/.well-known/acme-challenge/使用pathType: Exact,或者调整Ingress规则顺序,让挑战路径规则优先匹配。
内容的提问来源于stack exchange,提问作者salai

