前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Istio服务网格细节剖析

Istio服务网格细节剖析

作者头像
王先森sec
发布于 2023-04-24 09:36:14
发布于 2023-04-24 09:36:14
82800
代码可运行
举报
文章被收录于专栏:王先森王先森
运行总次数:0
代码可运行

Envoy简介

什么是Envoy

  • envoy 是作为微服务服务架构中以独立进程方式实现高级网络功能的,轻量级的7层服务代理程序,通常以sidecar的方式运行在应用程序的周边,也可以作为网络的边缘代理来运行。
  • envoy 的特性 进程外体系结构 ,L3/L4过滤器体系结构,HTTP L7过滤器体系结构, 一流的HTTP/2支持, HTTP/3支持(目前为alpha),HTTP L7路由,gRPC支持,服务发现和动态配置,健康检查,高级负载平衡,前端/边缘代理支持, 一流的可观察性

服务网格细节剖析

宏观分析

执行的操作:

  • 使用istioctl为pod注入了sidecar
  • 创建了virtualservice和destinationrule

如何最终影响到了pod的访问行为?

宏观角度

nginx的配置中,可以提供类似如下的配置片段实现按照权重的转发:

因为nginx是代理层,可以转发请求,istio也实现了流量转发的效果,肯定也有代理层,并且识别了前面创建的虚拟服务中定义的规则。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl kube-inject -f front-tomcat-dpl-v1.yaml

可以看到注入后yaml中增加了很多内容:

pod被istio注入后,被纳入到服务网格中,每个pod都会添加一个名为istio-proxy的容器(常说的sidecar容器),istio-proxy容器中有两个进程,一个是piolot-agent,一个是envoy

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c istio-proxy bash
# ps aux

目前已知:

  • 在istio网格内,每个Pod都会被注入一个envoy代理
  • envoy充当nginx的角色,做为proxy代理,负责接管pod的入口和出口流量

目前,还需要搞清楚几个问题:

  • istio-init初始化容器作用是什么?
  • istio-proxy如何接管业务服务的出入口流量?

认识envoy

Envoy 是为云原生应用设计的代理。

可以和nginx做类比: https://fuckcloudnative.io/posts/migrating-from-nginx-to-envoy/

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ docker run -d --name envoy -v `pwd`/envoy.yaml:/etc/envoy/envoy.yaml -p 10000:10000 envoyproxy/envoy-alpine:v1.15.2

$ curl localhost:10000
envoy.yaml
admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { cluster: some_service }
          http_filters:
          - name: envoy.router
  clusters:
  - name: some_service
    connect_timeout: 2s
    type: STATIC
    lb_policy: ROUND_ROBIN
    hosts: [{ socket_address: { address: 10.103.211.217, port_value: 9999 }}]

脑补一下网络代理程序的流程,比如作为一个代理,首先要能获取请求流量,通常是采用监听端口的方式实现;其次拿到请求数据后需要对其做微处理,例如附加 Header 或校验某个 Header 字段的内容等,这里针对来源数据的层次不同,可以分为 L3/L4/L7,然后将请求转发出去;转发这里又可以衍生出如果后端是一个集群,需要从中挑选一台机器,如何挑选又涉及到负载均衡等。

  • listener : Envoy 的监听地址。Envoy 会暴露一个或多个 Listener 来监听客户端的请求。
  • filter : 过滤器。在 Envoy 中指的是一些“可插拔”和可组合的逻辑处理层,是 Envoy 核心逻辑处理单元。
  • route_config : 路由规则配置。即将请求路由到后端的哪个集群。
  • cluster : 服务提供方集群。Envoy 通过服务发现定位集群成员并获取服务,具体路由到哪个集群成员由负载均衡策略决定。

envoy动态配置(xDS)

Envoy的启动配置文件分为两种方式:静态配置和动态配置。

  • 静态配置是将所有信息都放在配置文件中,启动的时候直接加载。
  • 动态配置需要提供一个Envoy的服务端,用于动态生成Envoy需要的服务发现接口,这里叫XDS,通过发现服务来动态的调整配置信息,Istio就是实现了v2的API

Envoy 接收到请求后,会先走 FilterChain,通过各种 L3/L4/L7 Filter 对请求进行微处理,然后再路由到指定的集群,并通过负载均衡获取一个目标地址,最后再转发出去。

