cert-manager 自动签发 HTTPS 证书:配置与三个常见失败

手动申请证书、手动配置、到期前手动续期——这件事在只有一两个域名时还能忍,一旦有 beta 和 prod 两套环境就很容易忘。cert-manager 把整个流程变成了一段声明式配置。

集群里跑的是 cert-manager v1.21.2。

ClusterIssuer 与两个环境

Issuer 是命名空间级的,ClusterIssuer 是集群级的。因为 beta 和 prod 都要用,建了 ClusterIssuer。

关键是建两个:staging 和 prod。它们的区别不在安全性,而在速率限制

  • staging:Let’s Encrypt 的测试环境,签发频率限制很宽松,但证书不被浏览器信任(会报红色警告)。用来验证流程通不通。
  • prod:正式环境,证书被信任,但对”同一域名在一段时间内的签发次数”有严格限制(目前是每周 50 张)。

正确顺序是:先用 staging 把流程跑通,确认 HTTP-01 校验能通过,再切到 prod。反过来做的话,很容易因为配置错误反复重试,几小时内就把一周的额度用光,然后只能干等。

HTTP-01 校验为什么失败

cert-manager 会在你的站点上临时放一个校验文件,然后让 Let’s Encrypt 从公网访问 http://<你的域名>/.well-known/acme-challenge/<token> 来确认这个域名确实归你。

失败通常就三个原因:

  • 80 端口不通:云厂商安全组、服务器防火墙没放行。HTTP-01 只能用 80 端口,没有例外。
  • 被强制跳转 HTTPS:如果 Ingress 配了”所有 HTTP 请求 301 到 HTTPS”,校验请求会被跳走,Let’s Encrypt 拿不到文件内容。需要给 challenge 路径单独放行。
  • DNS 还没生效:域名解析没指向这台服务器,或者刚改过解析还在传播中。

排查命令固定三板斧:

kubectl get certificate -A
kubectl describe certificate &lt;name&gt; -n &lt;ns&gt;
kubectl get challenge -A      # 看 challenge 的状态和原因

describe certificate 输出的 Events 基本会直接告诉你卡在哪一步。

证书复用

同一台主机下的所有 Ingress 共用一张证书。我的 WordPress、/qrcode/tools 都在 www.mazter.cn 下,所以只有一张 wp-tls

新增子路径应用时不需要动证书配置,这一点在 Traefik 那篇里也提过——共用域名的隐性收益。

续期

Let’s Encrypt 证书有效期 90 天。cert-manager 会在到期前自动续期,默认是到期前 30 天开始尝试。你什么都不用做。

值得做的一件事是加个监控:证书状态不是 Ready 时能收到通知。它平时不出问题,但一旦出问题(比如 DNS 改了、80 端口被封),表现是”整站突然打不开”,而且往往在你最不想处理事情的时候发生。