云原生
服务网格详解:现代平台为何需要它
一份从实践者角度出发的指南,讲解服务网格究竟做什么、它如何为开发团队减负,以及代理架构如何实现这一切。
Todea Engineering
云原生实践
只要你在 Kubernetes 上跑的微服务稍多一些,你的开发者大概率已经重新发明了半个服务网格。每个 HTTP 客户端里都嵌着重试和超时逻辑;证书轮换靠一个 CronJob 加一段脚本勉强撑着;服务到服务的认证是用 bearer token 临时拼出来的;然后每个仓库里都散落着一堆库版本、语言习惯,以及"以后再改"的配置。
每个团队都把同样的问题以略微不同的方式解决一遍。服务网格把这些关注点从应用代码中抽出来,交给平台团队掌管的基础设施去处理。
开发者不该背负的职责
当你把一个单体拆成微服务时,原本在同一个进程里发生的一切 — 错误处理、重试、超时、认证、指标 — 也跟着被拆开。没有网格的话,每个团队都会把同样的模式再建一遍,通常是用自己语言的习惯写法,经常配错,也很少一致:
- 重试和超时逻辑出现在每一个 HTTP 客户端里,常常配错
- TLS 证书管理依靠在 header 里传来传去的共享 secret 撑着
- 服务到服务的认证靠 API token 临时拼出来
- 分布式追踪埋点一个端点一个端点地手动加上去
- 熔断器在服务间被复制,每份都有些微小差异
- 负载均衡和重试预算散落在应用代码各处
- 网络策略表现为没人敢动的 IP 白名单
把这些乘上每一个服务、每一种你在用的语言,以及维护它们的每一个团队。成本巨大,一致性很差,可靠性也跟着打折。
服务网格把这些关注点从开发者身上拿走:
开发者写业务逻辑。网格负责那些横切的管道工作。
工作原理:代理架构
所有服务网格都建立在同样的两个组件之上:
- 数据平面:拦截服务间流量每一个字节、处理 mTLS、并执行策略的网络代理。
- 控制平面:配置这些代理、签发工作负载身份、并聚合其遥测数据的控制器。
不同网格之间真正的差别,在于代理跑在哪里。目前有两种主流模型。
边车代理
在边车模型里,代理作为一个额外的容器跑在每一个应用 Pod 里面。Linkerd 默认就是这样,经典的 Istio 也是。Pod 启动时,iptables 规则(由 init 容器或者 CNI 插件安装)会把 Pod 的入站和出站 TCP 流量透明地重定向到边车里。
当服务 A 调用 b.default.svc.cluster.local 时,A 的应用容器只是对一个 Kubernetes Service 发起一次普通的 HTTP 请求。iptables 重定向会把它灌进 A 的边车,由边车来处理 mTLS、重试、超时和路由,然后再把请求转发给 B 的边车。B 的边车执行授权策略、记录指标,并通过 loopback 转发给 B。
无边车架构
主要玩家包括:
-
Istio ambient 模式以 DaemonSet 的形式每个节点跑一个 L4 隧道(
ztunnel),负责该节点上所有本地 Pod 的 mTLS。L7 能力(HTTP 路由、基于路径的授权等)则通过按命名空间部署可选的 waypoint 代理来附加。L7 的成本只在真正需要的地方付。 -
Cilium Service Mesh把 L4 mTLS 和策略下沉到 Linux 内核里的 eBPF,再按节点跑一个 Envoy 来处理 L7 相关的工作。
权衡也随之倒了过来:没有每个 Pod 的额外开销、Pod 启动更快、每个工作负载要运维的部件更少 — 但共享代理意味着同一节点上工作负载之间的租户隔离问题会开始互相渗透,而要调试某一个服务的流量,你就得去推理一个节点粒度的组件。
从应用的角度看,这两种模型看起来是一样的:应用只是对一个 Kubernetes Service 发起一次普通的 HTTP 调用。从运维的角度看,在不改动任何一行应用代码的前提下,这些流量里的每一个字节都被认证、加密、可观测,并可被策略治理。
在平台层面,你能得到什么
一套部署得当的服务网格,可以在不改任何应用的前提下,为你提供:
- 每一对服务之间的 mTLS:证书的签发、轮换和吊销由网格负责。应用团队的仓库里再也不用写 PKI 代码。
- 工作负载身份:基于密码学证书,而不是 IP 地址或共享 secret。这是零信任网络的基石。
- 流量管理:重试、超时、熔断、金丝雀发布 — 全部通过配置声明。
- 分布式追踪:每个请求都会被自动传播一个 trace ID。
- 一致的指标:请求速率、错误率、p50/p95/p99 时延 — 所有服务都有,不需要写任何埋点代码。
- 跨集群服务发现:集群 A 里的服务可以像调用近邻一样调用集群 B 里的服务。
常见陷阱
服务网格的落地,失败的方式通常相当可预测:
- 把它当成一个开关。 把安装当成终点。把网格跑起来是简单的部分。真正需要投入的是后面那些事 — 运维、轮换信任锚、在请求路径上调试代理问题、跟上升级节奏、随着集群规模变大不断调整资源限制。一开始就把预算算进去,否则网格就会变成束之高阁的软件。
- 按功能而不是按适配度来挑。 Istio、Linkerd、Consul 和 Cilium Service Mesh 的运维画像非常不同。如果你的团队只有三个人,功能列表最长的那个并不是你想要的 — 选一个你实际扛得下其运维面的。
- 跳过可观测性的工作。 服务网格会生产海量遥测数据。没有仪表盘和 SLO,这些数据就是没用的。