Sidecar及流量拦截机制-上

⭐️关注我 ,一起探索更多知识!⭐️

更多相关文章

个人博客 :pyenv.cc

ServiceMesh基本概念

手把手教你部署istio控制平面

四个案例让你掌握istio网格功能

VirtualService实现Istio高级流量治理

DestinationRule实现Istio集群高级配置

一、Istio环境中运行Pod的要求

  • Service association (服务关联)
  • Pod 必须从属于某个Service,哪怕Pod不需要暴露任何端口,否则此Pod就是一个无Service的Pod,会导致网格内部无法于相关的Sidecar进行关联;
  • 同时从属于多个Service时,这些Service不能为该类Pod的同一个端口标识使用不同的协议;
  • Application UIDs
  • UID 1337 预留给了Sidecar Proxy 使用,业务应用不能以这一 UID 运行;
  • NET_ADMIN and NET_RAW capabilities
  • 强制启用了PSP(Pod Security Policy)的Kubernetes环境中,必须允许在网格内的Pod上使用NET_ADMIN和 NET_RAW这两个Capability,以确保Sidecar Envoy依赖的初始化Pod能够正常运行;
  • 未启用PSP,或者启用了PSP但使用了专用的Istio CNI Plugin的场景,可以不用;
  • Pods with app and version labels (部署在网格内的每一个应用程序都需要明确使用以下两个标签)
  • 显式地为 Pod使用app和version标签;
  • app标签用于为分布式追踪生成context,而label则用于指示应用的版本化;
  • Named Service Ports (为网格内的每一个Service的端口定义一个名称及明确其协议)
  • Service Port 应该明确指定使用的协议;
  • 命名格式 :
    • [-] 如 http-8080
    • Kubernetes v1.18 及之后的版本中,可以直接使用 appProtocol 字段进行标识;
# 网格会依赖对应方式指定的协议标识作为协议,即应用程序对外提供服务协议的特定标识;这也是Envoy在代理应用程序基于的协议类型;

1、<protocol>[-<suffix>] 格式
apiVersion: v1
kind: Service
metadata:
  name: demoappv10
spec:
  ports:
    - name: http-8080
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: demoapp
    version: v1.0
  type: ClusterIP

2、Kubernetes v1.18 及之后的版本中,可以直接使用 appProtocol 字段进行标识
apiVersion: v1
kind: Service
metadata:
  name: demoappv10
spec:
  appProtocol: http
  ports:
    - name: http
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: demoapp
    version: v1.0
  type: ClusterIP

二、协议选择 (Protocol Selection)

  • Istio 支持代理的协议
    • 支持代理任何类型的TCP流量,包括HTTP、HTTPS、gRPC及原始TCP(raw tcp) 协议;
    • 但为了提供额外的能力,比如路由和更加丰富的指标,Istio需要确定更加具体的协议( 应用层协议) ;
    • Istio不会代理任何UDP协议;
  • 协议选择
    • istio 能够自动检测并识别 HTTP和HTTP/2 的流量,未检测出的协议类型将一律视为普通的TCP流量;
    • 也支持由用户手动指定;
  • 手动指定协议
    • Service Port 应该明确指定使用的协议;
    • 命名格式 :
      • [-]
      • Kubernetes v1.18 及之后的版本中,可以直接使用 appProtocol 字段进行标识;
  • Istio支持的协议类型如下 :

https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/

image.png

三、Sidecar代理方式简介

  • Kubernetes平台上,Envoy Sidecar容器与application容器于同一个Pod中共存,它们共享 NETWORK、UTS和IPC等名称空间,因此也共用同一个网络协议栈;
    • Envoy Sidecar 基于 init 容器 (需要使用 NET_ADMIN 和 NET_RAW Capability 于 Pod启动时设置的 iptables规则以实现流量拦截)
      • 入站流量由iptables拦截后转发给Envoy;
      • Envoy根据配置完成入栈流量代理;
      • 后端应用程序生成的出站流量依然由iptables拦截并转发给Envoy;
      • Envoy 根据配置完成出站流量代理;
  • 流量拦截模式
    • REDIRECT : 重定向模式
    • TPROXY : 透明代理模式
      • 具体操作参考 : https://github.com/istio/istio/blob/master/tools/packaging/common/istio-start.sh