其中每一个环节可以静态配置,也可以动态服务发现,也就是所谓的 xDS。这里的 x 是一个代词,类似云计算里的 XaaS 可以指代 IaaSPaaSSaaS 等。

所以,envoy的架构大致的样子如下:

Downstream

下游(downstream)主机连接到 Envoy,发送请求并或获得响应。

Upstream

上游(upstream)主机获取来自 Envoy 的链接请求和响应。

监听器

  • 除了过滤器链之外,还有一种过滤器叫监听器过滤器(Listener filters),它会在过滤器链之前执行,用于操纵连接的元数据。这样做的目的是,无需更改 Envoy 的核心代码就可以方便地集成更多功能。
  • 每个监听器都可以配置多个过滤器链(Filter Chains),监听器会根据 filter_chain_match 中的匹配条件将流量转交到对应的过滤器链,其中每一个过滤器链都由一个或多个网络过滤器Network filters)组成。这些过滤器用于执行不同的代理任务,如速率限制,TLS 客户端认证,HTTP 连接管理,MongoDB 嗅探,原始 TCP 代理等。

envoy在微服务治理中的工作环境

可以在服务旁运行,以平台无关的方式提供必要的特性,所有到服务的流量都通过 Envoy 代理,这里 Envoy 扮演的就是 Sidecar 的角色。

针对于k8s的pod来讲:

在istio中,envoy的位置:

很明显,istio中,envoy进行流量治理,更多的使用的是XDS进行配置更新,而我们知道,XDS需要有服务端来提供接口,istiod中的pilot组件则提供了xDS服务端接口的实现 。

工作原理

目前为止,我们可以知道大致的工作流程:

  • 用户端,通过创建服务治理的规则(VirtualService、DestinationRule等资源类型),存储到ETCD中
  • istio控制平面中的Pilot服务监听上述规则,转换成envoy可读的规则配置,通过xDS接口同步给各envoy
  • envoy通过xDS获取最新的配置后,动态reload,进而改变流量转发的策略

思考两个问题:

  • istio中envoy的动态配置到底长什么样子?
  • 在istio的网格内,front-tomcat访问到bill-service,流量的流向是怎么样的?

针对问题1:

每个envoy进程启动的时候,会在127.0.0.1启动监听15000端口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c istio-proxy -- bash
# netstat -nltp
# curl localhost:15000/help
# curl localhost:15000/config_dump

针对问题2:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c front-tomcat -- bash
# curl bill-service:9999

按照之前的认知,

现在为什么流量分配由5:5 变成了9:1?流量经过envoy了的处理

