要有效运用 Istio 管理复杂的微服务通信,理解其数据平面的流量捕获与路由机制是首要前提,而 Envoy Sidecar 在这一机制中扮演着核心角色。本文将详细阐述 Istio 数据平面的关键运作原理,重点分析网络流量在 Envoy 代理内部以及 Pod 之间的具体流转路径,并深入解析流量劫持这一关键技术的实现方式。掌握这些基础原理,是工程师深入理解并熟练应用 Istio 的基础。
一、Envoy Sidecar 是如何注入的
1. Istio 是如何实现注入的
Istio 或者其他类似需要进行 Pod 注入的业务,会通过 Kubernetes Mutating Admission Webhook 进行注入。 Kubernetes Webhook 的主要作用就是在 API Server 处理请求(比如创建、更新、删除资源)之前,截获这些请求,并根据配置进行检查 (Validate) 或修改 (Mutate)。这就像给 Kubernetes API Server 添加了定制化的处理流程。 整个流程大致是这样的:
- 你使用 kubectl apply -f your-pod.yaml 命令向 Kubernetes API Server 提交一个创建 Pod 的请求。
- Kubernetes API Server 在处理这个请求的过程中,会检查是否有配置好的 Mutating Admission Webhook 对 Pod 资源感兴趣。Istio 在安装时就注册了这样一个 Webhook。
- API Server 会将你的 Pod 定义发送给 Istio 的 Mutating Webhook 服务。
- Istio 的 Webhook 服务接收到请求后,会根据你的 Pod 定义(通常是检查 Pod 的 Label,比如
sidecar.istio.io/inject: "true"
) 来判断是否需要注入 Sidecar。 - 如果需要注入,Istio 的 Webhook 会修改你的 Pod 定义,向其中添加:
- Envoy Sidecar 容器
- 一个或多个 init 容器(用来设置 iptables 规则,劫持流量)
- 相关的 Volume(卷)和 VolumeMounts(卷挂载)
- 以及一些 Annotation(注解),供后续的 Istio 控制平面使用。
- Istio 的 Webhook 将这个修改后的 Pod 定义返回给 Kubernetes API Server。
- API Server 接收到修改后的定义后,会继续后续的流程(包括可能经过 Validating Webhook)并最终创建出包含 Envoy Sidecar 的 Pod。
2 Istio 注入后的 Pod 结构
原始 Pod yaml
apiVersion: v1
kind: Pod
metadata:
name: "testpod"
labels:
app: "testpod"
spec:
containers:
- name: testpod
image: nginx
注入后的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: testpod-simplified-istio-zh # Pod 名称
namespace: istio # 假设 Istio 在此命名空间或正在监视此命名空间
labels:
app: testpod # 您的应用程序标签
# 常见的 Istio 标签 (通常由 Istio 注入或用户设置)
security.istio.io/tlsMode: istio
service.istio.io/canonical-name: testpod
service.istio.io/canonical-revision: latest
annotations:
# 此注解通常用于指定注入的 Istio 修订版本
istio.io/rev: default
spec:
# serviceAccountName 对 Istio 的身份特性很重要
serviceAccountName: default
containers:
- name: testpod
image: nginx
# 2. Istio 代理边车容器
- name: istio-proxy
image: docker.io/istio/proxyv2:1.25.2 # 使用特定的 Istio 版本
imagePullPolicy: IfNotPresent
args:
- proxy
- sidecar
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --proxyLogLevel=warning # 基本日志配置
- --log_output_level=default:info
# 3. Istio Init 容器 (用于网络设置)
initContainers:
- name: istio-init
image: docker.io/istio/proxyv2:1.25.2 # 应与代理版本匹配
imagePullPolicy: IfNotPresent
args:
- istio-iptables
- -p # Envoy 的入站端口
- "15001"
- -z # Envoy 的出站捕获端口
- "15006"
- -u # Envoy 运行所用的用户 ID
- "1337"
- -m # 拦截模式
- REDIRECT
- -i # 包括所有 IP 范围
- '*'
- -b # 包括所有重定向到 Envoy 的端口 (通配符)
- '*'
- -d # 从重定向中排除特定的入站端口
- 15090,15021,15020
- --log_output_level=default:info
上面的 Pod yaml 为了简洁,清理掉了下面的内容:
- 在应用程序、init 容器和代理之间共享的卷 (volumes),用于证书、配置和通信。
- 为 Istio 容器设定的特定安全上下文 (security contexts) 和权限。
- 用于配置代理行为和身份的环境变量及参数。
- 就绪探针 (readiness probe) 和存活探针 (liveness probe)。
其实可以看出来,istio 注入了两个容器,一个容器是 istio-init,它会执行一个 iptables 规则劫持 Pod 流量,一个是 istio-proxy,即数据平面 envoy 的真正业务容器。
二、Envoy Sidecar 如何接管 Pod 进出流量?
当一个 Pod 启动时,容器引擎首先会启动一个名为 “Pause” 的特殊容器。这个 Pause 容器的主要作用是建立并持有 Pod 的网络命名空间(Network Namespace)。随后启动的 Pod 内所有其他业务容器以及 Istio Sidecar 容器(如 istio-proxy
)都会共享这同一个 Pause 容器的网络命名空间。
在业务容器启动之前,如果 Pod 被注入了 Istio Sidecar,会先运行一个名为 istio-init
的初始化容器。istio-init
容器的关键任务是修改 Pod 网络命名空间内的 iptables
规则。通过这些 iptables
规则,从而实现 Pod 所有出入的流量,都被拦截至 Envoy Sidecar
。
查看 istio 拦截使用的 iptables 规则。
测试用的 yaml 。
apiVersion: v1
kind: Pod
metadata:
name: test-pod
namespace: istio # 你可以根据需要修改命名空间,例如 "istio"
labels:
app: test-pod
spec:
containers:
- name: test-pod
#image: nicolaka/netshoot # 包含了 iptables 和许多其他网络工具
image: ubuntu:20.04
command: ["/bin/sh", "-c", "sleep infinity"] # 保持容器运行,以便你可以 exec进去
securityContext:
privileged: true
restartPolicy: Never # 或者 OnFailure,适用于调试 Pod
# apt-get update
# apt-get -y install iptables
进入容器,使用 iptables-save
查看 iptables 状况。
#
# Generated by iptables-save v1.8.4 on Thu May 22 09:34:48 2025
*nat
:PREROUTING ACCEPT [41:1372]
:INPUT ACCEPT [41:1372]
:OUTPUT ACCEPT [40:3126]
:POSTROUTING ACCEPT [43:3306]
:ISTIO_INBOUND - [0:0]
:ISTIO_IN_REDIRECT - [0:0]
:ISTIO_OUTPUT - [0:0]
:ISTIO_REDIRECT - [0:0]
# 入方向的所有流量都要进入 ISTIO_INBOUND 。
-A PREROUTING -p tcp -j ISTIO_INBOUND
# 出方向所有流量都需要进入 ISTIO_OUTPUT 。
-A OUTPUT -j ISTIO_OUTPUT
# 下面这些目标的端口,直接放行,因为这些端口就是 envoy sidecar 使用的。
# 注释[1]
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15020 -j RETURN
# 其他非 dest 为 envoy sidecar 的到 ISTIO_IN_REDIRECT ,即所有流量都转给 15006
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
# output方向,source 为 127.0.0.6,请求的为 127.0.0.1(localhost) 的话,直接放行。
# 127.0.0.6 这个 IP 地址通常被 Envoy sidecar 代理自身使用
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
# 由 Envoy 代理自己 (UID 1337) 发起的、目标不是 127.0.0.1、也不是发往特殊端口 15008、但却要通过环回接口 lo 发送出去的 TCP 流量转给 Envoy Sidecar 入流量管理端口。
# 作用: Pod 自己请求自己的 Service 的时候,Dest 会为 Pod 自身,然后到达 ISTIO_OUTPUT 链,就会触发下面的规则,被送回 Envoy Sidecar 入流量管理端口。
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -p tcp -m tcp ! --dport 15008 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
# 如果目标网卡是 lo,但是 uid 非 1337 ,即 pod 自己访问 127.0.0.1 。就直接放行
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
# 如果源头是 envoy sidecar 发起的 ,就直接放行。
# 这个是真正的网络出口,即 envoy sidecar 处理过的流量就将直接放行。
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
# GID 再来一遍。
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -p tcp -m tcp ! --dport 15008 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
# 目标是 127.0.0.1 的直接放行
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
# 其他所有的都转给 15001 。
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
COMMIT
# Completed on Thu May 22 09:34:48 2025
-
注释[1]Envoy Sidecar 自身的 Port :
-
15001 (TCP): Envoy 的出站流量端口。
-
15006 (TCP): Envoy 的入站流量端口。
-
15008 (H2/TCP): 用于 Istio Ambient Mesh 架构中的通信。
-
15020 (HTTP): 这个端口服务于与 Istio agent 和 Envoy 相关的多个目的:提供指标和遥测数据,还作为 pilot-agent 进程的管理端口,用于调试。
-
15021 (HTTP): 这是 Envoy sidecar 的主要健康检查端口。
-
15090 (HTTP): 这个端口专门用于暴露 Envoy 的 Prometheus 遥测数据。
-
流量路径图解:
- 出站流量: 业务容器 -> Iptables -> Envoy Sidecar -> 目标服务
- 入站流量: 外部请求 -> Pod -> iptables -> Envoy Sidecar -> 业务容器
总结:
- 入方向的TCP流量:除了发往Envoy Sidecar自身特定服务端口的流量被直接放行外,其余所有流量都被重定向至Envoy的入站处理端口15006。
- 出方向的TCP流量:127.0.0.1 (除了一些特殊的)相关的一些流量直接放行,其他所有其他由应用发起的出站TCP流量则被重定向至Envoy的出站处理端口15001。
简化后的版本:
可以再回顾一下 init 容器的配置
initContainers:
- name: istio-init
image: docker.io/istio/proxyv2:1.25.2 # 应与代理版本匹配
imagePullPolicy: IfNotPresent
args:
- istio-iptables
- -p # Envoy 的入站端口
- "15001"
- -z # Envoy 的出站捕获端口
- "15006"
- -u # Envoy 运行所用的用户 ID
- "1337"
- -m # 拦截模式
- REDIRECT
- -i # 包括所有 IP 范围
- '*'
- -b # 包括所有重定向到 Envoy 的端口 (通配符)
- '*'
- -d # 从重定向中排除特定的入站端口
- 15090,15021,15020
- --log_output_level=default:info
可以发现,iptables 中所定义的规则,基本是通过几个参数决定的。
总而言之,通过 istio-init
初始化容器对 iptables
的巧妙配置,使得 Pod 的网络流量得以被透明地拦截并导向 Envoy Sidecar。这种底层的流量劫持与转发机制,正是 Istio 实现其丰富的流量管理、安全策略和遥测功能的关键所在。
三、Envoy Sidecar 在 Istio 中的工作机制与流量规则解析
当 Envoy Sidecar 启动时,它会利用 init 容器提供的配置信息,连接到 Istiod (Pilot) 的 xDS 服务端,并以订阅模式与 Istiod (Pilot) 进行交互,从而获取动态配置。
理解 Istio 的流量管理,首先需要区分其与传统 Kubernetes Service 代理模式的差异。Kubernetes Service 主要依赖 kube-proxy 实现一种反向代理的负载均衡,流量在节点级别被路由。而 Istio 的规则实现,则巧妙地通过注入到应用 Pod 中的 Envoy Sidecar,以正向代理的模式进行。
具体来说,Envoy Sidecar 对进出其所在 Pod 的流量进行拦截和处理:
- 入站流量 (Ingress):当外部流量进入 Pod 时,会先被该 Pod 内的 Envoy Sidecar 拦截。通常情况下,对于入站流量,Sidecar 主要执行安全策略(如 mTLS认证、授权)、收集遥测数据等,然后将流量直接转发给 Pod 内的业务容器。Envoy Sidecar 本身不执行核心业务逻辑。
- 出站流量 (Egress):当业务容器尝试访问其他服务(无论是集群内部还是外部)时,发出的流量同样会被其 Pod 内的 Envoy Sidecar 拦截。此时,所有高级流量治理功能,如动态路由(基于VirtualService)、负载均衡、熔断、超时、重试等,均由这个出口处 (egress) 的 Envoy Sidecar 根据从 Istiod 获取的规则来执行。
我们可以对比一下流量路径的变化:
- 传统模式 (无 Istio):Pod 访问 Service 的流量路径通常是:
源 Pod -> Node 网络协议栈 (iptables/ipvs) -> 目标 Pod
- Istio 模式 (以出站流量为例):引入 Envoy Sidecar 后,从业务容器发出的流量路径变为:
源 Pod (业务容器) -> 源 Pod (Envoy Sidecar) -> ...网络... -> 目标服务/目标 Pod
(在目标端,如果目标 Pod 也注入了 Sidecar,则入站流量会先经过目标 Pod 的 Sidecar)
这种基于出口端 Sidecar 控制的架构模式,会产生一个重要的影响,即 Istio 高级流量规则的生效范围:
- 未注入 Sidecar 的 Pod 访问已注入 Sidecar 的 Pod: 当一个未运行 Istio Sidecar 的 Pod(我们称之为“非 Istio Pod”)尝试访问一个已经注入了 Sidecar 的 Pod(“Istio Pod”)时,即使为目标 “Istio Pod” 关联的 Service 配置了各种高级的 Istio 规则,这些规则对于来自“非 Istio Pod”的入站请求也不会生效。这是因为发起请求的源端没有 Envoy Sidecar 来解析和执行这些 Istio 规则。流量将按照 Kubernetes 默认的服务发现和负载均衡机制进行。
- 已注入 Sidecar 的 Pod 访问其他服务: 反之,当一个已注入 Sidecar 的 “Istio Pod” 去访问一个“非 Istio Pod”,甚至是访问集群外部的服务时,由于其出站流量由其自身的 Envoy Sidecar 控制,因此可以通过配置 VirtualService、DestinationRule 等 Istio 资源,来实现 Istio 提供的高级流量管理功能,包括智能路由、负载均衡、请求超时、重试机制、熔断保护等。
核心在于:Istio 的高级流量治理能力主要在流量发起的出口端(Egress Sidecar)得到实现和强制执行。
四、Ingress Gateway 的作用和工作原理
Istio Ingress Gateway
的网络原理相对更为集中和清晰。在功能定位上,它与传统的 Kubernetes Ingress 控制器有相似之处,都扮演着集群流量入口的角色,负责管理外部访问。然而,与服务网格内部 Pod 间通信依赖的 Envoy Sidecar 不同,Ingress Gateway 本身就是一个独立的 Envoy Proxy 实例,它以一个或多个专用 Pod 的形式运行,而不是作为 Sidecar 注入到某个业务应用的 Pod 中。
这个 Gateway Pod 的核心职责是作为外部流量进入服务网格的统一入口。因此,当外部客户端尝试访问网格内的服务时,典型的流量路径如下:
- 外部请求:用户或外部系统发起请求。
- 负载均衡器 (Load Balancer):流量首先到达云提供商或本地环境部署的外部负载均衡器。这个负载均衡器将流量导向集群中的一个或多个 Ingress Gateway 节点。
- NodePort/LoadBalancer Service: Kubernetes Service (通常是
LoadBalancer
类型或NodePort
类型) 接收来自外部 LB 的流量,并将其路由到后端的 Istio Ingress Gateway Pod。 - Istio Ingress Gateway Pod (Envoy Proxy):Gateway Pod 内的 Envoy Proxy 接收流量。此时,Envoy 会根据
Gateway
和VirtualService
(或HTTPRoute
等 Gateway API 资源) 的配置进行处理,例如:- TLS 卸载
- 基于主机名或路径的路由
- 请求头操作
- 应用其他 Istio 策略(如授权、速率限制等)
- 目标业务 Pod: 经过 Ingress Gateway 处理和路由后,流量最终被转发到集群内部相应业务服务的 Pod。
简而言之,Ingress Gateway 充当了网格的“看门人”,集中管理所有入站连接,并通过其内部运行的 Envoy 实例,根据声明式配置将外部流量安全、智能地导向内部服务。
五、Egress Gateway:集群出口流量的统一管理与安全控制
Istio Egress Gateway 作为一组专用的 Envoy 代理 Pod(非应用 Pod 内的 Sidecar),用于集中管控从服务网格发往外部的出口流量。其核心目标是增强安全性、统一实施策略并简化网络连接。
- 为何需要 Egress Gateway 管理出口流量?
管控出口流量主要出于以下目的:
- 强化安全与可控性:
- 实施最小权限访问(例如,结合全局配置
outboundTrafficPolicy.mode=REGISTRY_ONLY
,仅允许访问已明确定义的外部服务),防止数据外泄和未授权访问。 - 通过集中的出口点,简化对所有出向流量的审计与监控。
- 实施最小权限访问(例如,结合全局配置
- 统一实施精细化策略:
- 对访问不同外部服务的流量,在 Egress Gateway 上集中应用特定策略,如超时、重试等高级功能。
- 适应网络限制与要求:
- 使处于受限网络环境(无法直连外部)的内部 Pod 能通过 Egress Gateway 安全访问外部服务。
- 为需要固定源 IP 以便通过外部防火墙白名单验证的场景,提供一组可预测的出口 IP。
- Egress Gateway 流量路径示例
-
不使用 Egress Gateway :
Pod (业务容器) → Pod (Envoy Sidecar) → 外部服务
-
使用 Egress Gateway:
Pod (业务容器) → Pod (Envoy Sidecar) → Egress Gateway Pod (Envoy Proxy) → 外部服务
Istio Egress Gateway
通过提供一个专用的出口流量控制点,极大地增强了服务网格的安全性、可管理性和网络策略的灵活性,是构建企业级服务网格时管理外部依赖的重要组件。
总结
通过上述分析,清晰揭示了Istio数据平面的核心在于每个业务Pod中注入的Envoy Sidecar。此Sidecar代理通过巧妙配置网络规则,实现了对应用流量的无感知拦截与全面管理。无论是进入应用的请求,还是应用发出的调用,都会经过Envoy的处理和转发。理解Envoy的工作模式、流量的精确导向机制以及底层的劫持技术原理,将使我们能更深刻地把握Istio流量管理的本质,为后续的高阶应用与故障排查奠定坚实基础。