四、Sidecar Envoy 流量劫持

  • 流量的透明劫持
    • 流量的透明劫持,用于确保让应用无需事先改造即可获得服务治理和观测能力;
    • 开启透明劫持功能后,出入应用的业务流量将会被Sidecar Envoy自动拦截;

image.png

五、Istio注入的Envoy Sidecar

  • Istio 基于 Kubernetes Admission Controller Webhook 完成sidecar自动注入,它会为每个微服务分别添加两个相关的容器;
    • istio-init : 隶属于 Init Containers ,即初始化容器,负责在微服务相关的Pod中 生成iptables规则 以进行流量拦截并向Envoy Proxy进行转发,运行完成后退出;
    • istio-proxy : 隶属于Contianers, 即Pod中的正常容器,程序为 Envoy Proxy;
# 查看每个Pod上是如何指定注入的 istio init container
# Init Containers 生成流量劫持规则
Init Containers:
  istio-init:
    Container ID:  docker://943e9512f4e3ec0f64b25b26ac334c70800169416389abc58b723413481c787f
    Image:         docker.io/istio/proxyv2:1.12.1
    Image ID:      docker-pullable://istio/proxyv2@sha256:4704f04f399ae24d99e65170d1846dc83d7973f186656a03ba70d47bd1aba88f
    Port:          <none>
    Host Port:     <none>
    Args:
      istio-iptables
      # 入向流量生成规则的重定向端口
      -p
      15001
      # 出向流量端口
      -z
      15006
      # 使用用户UID
      -u
      1337
      -m
      REDIRECT
      -i
      *
      -x

      -b
      *
      -d
      15090,15021,15020
...
Containers:
  demoapp:
    Container ID:   docker://563a48b833baf3ab46ef35f147012e124ba3c114323377c261f2cb5c8729a34f
    Image:          ikubernetes/demoapp:v1.0
    Image ID:       docker-pullable://ikubernetes/demoapp@sha256:6698b205eb18fb0171398927f3a35fe27676c6bf5757ef57a35a4b055badf2c3
    Port:           <none>
    Host Port:      <none>
...
# istio-proxy: 真正意义上流量治理 sidecar envoy
  istio-proxy:
    Container ID:  docker://bab78cd8993123c8a24a236a02a0b572a3acbc0e013559a24dd57959d9c7430c
    Image:         docker.io/istio/proxyv2:1.12.1
    Image ID:      docker-pullable://istio/proxyv2@sha256:4704f04f399ae24d99e65170d1846dc83d7973f186656a03ba70d47bd1aba88f
    Port:          15090/TCP
    Host Port:     0/TCP
    Args:
      proxy
      sidecar   # sidecar 模式运行
      --domain
      $(POD_NAMESPACE).svc.cluster.local
      --proxyLogLevel=warning
      --proxyComponentLogLevel=misc:error
      --log_output_level=default:info
      --concurrency
      2

5.1、istio-init初始化容器

  • istio-init初始化容器基于 istio/proxyv2 镜像启动,它运行 istio-iptables 程序以生成流量拦截规则
    • 拦截的流量将转发至两个相关的端口
      • 15006 :由 -z 选项定义,指定用于接收拦截所有发往当前Pod/VM的入栈流量的目标端口,该配置仅用于 REDIRECT 转发模式;
      • 15001 :由 -p 选项定义,指定用于接收拦截的所有TCP流量的目标端口;
    • 流量拦截模式由 -m 选项指定,目前支持 REDIRECT 和 TPROXY 两种模式;
    • 流量拦截时要包含的目标端口列表使用 -b 选项指定,而要排除的目标端口列表则使用 -d 选项指定;
    • 流量拦截时要包含的目标 CIDR 地址列表可使用 -i 选项指定,而要排除的目标 CIDR 格式的地址列表则使用 -x 选项指定;
5.1.1、istio中用于流量拦截的iptables规则
  • nsenter 命令于宿主机上可直接于目标容器的网络名称空间中运行 iptables 命令,例如,假设 productpage 相关的 Pod被调度运行于 k8s-node02 节点之上,且其内部的 envoy 进程的 pid在宿主机为 5607 ;