envoy如何接管由front-tomcat容器发出的请求流量?(istio-init

回顾iptables:

istio-init容器作用

Istio 给应用 Pod 注入的配置主要包括:

Init 容器 istio-init

Istio 在 pod 中注入的 Init 容器名为 istio-init,作用是为 pod 设置 iptables 端口转发。

我们在上面 Istio 注入完成后的 YAML 文件中看到了该容器的启动命令是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
istio-iptables -p 15001 -z 15006 -u 1337 -m REDIRECT -i '*' -x "" -b '*' -d 15090,15021,15020

Init 容器的启动入口是 istio-iptables 命令行,该命令行工具的用法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istio-iptables [flags]
  -p: 指定重定向所有 TCP 出站流量的 sidecar 端口(默认为 $ENVOY_PORT = 15001-m: 指定入站连接重定向到 sidecar 的模式,“REDIRECT” 或 “TPROXY”(默认为 $ISTIO_INBOUND_INTERCEPTION_MODE)
  -b: 逗号分隔的入站端口列表,其流量将重定向到 Envoy(可选)。使用通配符 “*” 表示重定向所有端口。为空时表示禁用所有入站重定向(默认为 $ISTIO_INBOUND_PORTS-d: 指定要从重定向到 sidecar 中排除的入站端口列表(可选),以逗号格式分隔。使用通配符“*” 表示重定向所有入站流量(默认为 $ISTIO_LOCAL_EXCLUDE_PORTS-o:逗号分隔的出站端口列表,不包括重定向到 Envoy 的端口。
  -i: 指定重定向到 sidecar 的 IP 地址范围(可选),以逗号分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量。空列表将禁用所有出站重定向(默认为 $ISTIO_SERVICE_CIDR-x: 指定将从重定向中排除的 IP 地址范围,以逗号分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量(默认为 $ISTIO_SERVICE_EXCLUDE_CIDR)。
  -k:逗号分隔的虚拟接口列表,其入站流量(来自虚拟机的)将被视为出站流量。
  -g:指定不应用重定向的用户的 GID(默认值与 -u param 相同)
  -u:指定不应用重定向的用户的 UID。通常情况下,这是代理容器的 UID(默认值是 1337,即 istio-proxy 的 UID)。
  -z: 所有进入 pod/VMTCP 流量应被重定向到的端口(默认 $INBOUND_CAPTURE_PORT = 15006)。

以上传入的参数都会重新组装成 iptables 规则,关于 Istio 中端口用途请参考 Istio 官方文档

这条启动命令的作用是:

  • 将应用容器的所有入站流量都转发到 sidecar的 15006 端口(15090 端口(Envoy Prometheus telemetry)和 15020 端口(Ingress Gateway)除外,15021(sidecar健康检查)端口)
  • 将所有出站流量都重定向到 sidecar 代理(通过 15001 端口)
  • 上述规则对id为1337用户除外,因为1337是istio-proxy自身的流量

该容器存在的意义就是让 sidecar 代理可以拦截pod所有的入站(inbound)流量以及出站(outbound)流量,这样就可以实现由sidecar容器来接管流量,进而实现流量管控。

init容器进行入站出站流量监控

因为 Init 容器初始化完毕后就会自动终止,因为我们无法登陆到容器中查看 iptables 信息,但是 Init 容器初始化结果会保留到应用容器和 sidecar 容器中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 查看front-tomcat服务的istio-proxy容器的id
$ docker ps |grep front-tomcat
6c0c6478ce2a   43e421a14aec                         "/bin/sh -c 'mkdir /…"   2 hours ago    Up 2 hours              k8s_front-tomcat_front-tomcat-v1-8687f9f845-rmlxt_default_0204ab7e-a083-4e71-9af6-dcc675ec7000_0

# 根据容器id获取front-tomcat容器在宿主机中的进程
$ docker inspect 6c0c6478ce2a|grep -i pid
            "Pid": 97369,
            "PidMode": "",
            "PidsLimit": null,
# 进入该进程的网络命名空间
$ nsenter -n --target 97369
# 查看命名空间的iptables规则
$ iptables -t nat -vnL
# PREROUTING 链:用于目标地址转换(DNAT),将所有入站 TCP 流量跳转到 ISTIO_INBOUND 链上。
Chain PREROUTING (policy ACCEPT 3879 packets, 233K bytes)
 pkts bytes target     prot opt in     out     source               destination         
 3884  233K ISTIO_INBOUND  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0  

# INPUT 链:处理输入数据包,非 TCP 流量将继续 OUTPUT 链。
Chain INPUT (policy ACCEPT 3884 packets, 233K bytes)
 pkts bytes target     prot opt in     out     source               destination  

# OUTPUT 链:将所有出站数据包跳转到 ISTIO_OUTPUT 链上。
Chain OUTPUT (policy ACCEPT 46 packets, 3926 bytes)
 pkts bytes target     prot opt in     out     source               destination
    8   480 ISTIO_OUTPUT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0
# POSTROUTING 链:所有数据包流出网卡时都要先进入POSTROUTING 链,内核根据数据包目的地判断是否需要转发出去,我们看到此处未做任何处理。
Chain POSTROUTING (policy ACCEPT 46 packets, 3926 bytes)
 pkts bytes target     prot opt in     out     source               destination

# ISTIO_INBOUND 链:将所有入站流量重定向到 ISTIO_IN_REDIRECT 链上,目的地为 150901502015021端口的流量除外,发送到以上两个端口的流量将返回 iptables 规则链的调用点,即 PREROUTING 链的后继 POSTROUTING。
Chain ISTIO_INBOUND (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15008
    0     0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15090
 3879  233K RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15021
    0     0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15020
    5   300 ISTIO_IN_REDIRECT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0 

# ISTIO_IN_REDIRECT 链:将所有入站流量跳转到本地的 15006 端口,至此成功的拦截了流量到sidecar中。
Chain ISTIO_IN_REDIRECT (3 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15006

# ISTIO_OUTPUT 链:选择需要重定向到 Envoy(即本地) 的出站流量,所有非 localhost 的流量全部转发到 ISTIO_REDIRECT。为了避免流量在该 Pod 中无限循环,所有到 istio-proxy 用户空间的流量都返回到它的调用点中的下一条规则,本例中即 OUTPUT 链,因为跳出 ISTIO_OUTPUT 规则之后就进入下一条链 POSTROUTING。如果目的地非 localhost 就跳转到 ISTIO_REDIRECT;如果流量是来自 istio-proxy 用户空间的,那么就跳出该链,返回它的调用链继续执行下一条规则(OUTPUT 的下一条规则,无需对流量进行处理);所有的非 istio-proxy 用户空间的目的地是 localhost 的流量就跳转到 ISTIO_REDIRECT。
Chain ISTIO_OUTPUT (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 RETURN     all  --  *      lo      127.0.0.6            0.0.0.0/0
    0     0 ISTIO_IN_REDIRECT  all  --  *      lo      0.0.0.0/0           !127.0.0.1            owner UID match 1337
    0     0 RETURN     all  --  *      lo      0.0.0.0/0            0.0.0.0/0            ! owner UID match 1337
    8   480 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1337
    0     0 ISTIO_IN_REDIRECT  all  --  *      lo      0.0.0.0/0           !127.0.0.1            owner GID match 1337
    0     0 RETURN     all  --  *      lo      0.0.0.0/0            0.0.0.0/0            ! owner GID match 1337
    0     0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner GID match 1337
    0     0 RETURN     all  --  *      *       0.0.0.0/0            127.0.0.1
    0     0 ISTIO_REDIRECT  all  --  *      *       0.0.0.0/0            0.0.0.0/0

# ISTIO_REDIRECT 链:将所有流量重定向到 Sidecar(即本地) 的 15001 端口。
Chain ISTIO_REDIRECT (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15001
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c istio-proxy -- bash
istio-proxy@front-tomcat-v1-8687f9f845-rmlxt:/$ netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:8005          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:15021           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 0.0.0.0:15021           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:15090           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 0.0.0.0:15090           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 127.0.0.1:15000         0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 127.0.0.1:15004         0.0.0.0:*               LISTEN      1/pilot-agent       
tcp        0      0 0.0.0.0:15006           0.0.0.0:*               LISTEN      16/envoy            
tcp        0      0 0.0.0.0:15006           0.0.0.0:*               LISTEN      16/envoy            
tcp6       0      0 :::15020                :::*                    LISTEN      1/pilot-agent

说明pod内的出站流量请求被监听在15001端口的envoy的进程接收到,进而就走到了envoy的Listener -> route -> cluster -> endpoint 转发流程。

问题就转变为:如何查看envoy的配置,跟踪转发的过程?

envoy流量转发跟踪分析

我们知道,envoy的配置非常复杂,直接在config_dump里去跟踪xDS的过程非常繁琐。因此istio提供了调试命令,方便查看envoy的流量处理流程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl proxy-config -h

比如,通过如下命令可以查看envoy的监听器:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 查看15001的监听
$ istioctl proxy-config listener front-tomcat-v1-8687f9f845-rmlxt --port 15001 -ojson
# virtualOutbound的监听不做请求处理,useOriginalDst: true, 直接转到原始的请求对应的监听器中

# 查看访问端口是9999的监听器
$ istioctl proxy-config listener front-tomcat-v1-8687f9f845-rmlxt --port 9999 -ojson
...
    {
        "name": "0.0.0.0_9999",
        "address": {
            "socketAddress": {
                "address": "0.0.0.0",
                "portValue": 9999
            }
        },
        "filterChains": [
            {
                "filterChainMatch": {
                    "applicationProtocols": [
                        "http/1.0",
                        "http/1.1",
                        "h2c"
                    ]
                },
                "filters": [
                    {
                        "name": "envoy.filters.network.http_connection_manager",
                        "typedConfig": {
                            "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
                            "statPrefix": "outbound_0.0.0.0_9999",
                            "rds": {
                                "configSource": {
                                    "ads": {},
                                    "resourceApiVersion": "V3"
                                },
                                "routeConfigName": "9999"
                            },
...

envoy收到请求后,会转给监听器进行处理请求,监听器先匹配address和port和socket都一致的Listener,如果没找到再找port一致,address==0.0.0.0的Listener

发现istio会为网格内的Service Port创建名为0.0.0.0_<Port>的虚拟监听器,本例中为0.0.0.0_9999

envoy的15001端口收到请求后,直接转到了0.0.0.0_9999,进而转到了"routeConfigName": "9999",即9999这个route中。

下面,看下route的内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl pc route front-tomcat-v1-8687f9f845-rmlxt --name 9999
NOTE: This output only contains routes loaded via RDS.
NAME     DOMAINS          MATCH     VIRTUAL SERVICE
9999     bill-service     /*        vs-bill-service.default

# 发现了前面创建的virtual service
$ istioctl pc route front-tomcat-v1-8687f9f845-rmlxt --name 9999 -ojson
[
    {
        "name": "9999",
        "virtualHosts": [
            {
                "name": "allow_any",
                "domains": [
                    "*"
                ],
                "routes": [
                    {
                        "name": "allow_any",
                        "match": {
                            "prefix": "/"
                        },
                        "route": {
                            "cluster": "PassthroughCluster",
                            "timeout": "0s",
                            "maxGrpcTimeout": "0s"
                        }
                    }
                ],
                "includeRequestAttemptCount": true
            },
            {
                "name": "bill-service.default.svc.cluster.local:9999",
                "domains": [
                    "bill-service.default.svc.cluster.local",
                    "bill-service.default.svc.cluster.local:9999",
                    "bill-service",
                    "bill-service:9999",
                    "bill-service.default.svc.cluster",
                    "bill-service.default.svc.cluster:9999",
                    "bill-service.default.svc",
                    "bill-service.default.svc:9999",
                    "bill-service.default",
                    "bill-service.default:9999",
                    "192.168.18.251",
                    "192.168.18.251:9999"
                ],
                "routes": [
                    {
                        "name": "bill-service-route",
                        "match": {
                            "prefix": "/"
                        },
                        "route": {
                            "weightedClusters": {
                                "clusters": [
                                    {
                                        "name": "outbound|9999|v1|bill-service.default.svc.cluster.local",
                                        "weight": 90
                                    },
                                    {
                                        "name": "outbound|9999|v2|bill-service.default.svc.cluster.local",
                                        "weight": 10
                                    }
                                ]
                            },
...

满足访问domains列表的会优先匹配到,我们访问的是192.168.18.251:9999,因此匹配bill-service.default.svc.cluster.local:9999这组虚拟hosts,进而使用到基于weight的集群配置。

我们看到,流量按照预期的配置进行了转发:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
90% -> outbound|9999|v1|bill-service.default.svc.cluster.local
10% -> outbound|9999|v2|bill-service.default.svc.cluster.local

下面,看一下cluster的具体内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl pc cluster front-tomcat-v1-8687f9f845-rmlxt --fqdn bill-service.default.svc.cluster.local -ojson
...
        "name": "outbound|9999|v1|bill-service.default.svc.cluster.local",
        "type": "EDS",
        "edsClusterConfig": {
            "edsConfig": {
                "ads": {},
                "resourceApiVersion": "V3"
            },
            "serviceName": "outbound|9999|v1|bill-service.default.svc.cluster.local"
        },
...

我们发现,endpoint列表是通过eds获取的,因此,查看endpoint信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl pc endpoint front-tomcat-v1-8687f9f845-rmlxt  --cluster 'outbound|9999|v1|bill-service.default.svc.cluster.local' -ojson
[
    {
        "name": "outbound|9999|v1|bill-service.default.svc.cluster.local",
        "addedViaApi": true,
        "hostStatuses": [
            {
                "address": {
                    "socketAddress": {
                        "address": "172.7.100.3",
                        "portValue": 80
                    }
                },
...

目前为止,经过envoy的规则,流量从front-tomcat的pod中知道要发往10.244.0.7:80 这个pod地址。前面提到过,envoy不止接管出站流量,入站流量同样会接管。

下面看下流量到达bill-service-v1的pod后的处理:

先回顾前面的iptables规则,除特殊情况以外,所有的出站流量被监听在15001端口的envoy进程拦截处理,同样的,分析bill-service-v1的iptables规则可以发现,监听在15006端口的envoy进程通过在PREROUTING链上添加规则,同样将进入pod的入站流量做了拦截。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# PREROUTING 链:用于目标地址转换(DNAT),将所有入站 TCP 流量跳转到 ISTIO_INBOUND 链上。
Chain PREROUTING (policy ACCEPT 148 packets, 8880 bytes)
 pkts bytes target     prot opt in     out     source               destination
  148  8880 ISTIO_INBOUND  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

# INPUT 链:处理输入数据包,非 TCP 流量将继续 OUTPUT 链。
Chain INPUT (policy ACCEPT 148 packets, 8880 bytes)
 pkts bytes target     prot opt in     out     source               destination

# ISTIO_INBOUND 链:将所有入站流量重定向到 ISTIO_IN_REDIRECT 链上,目的地为 150901502015021端口的流量除外,发送到以上两个端口的流量将返回 iptables 规则链的调用点,即 PREROUTING 链的后继 POSTROUTING。
Chain ISTIO_INBOUND (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15008
    0     0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15090
  143  8580 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15021
    5   300 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15020
    0     0 ISTIO_IN_REDIRECT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

# ISTIO_IN_REDIRECT 链:将所有入站流量跳转到本地的 15006 端口,至此成功的拦截了流量到sidecar中。
Chain ISTIO_IN_REDIRECT (3 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15006

15006端口是一个名为 virtualInbound虚拟入站监听器,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl pc l bill-service-v1-59b4f4ccc7-qvhw6.default --port 15006 -ojson
"name": "envoy.filters.network.http_connection_manager",
"typedConfig": {
    "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager",
    "statPrefix": "inbound_0.0.0.0_80",
    "routeConfig": {
        "name": "inbound|80||",
        "virtualHosts": [
            {
                "name": "inbound|http|9999",
                "domains": [
                    "*"
                ],
                "routes": [
                    {
                        "name": "default",
                        "match": {
                            "prefix": "/"
                        },
                        "route": {
                            "cluster": "inbound|80||",
                            "timeout": "0s",
                            "maxStreamDuration": {
                                "maxStreamDuration": "0s",
                                "grpcTimeoutHeaderMax": "0s"
                            }
                        },
                        "decorator": {
                            "operation": "bill-service.default.svc.cluster.local:9999/*"
                        }
                    }
                ]
            }
        ],
        "validateClusters": false

相比于VirtualOutboundvirtualInbound 不会再次转给别的虚拟监听器,而是直接由本监听器的filterChains处理,本例中我们可以发现本机目标地址为80的http请求,转发到了inbound|9999|http|bill-service.default.svc.cluster.local这个集群中。

查看该集群的信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ istioctl pc cluster bill-service-v1-59b4f4ccc7-qvhw6.default -h
$ istioctl pc cluster bill-service-v1-59b4f4ccc7-qvhw6.default  --fqdn "inbound|80||" -ojson
[
    {
        "name": "inbound|80||",
        "type": "ORIGINAL_DST",
        "connectTimeout": "10s",
        "lbPolicy": "CLUSTER_PROVIDED",
        "circuitBreakers": {
            "thresholds": [
                {
                    "maxConnections": 4294967295,
                    "maxPendingRequests": 4294967295,
                    "maxRequests": 4294967295,
                    "maxRetries": 4294967295,
                    "trackRemaining": true
                }
            ]
        },
        "cleanupInterval": "60s",
        "upstreamBindConfig": {
            "sourceAddress": {
                "address": "127.0.0.6",
                "portValue": 0
            }
        },
        "metadata": {
            "filterMetadata": {
                "istio": {
                    "services": [
                        {
                            "host": "bill-service.default.svc.cluster.local",
                            "name": "bill-service",
                            "namespace": "default"
                        }
                    ]
                }
            }
        }
    }
]

istio小知识

同一个Pod,不同的表现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c front-tomcat bash
# curl bill-service:9999

$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c istio-proxy bash
# curl bill-service:9999

可以发现,在front-tomcat容器中的访问请求,是受到我们设置的 9:1的流量分配规则限制的,但是istio-proxy容器中的访问是不受限制的。

istio-proxy自身,发起的往192.168.18.251的请求,使用的用户是 uid=1337(istio-proxy),因此不会被istio-init初始化的防火墙规则拦截,可以直接走pod的网络进行通信。

集群内的Service都相应的创建了虚拟出站监听器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ kubectl exec -ti front-tomcat-v1-8687f9f845-rmlxt -c front-tomcat bash
# curl sonarqube.jenkins:9000

$ istioctl pc l front-tomcat-v1-8687f9f845-rmlxt --port 9000 
ADDRESS      PORT MATCH     DESTINATION
192.168.18.33 9000 App: HTTP Route: sonarqube.jenkins.svc.cluster.local:9000
192.168.18.33 9000 ALL       Cluster: outbound|9000||sonarqube.jenkins.svc.cluster.local

$ istioctl pc r front-tomcat-v1-8687f9f845-rmlxt --name 'sonarqube.jenkins.svc.cluster.local:9000'

$ istioctl pc ep front-tomcat-v1-8687f9f845-rmlxt --cluster 'outbound|9000||sonarqube.jenkins.svc.cluster.local'

virtualOutBound 15001 —> virtial listener 192.168.18.33_9000 —> route sonarqube.jenkins.svc.cluster.local:9000 —> cluster outbound|9000||sonarqube.jenkins.svc.cluster.local —> 192.168.18.33:9000

istio服务网格内,流量请求完全绕过了kube-proxy组件

通过上述流程调试,我们可以得知,front-tomcat中访问bill-service:9999,流量是没有用到kube-proxy维护的宿主机中的iptables规则的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Istio系列二:Envoy组件分析
Envoy是Istio数据平面核心组件,在Istio架构中起着非常重要的作用,本文首先介绍Envoy的基本概念及工作流程,再从Istio的设计角度出发,对Envoy在Istio中如何部署及如何对入站出站流量进行代理转发及流量劫持进行具体分析,最后通过实验加以验证。
绿盟科技研究通讯
2019/12/11
4.1K0
Istio系列二:Envoy组件分析
Istio 网络:深入了解流量和架构
像 Istio 这样的服务网格项目为我们的架构引入了许多功能和优势,包括更安全地管理集群微服务之间的流量、服务发现、请求路由以及服务之间的可靠通信。
Luga Lee
2021/12/10
1.2K0
Istio 网络:深入了解流量和架构
Istio流量管理快速入门
后台账单服务更新v2版本,前期规划90%的流量访问v1版本,接入10%的流量到v2版本
王先森sec
2023/04/24
3250
Istio流量管理快速入门
Istio 支持双栈 Kubernetes 集群
作者:张怀龙 - Intel, 徐贺杰 - Intel, 丁少君 - Intel, Jacob Delgado - F5, 蔡迎春 - 前 F5
灵雀云
2023/09/07
3180
Istio 支持双栈 Kubernetes 集群
初探 Istio Ambient 模式
Ambient 是 Istio 刚刚宣布支持的一种新的数据面模式,在本篇文章中,我们将尝试安装 Istio 的 ambient 模式,并采用 bookinfo demo 来体验 ambient 提供的 L4 和 L7 能力。
赵化冰
2022/09/28
7740
初探 Istio Ambient 模式
istio 常见异常分析
istio 支持多平台,不过 Istio 和 k8s 的兼容性是最优的,不管是设计理念,核心团队还是社区, 都有一脉相承的意思。但 istio 和 k8s 的适配并非完全没有冲突, 一个典型问题就是 istio 需要 k8s service 按照协议进行端口命名(port naming)。
钟华
2020/03/09
3.7K1
认真聊一次iptables和netfilter,简单过下istio route
上一篇文章本意是给大家一个新的视角来研究 istio route 的细节。不过后台不少同学私信我说,一直没有办法理解 iptables ,也就不想细看那篇文章了。二哥一看就慌了,为了让大家能安心地研究那篇文章,我就先来聊聊 iptables ,准确地说我们需要聊的是 netfilter 。
LanceZhang
2022/10/28
1K0
认真聊一次iptables和netfilter,简单过下istio route
openshift 4.3 Istio的搭建(istio 系列一)
注:不建议使用openshift 1.11(即kubernetes 3.11)安装istio,可能会出现如下兼容性问题,参见此issue
charlieroro
2020/05/20
1.1K0
Mesh6# gRPC服务通过Istio网格通信
本文通过gRCP服务消费方mesha和gRPC服务提供方meshb,验证其部署在Istio网格的通信过程。通过该示例可以将外部注册中心接入网格,不再困难。
瓜农老梁
2021/11/17
1K0
Mesh6# gRPC服务通过Istio网格通信
《云原生服务网格Istio》第2章 Istio架构概述
第2章 Istio架构概述 2.1 Istio的工作机制 分为控制面和数据面两部分。可以看到,控制面主要包括Pilot、Mixer、Citadel等服务组件;数据面由伴随每个应用程序部署的代理程序Envoy组成,执行针对应用程序的治理逻辑 即观察frontend服务对 forecast 服务进行一次访问时,在 Istio 内部都发生了什么,以及 Istio 的各个组件是怎样参与其中的,分别做了哪些事情 虽然从时序上来讲,控制面的配置在前,数据面执行在后,但为了便于理解,在下面介绍这些动作时以数据面上的数据流
yeedomliu
2019/10/11
1.6K0
《云原生服务网格Istio》第2章 Istio架构概述
mac 上学习k8s系列(41)istio 注入
在学习完istio的安装和基本使用后mac 上学习k8s系列(32)istio part II,我们开始学习下isto的注入原理,首先准备环境
golangLeetcode
2022/08/02
5790
Istio中的流量配置
Istio的数据面会在pod中注入两个容器:istio-init和istio-proxy。
charlieroro
2020/09/22
2.4K0
Istio中的流量配置
Istio流量管理之请求路由分析
前面我们了解了 Gateway 和 VirtualService 资源对象的作用,以及它们是如何影响 Envoy 的配置的,那么这些资源对象又是如何影响流量的呢?通过 Istio 如何实现流量管理的呢?
我是阳明
2023/11/09
4710
Istio流量管理之请求路由分析
Istio: 服务网格领域的新王者
Istio 是当前 Service Mesh 领域最完善的解决方案,同源自 kubernetes 项目团队。
钟华
2019/02/12
4.4K0
Istio流量管理实现机制深度解析-基于1.4.0更新
基于1.4.0更新,和最新版本1.6.0的架构基本相同,具有较大参考价值。 目录 前言 Pilot高层架构 统一的服务模型 标准数据面 API 业务DSL语言 Istio流量管理相关组件 控制面组件 数据面组件 命令行工具 数据面标准API 基本概念和术语 XDS服务接口 XDS服务接口的最终一致性考虑 ADS聚合发现服务 Bookinfo 示例程序分析 Bookinfo程序结构 xDS接口调试方法 Envoy启动过程分析 Envoy配置分析 Bookinfo端到端调用分析 小结 参考资料 前言 Is
腾讯云原生
2020/09/10
1.3K1
打造企业级自动化运维平台系列(十六):服务网格 Istio 详解
官方解释:An open platform to connect, secure, control and observe services.
民工哥
2024/01/18
5560
打造企业级自动化运维平台系列(十六):服务网格 Istio 详解
Envoy请求流程源码解析(一)|流量劫持
Envoy 是一款面向 Service Mesh 的高性能网络代理服务。它与应用程序并行运行,通过以平台无关的方式提供通用功能来抽象网络。当基础架构中的所有服务流量都通过 Envoy 网格时,通过一致的可观测性,很容易地查看问题区域,调整整体性能。
灵雀云
2022/03/03
1.4K0
Envoy请求流程源码解析(一)|流量劫持
Istio 1.1 中的 Sidecar 资源
缺省情况下,Istio 在 Pod 创建之前将 istio-init 和 istio-proxy 注入到 Pod 之中,使用 istio-init 对 iptables 进行初始化,将业务容器的流量拦截到 istio-proxy,从而完成通信控制权的移交工作——应用容器的自发 Ingress 和 Egress 通信,都从 Envoy 中留过,Envoy 作为数据平面,需要接受来自控制面的 xDS 指令,据此作出通信决策。
崔秀龙
2019/07/23
1.4K0
istio请求路由分析
•httpbin访问sleep:80端口•iptables拦截转发到15001 的15001端口
有点技术
2020/07/22
1.6K0
Istio源码解析4-Istio中pilot代理的启动
上一篇中我们介绍了EnvoyXdsServer的结构以及EnvoyXdsServer的启动流程、怎么与envoy客户端建立连接,当Istio CRD配置、K8s服务事件变化后,怎么监控到事件并把相关配置传到EnvoyXdsServer的channel中,如何进行防抖及推送,最后把事件传到每个客户端的connection中。这里我们介绍下envoy客户端的启动过程以及envoy如何与istiod建立连接。
CNCF
2022/11/28
8350
Istio源码解析4-Istio中pilot代理的启动
推荐阅读
相关推荐
Istio系列二:Envoy组件分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文