在讲解 Istio 如何将 Envoy 代理注入到应用程序 Pod 中之前,我们需要先了解以下几个概念:
- Sidecar 模式:容器应用模式之一,Service Mesh 架构的一种实现方式。
- Init 容器:Pod 中的一种专用的容器,在应用程序容器启动之前运行,用来包含一些应用镜像中不存在的实用工具或安装脚本。
- iptables:流量劫持是通过 iptables 转发实现的。
Init 容器
Init 容器是一种专用容器,它在应用程序容器启动之前运行,用来包含一些应用镜像中不存在的实用工具或安装脚本。
一个 Pod 中可以指定多个 Init 容器,如果指定了多个,那么 Init 容器将会按顺序依次运行。只有当前面的 Init 容器必须运行成功后,才可以运行下一个 Init 容器。当所有的 Init 容器运行完成后,Kubernetes 才初始化 Pod 和运行应用容器。
在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready
状态。Init 容器的端口将不会在 Service 中进行聚集。 正在初始化中的 Pod 处于 Pending
状态,但应该会将 Initializing
状态设置为 true。Init 容器运行完成以后就会自动终止。
Istio注入Sidecar代理
基于k8s平台,在Istio注入sidecar之后,Service没有变化,所有变化都在Deployment
里,Istio 给应用 Pod 注入的配置主要包括:
- Init 容器
istio-init
:用于给 Sidecar 容器即 Envoy 代理做初始化,设置 iptables 端口转发,该容器存在的意义就是让 Envoy 代理可以拦截所有的进出 Pod 的流量,即将入站流量重定向到 Sidecar,再拦截应用容器的出站流量经过 Sidecar 处理后再出站。因为 Init 容器初始化完毕后就会自动终止,因为我们无法登陆到容器中查看 iptables 信息,但是 Init 容器初始化结果会保留到应用容器和 Sidecar 容器中。 - 应用容器
istio-proxy
:运行 Envoy 代理
iptables普及
iptables
是 Linux 内核中的防火墙软件 netfilter 的管理工具,位于用户空间,同时也是 netfilter 的一部分。Netfilter 位于内核空间,不仅有网络地址转换的功能,也具备数据包内容修改、以及数据包过滤等防火墙功能。
在了解 Init 容器初始化的 iptables 之前,我们先来了解下 iptables 和规则配置。
下图展示了 iptables 调用链。
- Init 容器中使用的的 iptables 版本是
v1.6.0
,共包含 5 张表:
raw
用于配置数据包,raw
中的数据包不会被系统跟踪。filter
是用于存放所有与防火墙相关操作的默认表。nat
用于 网络地址转换(例如:端口转发)。mangle
用于对特定数据包的修改(参考损坏数据包)。security
用于强制访问控制 网络规则。
不同的表中的具有的链类型如下表所示:
规则名称 | raw | filter | nat | mangle | security |
---|---|---|---|---|---|
PREROUTING | ✓ | ✓ | ✓ | ||
INPUT | ✓ | ✓ | ✓ | ✓ | |
OUTPUT | ✓ | ✓ | ✓ | ✓ | |
POSTROUTING | ✓ | ✓ | |||
FORWARD | ✓ | ✓ | ✓ | ✓ |
下图是 iptables 的调用链顺序。
- iptables 命令
iptables
命令的主要用途是修改这些表中的规则。iptables
命令格式如下:
1 | $ iptables [-t 表名] 命令选项[链名][条件匹配][-j 目标动作或跳转] |
- 查看iptables 规则,默认查看的是 filter 表中的规则
1 | $ iptables -L -v |
我们看到三个默认的链,分别是 INPUT、FORWARD 和 OUTPUT,每个链中的第一行输出表示链名称(在本例中为INPUT/FORWARD/OUTPUT),后跟默认策略(ACCEPT)。
每条链中都可以添加多条规则,规则是按照顺序从前到后执行的。我们来看下规则的表头定义。
- pkts:处理过的匹配的报文数量
- bytes:累计处理的报文大小(字节数)
- target:如果报文与规则匹配,指定目标就会被执行。
- prot:协议,例如
tdp
、udp
、icmp
和all
。 - opt:很少使用,这一列用于显示 IP 选项。
- in:入站网卡。
- out:出站网卡。
- source:流量的源 IP 地址或子网,后者是
anywhere
。 - destination:流量的目的地 IP 地址或子网,或者是
anywhere
。
prot
、opt
、in
、out
、source
和 destination
和显示在 destination
后面的没有表头的一列扩展条件共同组成匹配规则。当流量匹配这些规则后就会执行 target
。
- target 支持的类型
target
类型包括 ACCEPT
、REJECT
、DROP
、LOG
、SNAT
、MASQUERADE
、DNAT
、REDIRECT
、RETURN
或者跳转到其他规则等。只要执行到某一条链中只有按照顺序有一条规则匹配后就可以确定报文的去向了,除了 RETURN
类型,类似编程语言中的 return
语句,返回到它的调用点,继续执行下一条规则。
通过iptables nat表劫持流量
Init 容器通过向 iptables nat 表中注入转发规则来劫持流量的,下图显示的是 productpage 服务中的 iptables 流量劫持的详细过程。
Init 容器启动时命令行参数中指定了 REDIRECT
模式,因此只创建了 NAT 表规则,接下来我们查看下 NAT 表中创建的规则,这是全文中的重点部分,前面讲了那么多都是为它做铺垫的。下面是查看 nat 表中的规则,其中链的名字中包含 ISTIO
前缀的是由 Init 容器注入的,规则匹配是根据下面显示的顺序来执行的,其中会有多次跳转。
1 | # 查看 NAT 表中规则配置的详细信息 |
ISTIO_OUTPUT
链规则匹配的详细过程如下:
- 如果目的地非 localhost 就跳转到 ISTIO_REDIRECT 链
- 所有来自 istio-proxy 用户空间的非 localhost 流量跳转到它的调用点
OUTPUT
继续执行OUTPUT
链的下一条规则,因为OUTPUT
链中没有下一条规则了,所以会继续执行POSTROUTING
链然后跳出 iptables,直接访问目的地 - 如果流量不是来自 istio-proxy 用户空间,又是对 localhost 的访问,那么就跳出 iptables,直接访问目的地
- 其它所有情况都跳转到
ISTIO_REDIRECT
链
其实在最后这条规则前还可以增加 IP 地址过滤,让某些 IP 地址段不通过 Envoy 代理。
以上 iptables 规则都是 Init 容器启动的时使用 istio-iptables.sh 脚本生成的,详细过程可以查看该脚本。