# 对应运行envoy sidecar 节点上运行命令
root@native:~# ps aux | grep envoy | grep 1337
root@native:~# nsenter -t 8134 -n iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N ISTIO_INBOUND
-N ISTIO_IN_REDIRECT
-N ISTIO_OUTPUT
-N ISTIO_REDIRECT
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 22 -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
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -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 ! -d 127.0.0.1/32 -o lo -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
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
5.1.2、流量拦截的处理机制
  • 入向流量拦截 : PREROUTING -> ISTIO_INBOUND
    • RETURN
      • 目标端口为 TCP 协议的 22、15020、15021、15008、15090 时将报文返回至上级 PREROUTING 链,即不予拦截;
    • ISTIO_IN_REDIRECT : 其它目标端口的请求报文则由该自定链中的规则 (-A ISTIO_IN_REDIRECT -p tcp -j RESIRECT --to-ports 15006) 将请求重定向至 15006 端口;
      • 15006 端口时为 envoy 的 VirtualInboundListener 绑定的端口,于是请求则转交由Envoy处理;
      • Envoy 根据报文目标地址匹配入向 (Inbound) 方向的Listener,若存在,则根据该 Listener的配置决定如何将请求转发至 Envoy后端的应用程序;

image.png

  • 出向流量拦截 : OUTPUT -> ISTIO_OUTPUT
    • RETURN
      • 从 LO 接口流出,且源地址为 127.0.0.6/32 的出向流量
      • UID Owner 为 1337 的出向流量
      • GID Owner 为 1337 的出向流量
      • 从 LO 接口流出,且UID Owner 非为 1337 的出向流量
      • 从 LO 接口流出,且GID Owner 非为 1337 的出向流量
      • 目标地址是 127.0.0.1/32 的出向流量
    • ISTIO_IN_REDIRECT : Sidecar Envoy 同其反向代理的本地后端应用程序间的通信
      • 从 LO 接口流出,目标地址非为 127.0.0.1/32,且UID Owner 为 1337 的出向流量
      • 从 LO 接口流出,目标地址非为 127.0.0.1/32,且GID Owner 为 1337 的出向流量
  • ISTIO_REDIRECT:其它报文则由该自定义链中的规则(-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001)重定向至15001端口;
    • Envoy根据报文目标地址匹配出向(Outbound)方向的Listener,若存在,则 根据该Listener的配置决定如何将报文向外转发;

image.png

5.2、istio-proxy 容器

  • istio-proxy即所谓的sidecar容器,它运行两个进程:
    • pilot-agent
    • 基于k8s api server 为 envoy 初始化出可用的 bootstrap 配置文件并启动envoy;
    • 监控并管理envoy的运行状态,包括envoy出错时重启envoy,以及envoy配置变更后将其重载等;
    • envoy
    • envoy 由pilot-agent 进程基于生成bootstrap 配置进行启动,而后根据配置中指定的 pilot 地址,通过xDS API获取动态配置信息;
    • Sidecar形式的Envoy通过流量拦截机制为应用程序实现入站和出站代理功能;
# kubectl exec demoappv10-6ff964cbff-84kqr -it -c istio-proxy -- ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
istio-p+     1  0.1  0.4 747732 47700 ?        Ssl  Feb19   0:50 /usr/local/bin/pilot-agent proxy sidecar --domain default.svc.cluster.local --proxyLogLevel=
istio-p+    28  0.4  0.5 185544 58488 ?        Sl   Feb19   3:16 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45
istio-p+    42  0.0  0.0   5900  2804 pts/0    Rs+  03:45   0:00 ps aux

5.2.1、istio-proxy 容器及其Listener
  • Envoy 的bootstrap 配合文件由pilot-agent 负责生成,而生效的大多配置则定义了dynamic resources ,并通过xDS静态集群指向的Plot 获取;
    • 而这些配置则来自于 VirtaulService、DestinationRule、Gateway和ServiceEntry资源对象等提供的配置;
  • 由Pilot基于Kubernetes发现的网格内的各Service均会被自动转换为下发给各Sidecar实例的Listener、Route、Cluster和Endpoint的相关配置;
    • 为了能够让Sidecar Envoy代理网格内进出各Service的流量,所以需要进行流量劫持,而后由Envoy根据请求特征,将流量派发至合适的Listener,进而完成后续的流量路由、负载均衡等;
