Gateway 开门,VirtualService 修路
一句话总结
Gateway 只决定以什么端口、host 和 TLS 接收流量,接收后的路由全部由 VirtualService 完成。二者通过 VirtualService 的 gateways 字段连接。
为什么需要它
Kubernetes Ingress 把入口与路由混在一个资源中,表达能力有限。基于 header 的路由、权重分配、TLS passthrough 等需求都落入控制器专用 annotation,最终 manifest 被绑定到特定 Ingress 控制器。
Istio 通过职责分离解决:Gateway 声明 gateway Pod 的 listener,路由则复用 mesh 内部的 VirtualService。因此,内部 east-west 路由与外部进入的 north-south 路由可以使用同一语法。
工作原理
Gateway 通过 spec.selector 选择把配置附加到哪个 gateway Pod,通常是 istio: ingressgateway。Gateway 资源不会创建 proxy,只为已有 Gateway Deployment 添加 listener 配置。
必须区分三种 TLS 模式。
| 模式 | Gateway 的工作 | 所需内容 |
|---|---|---|
| SIMPLE | 终止 TLS,以明文向后转发 | 服务器证书(credentialName) |
| MUTUAL | 终止 TLS,并验证客户端证书 | 服务器证书 + CA |
| PASSTHROUGH | 不终止 TLS,只按 SNI 转发 | 无需证书 |
PASSTHROUGH 的协议不能写成 HTTPS,必须写成 TLS,因为 Gateway 不解析 HTTP;因此路由也不用 HTTP 规则,而使用 tls 块的 sniHosts。credentialName 指向的 kubernetes.io/tls Secret 必须位于Gateway Pod 所在 namespace。把它放在应用 namespace,再疑惑为何未挂载,是常见事故。
绑定必须同时满足两个条件:VirtualService 的 gateways 中包含 Gateway 名称,且其 hosts 与 Gateway 的 server hosts 有交集。若同一规则也应用于 mesh 内流量,应在 gateways 中加入保留字 mesh。
ServiceEntry 方向相反,它把mesh 外部服务带入 mesh。注册后,外部 API 也能应用 timeout、retry、mirroring 和 metrics。resolution 分为 STATIC(使用 endpoints 中 IP)、DNS(解析名称)、NONE(使用原请求地址)。若全局启用 outboundTrafficPolicy: REGISTRY_ONLY,不在 ServiceEntry 中的外部 host 会被阻止。
Sidecar 资源用途不同。默认所有 sidecar 都接收 mesh 中全部服务配置;服务数千时,仅配置就可能让 Envoy 内存膨胀数百 MiB。用 Sidecar 缩小 egress.hosts 后,只向 workload 下发其需要的范围。格式为 네임스페이스/호스트;./* 表示自身 namespace,istio-system/* 表示控制平面 namespace。
还要了解发展方向:新 Ingress 推荐使用 Kubernetes Gateway API(Gateway + HTTPRoute);ambient 模式的 waypoint proxy 本身也用 Gateway API 的 Gateway 资源声明。Istio 专用 Gateway/VirtualService 会继续支持,但新标准功能会优先进入 Gateway API。
现场会遇到的情况
作者家庭实验室部署 Cilium Gateway API 时曾遇阻。安装 Gateway API CRD v1.2 后,控制器拒绝启动,原因是 tlsroutes 与 referencegrants 尚非 v1。升级 CRD 到 v1.6.1 后才正常。
同样的教训适用于 Istio:Gateway API 是独立项目,必须先在集群安装 CRD,且实现(Istio、Cilium)要与 CRD 版本匹配。“已执行 istioctl install,为何不能创建 HTTPRoute?”答案就在这里。同一实验室中 hubble-relay 与 hubble-ui 曾保持 Pending,也是类似问题:它们是 Deployment 而非 DaemonSet,不能容忍控制平面 taint;worker 加入后立即恢复。Gateway Deployment 也常因同一原因无法调度。
下一实验要做什么
实际创建 backend workload 与 kubernetes.io/tls Secret,再把 SIMPLE 和 PASSTHROUGH server 放进同一 Gateway,用 VirtualService 绑定;随后把外部支付 API 注册为 ServiceEntry,并用 Sidecar 把该 workload 的视野缩小到三个项目。