
从各种需要手动复制证书的脚本,到如今清晰明了的架构设计,Kubernetes Gateway API 正引领一场变革,让跨命名空间复制 Secret 这种“土法炼钢”的操作彻底成为历史。
回想 2018 年,那时一篇介绍如何在 Kubernetes 中管理通配符证书的文章意外走红。原因无他,它戳中了当时运维的痛点:为了避免 Let‘s Encrypt 的速率限制,大家不得不在不同命名空间之间手动或借助脚本复制同一个 TLS Secret。
但在快速迭代的容器和 云原生 领域,七年时间足以让技术架构发生天翻地覆的变化。昔日的 v1alpha1 API 早已作古,Ingress 逐渐显现出局限性,而“将同一份私钥复制粘贴到几十个命名空间”的做法,如今看来更像是在为有缺陷的架构打补丁。
我们曾花费大量精力去制造工具,弥补设计上的不足,比如解决跨命名空间的 Secret 同步问题。然而,今天的最佳实践告诉我们:最高级的解决方案并非管理复杂性,而是从设计源头将其消除。Kubernetes Gateway API 正是这一理念的践行者,它提供了一套“零复制”的方案来优雅地处理 Wildcard TLS。
下面,就让我们一起看看在当下使用 Gateway API 管理通配符证书的正确姿势。
架构演进:从 Ingress 到 Gateway API 的范式转移
在传统的 Ingress 模式下,TLS 终止确实发生在 Ingress Controller 上,但配置却是割裂和碎片化的。如果 marketing 命名空间里有一个 Ingress 资源,那么与之关联的 TLS Secret 也必须存在于同一个 marketing 命名空间中。
这种设计迫使运维人员编写各种临时的“反射器”脚本,或者引入 kubernetes-replicator 这类工具,将那份宝贵的通配符证书克隆到集群的每一个角落。
Gateway API 的出现彻底改变了这一局面。它将 Listener(定义端口、协议和 TLS 配置)与 Route(定义应用路由逻辑)进行了清晰的职责分离。
在这种新架构下,运维团队可以在一个安全的集中式命名空间(例如 infra)中管理 Gateway 资源,通配符证书只需存放在这里,且仅存放在这里。而开发团队则可以在各自的应用命名空间里专注管理他们的 HTTPRoute,他们只需要将自己的路由“挂载”到中心化的 Gateway 上,完全无需接触或管理证书本身。
这种职责分离,是不是听起来就让运维和开发的协作清爽了许多?
第一步:集中化证书管理
我们依然可以借助 cert-manager 来自动化证书签发,但关键的不同在于:证书只签发一次,并且只存储在一个地方。
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-mycompany-com
namespace: infra # 证书将永久存放在此命名空间
spec:
secretName: wildcard-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
commonName: "*.mycompany.com"
dnsNames:
- "*.mycompany.com"
通过以上配置,名为 wildcard-secret 的 TLS Secret 将只存在于 infra 命名空间。从此,证书复制的烦恼烟消云散。
第二步:定义共享的 Gateway(统一的边缘入口)
Gateway 资源替代了传统的 Ingress Controller 概念。我们在这里定义一个 Gateway,指定其监听 HTTPS 443 端口,并引用上一步创建的 Secret。
核心配置点:通过 allowedRoutes 字段,我们可以控制哪些命名空间的路由可以附加到此 Gateway。下面的配置允许所有命名空间的路由进行绑定。
注意:以下示例中的 gatewayClassName 是针对 GKE Global Load Balancer 的。如果你使用的是 Regional LB 或其他云厂商的负载均衡器,请查阅相应文档进行调整。
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
namespace: infra
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: wildcard-secret # 引用 infra 命名空间中的 Secret
allowedRoutes:
namespaces:
from: All # <--- 实现“零复制”魔法的关键配置
在 GKE 集群中,你需要确保已启用 Gateway API:
gcloud container clusters update YOUR_CLUSTER_NAME --gateway-api=standard
第三步:应用部署(无需感知证书)
现在,假设 checkout 团队需要部署他们的应用。他们不再需要向运维索要证书副本,不需要配置任何证书复制器,只需要在自己的命名空间中定义一个 HTTPRoute 即可。
最佳实践提示:注意使用 sectionName 字段。它可以明确地将路由绑定到 Gateway 中特定的 https listener,避免未来 Gateway 增加其他监听器(如 HTTP 80 端口)时产生歧义。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: checkout-route
namespace: checkout # 应用位于独立的命名空间
spec:
parentRefs:
- name: shared-gateway
namespace: infra # 指向中心化的 Gateway
sectionName: https # 明确绑定到 TLS 监听器
hostnames:
- “checkout.mycompany.com”
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: checkout-service
port: 80
至此,开发与运维的边界变得清晰,安全策略的集中管控与应用部署的灵活性实现了完美统一。
生产环境检查清单:避开常见陷阱
上面的 YAML 配置可以让你的服务跑起来,但要想在生产环境中稳如磐石,还需要注意以下两个关键点。
1. DNS 配置:现实主义的必修课
在 Ingress 时代,每个 Ingress 可能会分配独立的 IP 地址。但在 Gateway 模式下,整个集群(或同一 Gateway)往往共享一个外部 IP 地址。
因此,你必须在你的 DNS 服务商(如 Cloud DNS、Route53)中,将通配符记录 *.mycompany.com 的 A 记录指向这个 Gateway 的公共 IP 地址。如果 DNS 记录没有正确指向,用户流量根本无法到达你的 Gateway,后续的所有路由规则都无从谈起。
专业建议:集成 ExternalDNS 并启用其 Gateway 数据源支持。它可以自动读取集群中所有 HTTPRoute 的 hostnames 字段,并动态更新云 DNS 记录,实现真正的声明式 DNS 管理。
2. 避开“502 Bad Gateway”陷阱
GKE 的 Gateway 负载均衡器对后端服务的健康检查非常严格。如果你的 checkout-service 在根路径 /(或者你为 readinessProbe 配置的路径)没有返回 200 OK 状态码,Gateway 会直接向客户端返回 502 错误。
解决方案:确保你的应用 Deployment 配置了正确且有效的 readinessProbe。
# 在你的 Deployment spec 中
readinessProbe:
httpGet:
path: /healthz # 确保此路径返回 200
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
忽视这一点,你可能不得不在深夜面对莫名的 502 错误而苦苦排查。
写在最后
2018年,我们依赖初版 API 和 Bash 循环来解决问题。到了今天,声明式架构和 Kubernetes Gateway API 为我们提供了更优雅、更根本的解决方案。
我们曾经不得不花费时间制造工具,去修补架构设计上的缺陷。但现在,我们意识到,比制造更强补丁更重要的,是构建一个更好的、无需补丁的架构。Gateway API 告诉我们,最高级的工程艺术,并非在于将复杂性管理得井井有条,而在于通过精妙的设计,让复杂性根本无从产生。
这种从“打补丁”到“重设计”的思路转变,正是技术进步带给我们的深刻启示,也值得每一位在 云栈社区 探讨实践的开发者深思。