上篇文章我们介绍了 k8s 的 Gateway API,也介绍了k8s 的 GAMMA(Gateway API For Mesh Management and Administration)倡议,旨在将 Kubernetes Gateway API 扩展到服务网格领域。这篇文章我们将继续在 k8s 环境中实际部署 Istio 这个服务网格实现。
Istio 简介
在 GAMMA 出现之前,Kubernetes 的网络管理处于 割裂 状态:
- Gateway API (南北向): 主要负责集群外部流量进入集群(Ingress 的继任者)。
- Service Mesh (东西向): 主要负责集群内部服务之间的通信、治理、加密(如 Istio, Linkerd)
每个服务网格实现都有自己的私有 API(比如 Istio 的 VirtualService),这导致了用户在切换网格工具时面临巨大的迁移成本。GAMMA 的目标就是标准化服务网格的配置,让东西向流量也使用 Gateway API。GAMMA 并不是要取代服务网格,而是为服务网格提供一套通用的控制面标准,它使用标准的 Gateway API 资源(如 HTTPRoute)来管理服务网格内的东西向流量(服务间通信)。
Istio 是目前功能最全、生态最丰富的服务网格实现。它采用了典型的控制面(Control Plane)与数据面(Data Plane)分离的架构。
- 数据面 (Envoy Proxy): Istio 默认在每个服务 Pod 中注入一个 Envoy 代理作为 Sidecar。所有的进出流量都会被 Envoy 劫持。Envoy 负责实际的负载均衡、熔断、限流和指标收集
- 控制面 (Istiod): 负责策略下发。它将你写的 YAML 配置(如 VirtualService)转换成 Envoy 能够理解的配置,并通过 xDS 协议推送到各个 Sidecar
Istio 提供了以下核心功能:
- 流量管理 (Traffic Management):
- 动态路由: 可以实现非常精细的流量切分,轻松实现金丝雀发布或蓝绿部署
- 弹性能力: 内置了重试(Retry)、超时(Timeout)、熔断(Circuit Breaker)和限流功能,这些逻辑在网格层实现,不需要在业务代码中实现
- 安全 (Security)
- mTLS (双向 TLS): 自动为服务间的通信进行加密和身份验证
- 策略控制: 可以定义
只有 Service A 能访问 Service B 的 /admin 接口这种细粒度的授权规则
- 可观测性 (Observability):
- 网格可视化: 配合 Kiali 等工具,可以自动绘出服务间的调用关系图。
- 分布式追踪: 自动注入 Trace ID,通过 Jaeger 查看请求在微服务间的流转耗时
- 策略执行: 支持配额管理和黑白名单
Istio 目前存在两种模式:Sidecar 模式 和 Ambient 模式。
对于 Sidecar 模式:
- 在 Sidecar 模式下,Istio 在每个业务 Pod 中注入一个 Envoy 代理容器。
- 所有的进出流量都必须通过 iptables 强制劫持到这个 Envoy 代理中
- 流量在到达业务代码前,在同一个 Pod 内完成 L4(传输层)加密和 L7(应用层)路由。
- 代理和业务强绑定生命周期
对于 Ambient 模式:
- 不再将代理塞进 Pod 内部,而是将功能拆分为两个独立层级
- L4 层级:Ztunnel (Secure Overlay):
- 每个节点(Node)部署一个共享的 ztunnel
- 只负责 L4 流量的零信任加密(mTLS)、节点流量透明拦截、HBONE 隧道等
- L7 层级:Waypoint Proxy
- 可选的 Envoy 实例,按需开启
- 处理复杂的 L7 逻辑,如重试、限流、熔断、基于路径的路由等
- 业务 Pod 纯业务、无任何代理容器、无需重启注入
Ambient 模式是一种全新改进的模型,旨在弥补 Sidecar 模式的不足。Istio 社区的大部分精力都投入到了 Ambient 模式的改进上, 尽管 Sidecar 模式仍然得到全面支持。一般来说,建议新用户从 Ambient 模式开始。它速度更快、 成本更低,而且更易于管理。
Istio 部署
Istio 安装
接下来我们来实际安装 Istio,首先通过如下命令下载安装 Istio release:
1 | # curl -L https://istio.io/downloadIstio | sh - |
- release 包默认直接存放在当前目录下,因此需要设置 PATH 环境变量
1 | # cd istio-1.29.2/ |
- 运行安装前检查:
istioctl x precheck,检查集群是否满足 Istio 安装要求,包括:Kubernetes 版本、资源配额、网络配置等
1 | # istioctl x precheck |
- 安装 Istio:
1 | # istioctl install --set profile=default -y |
| 组件 | 说明 |
|---|---|
| Istiod | Istio 控制面,负责配置下发(xDS)、证书管理等 |
| istio-ingressgateway | Istio 入口网关,处理南北向流量 |
| Sidecar Proxy | 数据面代理(Envoy),注入到每个 Pod |
- 检查安装状态
1 | # kubectl get pods -n istio-system |
- 如果 k8s 环境中还没有安装 Gateway API CRD,还需要手动安装。我的环境之前测试 Envoy Gateway 时已经安装过了,这里就不用手动安装
1 | kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \ |
启用 Sidecar 自动注入
为命名空间添加标签,启用自动注入
1 | # kubectl label namespace default istio-injection=enabled --overwrite |
这条命令的核心作用是监视 default 命名空间,并在部署新应用时,自动把 Sidecar 代理(Envoy)塞进去:
kubectl label: 这是 Kubernetes 的标准命令,用于给资源添加或修改标签(Label)namespace default: 指定操作的对象类型是namespace(命名空间),对象名称是defaultistio-injection=enabled: 这是关键的键值对istio-injection是 Istio 控制面(istiod)预设的一个特殊 Keyenabled表示开启自动注入
--overwrite:如果该键值对已经存在,则覆盖原有值;如果不存在,则新增该键值对。这样可以确保默认命名空间总是开启自动注入
这样当你执行 kubectl apply -f deployment.yaml 部署新应用时:
- API Server 发现命名空间有
istio-injection=enabled标签,API Server 就会把 Pod 的定义发给 Istiod - Istiod 在 Pod 的容器列表中插入一个新的
istio-proxy容器(即 Sidecar),并配置好 iptables 初始化容器。 - API Server 接收修改后的 Pod 定义,最后由 Kubelet 启动这个
双容器Pod
检查命名空间标签是否设置成功:
1 | # kubectl get ns default --show-labels |
应用测试
部署测试应用
接下来创建如下配置文件 manifests/gamma/echo-services-mesh.yaml,用于配置测试应用:
1 | apiVersion: apps/v1 |
服务说明:
| 服务 | 说明 | 返回内容 |
|---|---|---|
| sleep | 客户端服务,用于发起测试请求 | - |
| backend-v1 | 后端服务 v1 版本 | backend-v1 |
| backend-v2 | 后端服务 v2 版本 | backend-v2 |
| backend-alt | 备用后端服务 | backend-alt |
应用配置文件:
1 | kubectl apply -f manifests/gamma/echo-services-mesh.yaml |
等待 Pod 就绪:
1 | kubectl wait --timeout=90s --for=condition=Ready pods -l app=sleep |
查看 Pod 状态:
1 | kubectl get pods -o wide |
输出:
1 | NAME READY STATUS RESTARTS AGE IP NODE |
这里尤其需要注意:
READY 2/2: 表示 Pod 中有 2 个容器(应用容器 + Istio Sidecar)- Sidecar 已成功注入到所有 Pod
验证基础连通性:
1 | # kubectl exec deploy/sleep -- curl -s backend-v1:80/ |
场景 1:基础 Mesh HTTPRoute 测试
接下来测试使用 HTTPRoute 将流量从 backend-v1 重定向到 backend-alt:
创建 manifests/gamma/httproute-mesh-basic.yaml 配置文件
1 | apiVersion: gateway.networking.k8s.io/v1 |
-
parentRefs: GAMMA 的核心概念
- 传统 Gateway API: parentRefs 指向 Gateway(南北向流量)
- GAMMA: parentRefs 指向 Service(东西向流量)
- Istio 监听 Service parentRefs 的 HTTPRoute,并在 Sidecar 中配置路由
-
hostnames: 匹配目标服务的 DNS 名称
- 格式:
{service}.{namespace}.svc.cluster.local
- 格式:
-
backendRefs: 实际处理请求的后端服务
应用 HTTPRoute:
1 | kubectl apply -f manifests/gamma/httproute-mesh-basic.yaml |
查看 HTTPRoute 详情:
1 | # kubectl get httproute mesh-route-basic -o yaml |
接下来测试路由:
1 | # kubectl exec deploy/sleep -- curl -s backend-v1:80/ |
可以看到,通过 HTTPRoute 成功将集群内发往 backend-v1 的流量重定向到 backend-alt。
场景 2:服务间流量分割测试
接下来测试使用 HTTPRoute 实现服务间流量按权重分配(金丝雀发布场景)。
使用如下配置文件 manifests/gamma/backend-service.yaml 创建父 Service:
1 | apiVersion: v1 |
使用如下配置文件 manifests/gamma/httproute-mesh-split.yaml 来通过 HTTPRoute 实现流量分割:
1 | apiVersion: gateway.networking.k8s.io/v1 |
概念说明:
-
weight: 流量权重比例
- 权重是相对值,实际比例为
weight/(总weight) - 80:20 表示 80% 流量到 backend-v1,20% 到 backend-v2
- 权重是相对值,实际比例为
-
流量分割应用场景:
- 金丝雀发布:新版本先接收少量流量验证
- A/B 测试:不同版本接收不同流量比例
- 蓝绿部署:快速切换流量比例
应用这两个配置:
1 | kubectl apply -f manifests/gamma/backend-service.yaml |
同样可以通过如下命令查看路由状态:
1 | kubectl get httproute mesh-route-split -o yaml |
接下来实际测试,判断流量是否按预期分配:
1 | # for i in {1..20}; do kubectl exec deploy/sleep -- curl -s backend:80/; done | sort | uniq -c |
场景 3:Header 匹配路由测试
接下来测试基于 HTTP Header 的路由匹配(版本选择场景)。首先同样创建创建一个父 Service,配置文件 manifests/gamma/backend-header-service.yaml 如下:
1 | apiVersion: v1 |
创建如下基于 Header 的 HTTPRoute 配置文件 manifests/gamma/httproute-mesh-header.yaml:
1 | apiVersion: gateway.networking.k8s.io/v1 |
-
headers 匹配: 基于 HTTP Header 进行路由
type: Exact: Header 值精确匹配type: RegularExpression: Header 值正则匹配
-
匹配逻辑:
- 规则 1: 带有
x-version: v2header → 路由到 backend-v2 - 规则 2 (默认): 无匹配 header → 路由到 backend-v1
- 规则 1: 带有
-
应用场景:
- 内部测试:开发人员带特定 header 访问新版本
- 灰度发布:特定用户群体访问新版本
- 多租户:不同 header 路由到不同租户服务
应用配置:
1 | kubectl apply -f manifests/gamma/backend-header-service.yaml |
实际测试路由:
1 | # kubectl exec deploy/sleep -- curl -s backend-header:80/ |
可以看到基于 Header 的路由匹配成功。
流程总结
通过上面的几个测试场景,我们展示了如何基于 Istio 来实现 k8s 的 GAMMA,直接通过 Gateway API 定义路由规则,从而实现服务间流量管理。下图概要展示了流程总结:
1 | ┌─────────────────────────────────────────────────────────────────────────────┐ |
- GAMMA 实现采用 Service 作为 parentRefs
- Istiod 监听所有 HTTPRoute,过滤出 parentRefs.kind=Service 的路由
- 对于每个 Service parentRefs,Istiod 在 Envoy 中配置拦截该 Service 的流量
- 流量被拦截后,根据 HTTPRoute 规则进行路由决策
- 最终转发到 backendRefs 指定的服务
另外我们可以通过 istioctl proxy-status 命令来查看 Sidecar 的配置状态。
小结
这篇文章我们通过部署 Istio 来实际测试了 k8s 的 GAMMA 功能,并通过 Gateway API 来定义 HTTPRoute 实现集群内服务间流量(东西相流量)管理,以进一步加深对 k8s Gateway API 的理解。