第29章 Service Mesh 数据面:Envoy Sidecar 全链路

学习目标

  • 把前面所有要素串成一条线:sidecar 劫持 + Envoy + mTLS + xDS + L7 = Mesh 数据面
  • 走通一次服务间调用穿过两个 Envoy 的完整链路
  • 理解控制面如何用 xDS 把 VirtualService/DestinationRule 下发成数据面配置
  • 厘清 Service Mesh 与 API 网关的分工与融合

前置知识


原理

Mesh 数据面 = 你已学的一切的组合

Service Mesh 听起来高深,但从本书视角看,它的数据面就是把前面的代理技术组合起来:

  Service Mesh 数据面 = 每 Pod 一个 Envoy(第15章)
                      + 透明流量劫持(第26章 iptables / 第11章)
                      + 自动 mTLS(第05章)
                      + xDS 动态配置(第15章)
                      + L7 路由/重试/熔断(第10章)

一句话:Mesh 数据面 = 被控制面编排的、每 Pod 一个的 L7 反向代理网格。它治理的是东西流量(服务间,第27章 的对照)。

一次服务间调用的完整链路

服务 A 调用服务 B,请求穿过两个 Envoy,全程业务无感:

  ┌─ A Pod ─────────┐                      ┌─ B Pod ─────────┐
  │ A-app           │                      │           B-app │
  │   │①出站         │                      │         ⑥入站│   │
  │   ▼ iptables     │                      │      iptables▲   │
  │ A-Envoy:15001    │                      │   B-Envoy:15006  │
  └───┬──────────────┘                      └──────────────▲──┘
      │②选路由(RDS) ③负载均衡选B实例(EDS)         ⑤mTLS解密+鉴权│
      │④mTLS加密(SDS证书)                                      │
      └──────────────── 加密隧道 ──────────────────────────────┘

  ① A-app 发出请求 → 被 iptables 劫持到 A-Envoy:15001(出站,第26章)
  ② A-Envoy 按路由规则(VirtualService→RDS)决定去哪个服务
  ③ 按负载均衡从 B 的实例列表(EDS)选一个,应用熔断/重试/超时
  ④ 用 SDS 下发的证书与 B 建 mTLS(第05章)
  ⑤ B-Envoy:15006 收到,mTLS 解密 + 鉴权(AuthorizationPolicy)
  ⑥ 转发给 B-app。回程对称。全程 A-app/B-app 无感

每一跳的能力都是前面学过的:路由(第10章)、负载均衡(第09章)、mTLS(第05章)、Envoy filter(第15章)。

控制面如何驱动数据面(xDS 落地)

数据面 Envoy 本身不"懂"业务规则,全靠控制面(Istiod)翻译 + 下发:

  你写的高层 CRD          控制面 Istiod 翻译       下发给数据面 Envoy(xDS,第15章)
  ──────────────         ─────────────────       ────────────────────────────
  VirtualService    ──▶  路由规则            ──▶  RDS(Route)
  DestinationRule   ──▶  负载均衡/熔断/子集   ──▶  CDS(Cluster)
  Service/Endpoints ──▶  实例列表            ──▶  EDS(Endpoint)
  PeerAuthentication──▶  mTLS 策略 + 证书     ──▶  SDS(Secret)+ Listener
  Gateway           ──▶  入口监听器          ──▶  LDS(Listener)

这就是 第24章 的"数据面 vs 控制面"分工的终极体现:Envoy(C++) 跑数据,Istiod(Go) 算配置。你改一个 VirtualService,Istiod 算出新路由,xDS 秒级推给所有相关 Envoy,无 reload、无重启。

Mesh 提供的能力总表

维度Mesh 数据面能力来自本书
安全自动 mTLS、零信任、AuthorizationPolicy第05章
流量管理灰度/金丝雀、流量镜像、故障注入、超时重试熔断第10章、第15章
可观测黄金指标、分布式追踪、访问日志(每请求)第10章
弹性负载均衡、连接池、异常剔除第09章

