文章《Kubernetes生产实践系列之二十三:Service Mesh之在Kubernetes部署Istio进行service mesh》介绍了Istio的部署和使用案例,本文对于v1.6版本的Istio proxy sidecar的工作原理进行分析,包括:
转载自https://blog.csdn.net/cloudvtech
根据Istio官方文档《Installing the Sidecar》,sidecard有手动注入和自动注入两种方式,这两种注入方式可以使用默认的注入配置文件:
kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.config}' > inject-config.yaml
kubectl -n istio-system get configmap istio-sidecar-injector -o=jsonpath='{.data.values}' > inject-values.yaml
kubectl -n istio-system get configmap istio -o=jsonpath='{.data.mesh}' > mesh-config.yaml
accessLogEncoding: TEXT
accessLogFile: /dev/stdout
accessLogFormat: ""
defaultConfig:
concurrency: 2
configPath: ./etc/istio/proxy
connectTimeout: 10s
controlPlaneAuthPolicy: NONE
discoveryAddress: istiod.istio-system.svc:15012
drainDuration: 45s
parentShutdownDuration: 1m0s
proxyAdminPort: 15000
proxyMetadata:
DNS_AGENT: ""
serviceCluster: istio-proxy
tracing:
zipkin:
address: zipkin.istio-system:9411
disableMixerHttpReports: true
disablePolicyChecks: false
enablePrometheusMerge: false
ingressClass: istio
ingressControllerMode: STRICT
ingressService: istio-ingressgateway
protocolDetectionTimeout: 100ms
reportBatchMaxEntries: 100
reportBatchMaxTime: 1s
sdsUdsPath: unix:/etc/istio/proxy/SDS
trustDomain: cluster.local
trustDomainAliases: null
a) 使用istioctl进行手动注入
istioctl kube-inject -f sample.yaml | kubectl apply -f -
也可以在注入的时候overwrite默认的Istio配置文件,使用自定义的配置:
istioctl kube-inject \
--injectConfigFile inject-config.yaml \
--meshConfigFile mesh-config.yaml \
--valuesFile inject-values.yaml \
--filename sample.yaml \
| kubectl apply -f -
b) 使用webhook admission controller进行自动注入
需要先将一个namespace标记成可以注入的:
kubectl label namespace istio-test istio-injection=enabled
之后在这个namespace部署的POD会由Kubernetes自动按照注入的配置文件进行sidecar注入
在执行sidecar注入之后,新启动的POD会启动sidecar,包含两个container,一个是初始化容器,一个是proxy容器。
a) 初始化容器istio-init
该容器主要是进行POD network namespace sidecar iptables的写入,这些iptables规则主要是进行出站和入站数据的劫持转发:
b) 数据流代理容器istio-proxy
该容器进行数据面数据流的转发和控制,实现servicemesh的所有数据流管控工作,包括目的地查找、负载均衡、熔断、服务发现、服务健康管理、metrics和trace等工作。该数据proxy借助envoy进行数据面得到操作,envoy使用C++进行编码,同时使用xDS协议进行系统化和规范化的控制面和数据面、数据面和数据面的信息交互。
转载自https://blog.csdn.net/cloudvtech
数据流量的劫持主要发生在istio-init容器里面建立的iptables规则中,由于这些iptables是建立在业务POD的namespace的,所以在主机上是看不到这些规则的。
init容器通过istio-iptables命令和指定的参数来插入iptables:
istio-iptables -p 15001 -z 15006 -u 1337 -m REDIRECT -i * -x -b * -d 15090,15021,15020
对应的代码在这里:
https://github.com/istio/istio/blob/master/tools/istio-iptables/pkg/cmd/run.go
该命令参考如下一些变量:
PROXY_PORT=15001
PROXY_INBOUND_CAPTURE_PORT=15006
PROXY_UID=1337
PROXY_GID=1337
INBOUND_INTERCEPTION_MODE=REDIRECT
INBOUND_TPROXY_MARK=1337
INBOUND_TPROXY_ROUTE_TABLE=133
INBOUND_PORTS_INCLUDE=*
INBOUND_PORTS_EXCLUDE=15090,15021,15020
OUTBOUND_IP_RANGES_INCLUDE=*
OUTBOUND_IP_RANGES_EXCLUDE=
OUTBOUND_PORTS_EXCLUDE=
KUBEVIRT_INTERFACES=
ENABLE_INBOUND_IPV6=false
PROXY_UID/GID是enovy proxy以该ID运行,15006和15001分别是入站和出站端口,15090/15021/25020是istio的管理端口,所以会从入站监控端口里面去除,另外入站流量使用REDIRECT的模式进行劫持,另外一种劫持方式是TPROXY。
插入的规则如下:
* nat
-N ISTIO_REDIRECT
-N ISTIO_IN_REDIRECT
-N ISTIO_INBOUND
-N ISTIO_OUTPUT
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A ISTIO_INBOUND -p tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15020 -j RETURN
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -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
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
COMMIT
同时注入之后的POD网卡设备信息如下:
root@web-54f74db995-c26xv:/# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: tunl0@NONE: mtu 1480 qdisc noop state DOWN group default qlen 1000
link/ipip 0.0.0.0 brd 0.0.0.0
4: eth0@if106: mtu 1440 qdisc noqueue state UP group default
link/ether 86:4c:63:b6:14:cc brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.241.91/32 scope global eth0
valid_lft forever preferred_lft forever
在进行iptables规则解读之前,有几个基本的规则需要先进行了解,以便于理解后续的iptables规则:
init容器插入的iptables规则编号如下:
01: * nat
02: -N ISTIO_REDIRECT
03: -N ISTIO_IN_REDIRECT
04: -N ISTIO_INBOUND
05: -N ISTIO_OUTPUT
06: -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
07: -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
08: -A PREROUTING -p tcp -j ISTIO_INBOUND
09: -A ISTIO_INBOUND -p tcp --dport 22 -j RETURN
10: -A ISTIO_INBOUND -p tcp --dport 15090 -j RETURN
11: -A ISTIO_INBOUND -p tcp --dport 15021 -j RETURN
12: -A ISTIO_INBOUND -p tcp --dport 15020 -j RETURN
13: -A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
14: -A OUTPUT -p tcp -j ISTIO_OUTPUT
15: -A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN
16: -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
17: -A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
18: -A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
19: -A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
20: -A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
21: -A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
22: -A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
23: -A ISTIO_OUTPUT -j ISTIO_REDIRECT
24: COMMIT
iptables规则解释:
综上所述,入站的数据包的处理比较简单,除了exlcude一些端口,其余的都进入proxy入站处理逻辑,而出站的情况比较复杂,对于如下一些case进行了特殊处理:
这里主要的区分点包括:
其它参考信息:
转载自https://blog.csdn.net/cloudvtech
基本流程:进入和流出istio proxy sidecar和业务容器的流量都需要分别经过ISTIO_INBOUND和ISTIO_OUTPUT的处理,sidecar和业务容器发出或者接收的流量都会独立走一次iptables链表
servicemesh流程:app1 => envoy proxy1 => envoy proxy2 => app2,app1调用app2所在的服务会通过Kubernetets的cluster service IP进行,进入envoy proxy1之后会选定app2所在的服务的后端列表里面的某一个endpoint比如app2容器,获取其IP,将请求的目的地设置为该IP,发送过去,envoy proxy2在接收到数据包之后,会直接转发给后端app2容器。
proxy和mesh操作:而对于envoy proxy而言,入站数据包是指外部业务容器调用本地业务容器的流量以及本地调用外部之后的返回流量,这里都只要让proxy进行转发操作而不需要mesh操作;出站数据包是指本地业务容器调用外部业务容器的流量以及本地给外部返回的响应流量,这里前者需要本地proxy进行mesh操作而后者只需要proxy操作不需要mesh操作;入站和入站的数据包经过evnoy mesh操作之后都带有明确的源POD和目的POD地址。
对于入站的数据,被劫持之后的目的动作有两个:
对于出站的数据,被劫持之后的目的动作有三个:
这里比较费解的是出站数据竟然有可能要进行入站处理,主要是考虑服务A的某个POD1调用自己所在的服务A的Kubernetes service IP,最后被istio proxy进行mesh之后调度到自己(POD1)的情况,这种情况下出站操作之后紧接着就应该是入站操作。
app1(svc1)会使用app2所在的svc2来进行调用:
app2(svc2)处理之后响应app1的流程如下:
注释:
特别的,如果svc1 = svc2,并且在步骤d)中POD1 = POD2,则数据包的出口设备会变成lo,目的地址为POD1的IP地址,则会匹配ISTIO_OUTPUT链表中的规则16/19,然后进入ISTIO_IN_REDIRECT链表
转载自https://blog.csdn.net/cloudvtech