入站与出站先分清
本项目同时出现两个“Gateway”:
- Shared Envoy Gateway:管理外部请求如何进入 CPA;
- Shared Mihomo Gateway:管理 CPA 的请求如何通过代理出去。
名字相似,方向相反:
| |
本文只讲入站的 Gateway API。
为什么不为每个 Pool 创建 LoadBalancer
如果每个号池都创建一个 LoadBalancer Service,会带来:
- 每个 Pool 一份云负载均衡成本;
- 大量公网 IP;
- DNS 和证书分散;
- 暴露 cpa-manager 的误配置风险;
- 入口策略难以统一审计。
项目选择共享入口:集群只维护 Shared Envoy Gateway,各 Pool 通过自己的 hostname 和 HTTPRoute 绑定到它。
| |
这叫“共享基础设施、租户自带路由”。
Gateway API 的三个核心对象
GatewayClass:谁来实现 Gateway
项目声明:
| |
GatewayClass 是 cluster-scoped,类似 StorageClass:它说明哪种 controller 负责实现 Gateway。
仓库不会安装 Envoy Gateway controller。若集群中没有对应 controller,GatewayClass 和 Gateway 即使能创建,也不会真正产生可工作的入口。
Gateway:共享入口与 listener
项目在 subpool-gateway Namespace 创建 subpool-edge:
| |
Gateway 描述一个基础设施入口,listener 描述它监听的协议、端口和允许哪些 Route 绑定。
当前仓库 listener 是 HTTP 80。README 提到生产需要通配 DNS/TLS,但当前 manifest 没有直接配置 HTTPS listener 和证书,因此生产 TLS 仍属于必须补齐并验证的环境能力,不能因为有 Gateway 对象就假定 HTTPS 已完成。
HTTPRoute:某个 hostname 去哪个后端
当 SubPool 使用 Gateway 模式时,Operator 在 Pool Namespace 创建名为 cpa 的 HTTPRoute:
| |
HTTPRoute 属于租户 Namespace,Gateway 属于共享基础设施 Namespace。二者通过 parent reference 建立关系。
跨 Namespace Route 如何获得准入
Gateway listener 配置:
| |
只有带 managed label 的 Namespace,其 HTTPRoute 才能绑定这个 listener。
这些 label 由 Operator 在创建 SubPool Namespace 时添加。因此任意普通 Namespace 不能随便提交一个 Route 劫持共享入口域名。
这体现了 Gateway API 的角色分工:
- 基础设施管理员管理 Gateway 和 listener 策略;
- 应用或 Operator 管理自己 Namespace 中的 HTTPRoute;
- Gateway status 明确告诉双方 Route 是否被接受。
完整数据路径
Gateway 模式下,外部请求大致经过:
| |
任何一段缺失,外部访问都可能失败。Gateway API 不负责自动购买域名,也不保证云安全组、LoadBalancer、DNS 和证书已经正确配置。
Operator 如何判断 ExposureReady
Gateway 模式下,Operator 分两步检查。
先检查 HTTPRoute status 中目标 parent:
- parent name 必须是配置指定的 Gateway;
- parent Namespace 必须匹配;
- sectionName 必须匹配
httplistener; Accepted=True;ResolvedRefs=True。
再检查 Shared Gateway:
Programmed=True。
只有这些条件同时成立,ExposureReady=True。
Accepted 表示 Gateway controller 接受该 Route;ResolvedRefs 表示后端等引用能成功解析;Programmed 表示 Gateway 配置已经下发到数据面。它们比“对象存在”提供了更强证据。
四个常见 reason
| Reason | 含义 | 优先检查 |
|---|---|---|
RouteMissing | Operator 尚未看到 HTTPRoute | reconcile、权限、受管资源冲突 |
RouteNotAccepted | Route 未被目标 listener 接受 | allowedRoutes、parentRef、backendRef status |
GatewayMissing | 配置指定的共享 Gateway 不存在 | deploy/gateway 是否安装、名称与 Namespace |
GatewayNotProgrammed | Gateway controller 尚未准备好数据面 | Envoy Gateway controller、Gateway status 和 Event |
排查命令:
| |
重点看 status.parents[].conditions 与 status.conditions,而不只是 spec。
Internal 切换到 Gateway 会发生什么
修改 spec.exposure.mode 为 Gateway 后,Operator 会创建 HTTPRoute,并在 status 中写入派生 hostname。
从 Gateway 切回 Internal,Operator 会删除 HTTPRoute,但保留 CPA ClusterIP Service 和运行数据。
暂停 Pool 时也会删除 HTTPRoute并把 StatefulSet 缩容为 0,避免一个没有后端的公共路由继续挂在共享入口上。
cpa-manager 为什么没有 HTTPRoute
项目明确把 CPA 定义为 Pool Endpoint,cpa-manager 只是管理员看板。Manager 始终保持 ClusterIP,只通过受控 port-forward 使用。
这是一条安全边界:
| |
不能因为 Gateway 模式已经存在,就顺手给 Manager 再加一条 Route。那会扩大攻击面,并绕过项目既定的管理员访问控制。
DNS、TLS 与 Gateway 对象不是一回事
Gateway status 正常并不能自动证明:
<pool-id>.<baseDomain>已解析到入口 IP;- 通配符 DNS 已配置;
- HTTPS listener 已存在;
- TLS Secret 或证书 controller 正常;
- 云 LoadBalancer 可从互联网访问;
- 防火墙或安全组已开放。
这些属于 Cluster Bootstrap 和环境运维。Operator 只根据已有共享 Gateway 和 Route status 判断 Kubernetes 内部的入口前提。
Gateway API 相比旧式 Ingress 的思维变化
Ingress 常把基础设施与应用路由挤在同一种对象里,并大量依赖 controller-specific annotations。Gateway API 把职责拆成 GatewayClass、Gateway 和 Route:
| |
这种分层非常适合本项目:平台团队控制 Shared Envoy,SubPool Operator 只创建每 Pool 的 HTTPRoute。
安全的排障原则
如果 ExposureReady=False,应修复 Shared Gateway、listener、allowedRoutes、DNS 或 TLS,而不是:
- 把 CPA Service 改成 LoadBalancer;
- 给每个 Pool 新建公网 IP;
- 删除 managed Namespace selector;
- 直接暴露 cpa-manager;
- 放开 CPA 出站绕过 Mihomo。
绕过架构可能让一次临时排障变成长期安全债务。按照 DNS → Gateway → Route → Service → Endpoint → Pod 的顺序逐段验证,才能修复真正的断点。