代价与演进

  • 代价:每 Pod 一个 sidecar 的资源/延迟开销、整体复杂度、调试难度(第26章)
  • 演进:Ambient Mesh(ztunnel + waypoint)去 sidecar 化、eBPF 加速数据面(第11章、第12章)

Mesh 与 API 网关:分工与融合

API 网关(apiGateway 手册)Service Mesh
流量南北(外→内,第27章)东西(服务间)
形态集中式入口分布式 sidecar
关注认证、限流、API 管理服务间 mTLS、路由、可观测

两者正在融合:Gateway API(第27章)成为统一入口标准,Istio 既做 mesh 又做 ingress gateway。详细的治理视角(Istio 组件、灰度、熔断)见 apiGateway · 服务网格,本书聚焦"数据面=代理"这一面。


️ 实现 / 命令

实验一:观察请求穿过两个 Envoy

# 看 A 的 sidecar 访问日志,能看到出站记录
kubectl logs <a-pod> -c istio-proxy | tail
# [out] "GET /api HTTP/1.1" 200 ... → b-svc.default.svc.cluster.local
# 看 B 的 sidecar,能看到对应的入站记录 → 一次调用两条日志,证明穿过了两个 Envoy
kubectl logs <b-pod> -c istio-proxy | tail

实验二:VirtualService 灰度(控制面→数据面)

# 90% 流量到 v1,10% 到 v2(金丝雀,第10章按权重)
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata: { name: b-route }
spec:
  hosts: [b-svc]
  http:
  - route:
    - { destination: { host: b-svc, subset: v1 }, weight: 90 }
    - { destination: { host: b-svc, subset: v2 }, weight: 10 }
kubectl apply -f b-route.yaml
# 确认它被翻译成了数据面的路由配置(RDS)
istioctl proxy-config routes <a-pod> --name 80 -o json | grep -A3 weight
# 多次调用,约 1/10 命中 v2 —— 控制面规则秒级生效到数据面,无 reload

实验三:验证自动 mTLS

kubectl apply -f - <<'EOF'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata: { name: default, namespace: default }
spec: { mtls: { mode: STRICT } }
EOF
# 抓 Pod 间流量:明文消失,全是 TLS(第05章)
istioctl proxy-config secret <a-pod>     # 看 SDS 下发的证书
istioctl authn tls-check <a-pod> b-svc.default.svc.cluster.local

实验四:可观测(数据面自带指标)

# Envoy 暴露的黄金指标(无需改业务代码)
kubectl exec <a-pod> -c istio-proxy -- curl -s localhost:15000/stats | grep "upstream_rq_"
# upstream_rq_200 / upstream_rq_5xx / upstream_rq_time —— 请求数、错误、延迟全在数据面

排错

现象根因解决
调用一直 503 UH无健康 upstream / mTLS 不匹配查 proxy-config endpoints、mTLS 模式(第15章)
灰度规则不生效sidecar 没注入 / VS 没选中确认注入(第26章)、istioctl proxy-config routes
mTLS 报错一边 STRICT 一边明文统一 PeerAuthentication
配置改了不生效xDS 没同步istioctl proxy-status 看是否 SYNCED
延迟变高每跳两个 Envoy 开销评估 Ambient/资源调优
调试无从下手链路太长istioctl proxy-config、访问日志、Kiali

本章小结

  • Mesh 数据面 = 每 Pod 一个 Envoy + 透明劫持 + 自动 mTLS + xDS + L7——全是本书前面学过的技术组合。
  • 一次服务调用穿过两个 Envoy:出站选路由/负载均衡/加密 → 入站解密/鉴权 → 业务无感。
  • 控制面把 VirtualService/DestinationRule/PeerAuthentication 翻译成 RDS/CDS/SDS 下发数据面(数据面 vs 控制面分工)。
  • Mesh 治东西流量、网关治南北,正经 Gateway API 融合。

容器与 K8s 篇至此收官——你已把代理原理一路落到 Docker、Istio 劫持、Ingress、Egress、Mesh 数据面。最后一篇 第七篇·进阶 收尾全书:可编程代理、性能调优、排错决策树、代理安全。