5.2.2、istio-proxy Listener (几个重要侦听器的作用)
  • Envoy Listener 支持绑定于 IP Socket 或 Unix Domain Socket 之上,也可以不予绑定,而是接收由其他的Listener转发来的数据;
    • VirtualOutboundListener
    • 通过一个端口接收所有的出口流量,而后再按照请求的端口分别转发给相应的 Listener进行处理;
    • VirtualInboundListner
    • 功能相似,但主要用于处理入向流量;

VirtualOutboundListener(不过多展开)

  • iptables 将其所在的Pod中的外发流量拦截后转发至监听于15001的Listener,而该Listener通过在配置中将 use_origin_dest 参数设置为true,从而实现将接收到的请求转发给同请求原目标地址关联的Listener之上;
  • 若不存在可接收转发报文的Listener,则Envoy将根据Istio的全局配置选项 outboundTrafficPolicy 参数的值决定如何进行处理 :
    • ALLOW_ANY :
    • 允许外发至任何服务的请求,无论目标服务是否存在于Pilot的注册表中;此时,没有匹配的目标Listener的流量将由该侦听器上 tcp_proxy 过滤器指向的 Passthrouh Cluster 进行透传;
    • REGISTRY_ONLY :
    • 仅允许外发请求至注册与Polit 中的服务;此时,没有匹配的目标Listener的流量将由该侦听器上 tcp_proxy 过滤器指向的 BlackHoleCluster 将流量直接丢弃;
  • 出向流量劫持方式总结 :
    • 所有应用的出向流量会被重定向给 Envoy Sidecar 的 15001 侦听器,而后 15001 侦听器将流量根据其请求的原有的目标IP和目标端口来在Envoy中找出真正于该流量相关的出站侦听器,再把其请求转交至其真正相关的出站侦听器;若其没有找到对应条件的出站侦听器则根据出站流量策略 outboundTrafficPolicy 确定是交给 Passthrouh Cluster 进行透传还是 BlackHoleCluster 进行丢弃;

VirtualInbound Listener(不过多展开)

  • 入向流量劫持
    • 较早版本的 Istio 基于同一个 VirtualListener 在 15001 端口上同时处理入站和出站流量;
    • 自 1.4 版本起,Istio引入了 REDIRECT 代理模式,它通过监听于 15006 端口 的专用 VirtualInboundListener 处理入向流量代理以避免潜在的死循环问题;
  • 入向流量处理
    • 对于进入到 侦听器 “0.0.0.0:15006” 的流量,VirtaulInboundListener 会在 filterChains 中,通过一系列的 filter_chain_match 对流量进行匹配检测,以确定应该由哪个或哪些过滤器进行流量处理;
  • 入向流量劫持方式总结
    • istio proxy 对所有相关入向流量的处理方式是所有请求的无论目标 APP服务监听的端口,Envoy 都不会为其在前端创建入站侦听器而是所有流量交给 15006 ,在15006入站侦听器内部 都会通过 filter_chain_match 进行处理,然后通过其内部 filterChainMatch 进行匹配,而后又经过filter进行流量转发;

5.3、istio-proxy Clusters

  • Istio 网格中的Cluster分别由 static_resources 提供的静态配置集群以及 dynamic_resources 提供的动态配置集群组成;
    • 静态集群由 envoy_rev0.json 的初始化配置中的 prometheus_stats 、xDS server 和zipkin server等组成;
    • 动态集群则是由通过xDS API 从Pilot获取的配置信息生成;
  • 对于网格内的一个特定Pod来说,其集群可主要分为两类 :
    • inbound : 该Pod内的Sidecar Envoy直接代理的服务;
    • outbound : 网格内的所有服务;
  • 动态集群类型
    • Inbound Cluster :Sidecar Envoy直接代理的应用,同一Pod中,由Sidecar Envoy反向代理的应用容器;
    • Outbound Cluster :网格中的所有服务,包括当前Sidecar Envoy直接代理的服务,该类Cluster占了Envoy可用集 群中的绝大多数;
    • PassthroughCluster和InboundPassthroughClusterIpv4 :发往此类集群的请求报文会被直接透传至其请求中的原 始目标地址,Envoy不会进行重新路由;
    • BlackHoleCluster :Envoy的一个特殊集群,它没有任何可用的endpoint,接收到的请求会被直接丢弃;未能正 确匹配到目标服务的请求通常会被发往此Cluster;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值