分析用户请求K8S里ingress-nginx提供的ingress流量路径

前言

本文是个人的小小见解,欢迎大佬指出我文章的问题,一起讨论进步~

我个人的疑问点

  1. 进入的流量是如何自动判断进入iptables的四表?
  2. k8s nodeport模式的原理?

一 本机环境介绍

节点名节点IPK8S版本CNI插件
Master192.168.44.1411.29.2calico(IPIP模式)
k8s-slave192.168.44.1421.29.2calico(IPIP模式)

二 容器介绍

ingress-nginx与 jupyter分别在2台服务器上

节点名节点IP容器名容器IPsvc地址
master192.168.44.141ingress-nginx-controller-556d4fff79-9jdmq172.16.219.89NodePort 10.100.104.51 80:80/TCP,443:443/TCP
k8s-slave192.168.44.142jupyter-deployment-57454c6795-xpgfk172.16.64.206ClusterIP 10.97.82.53 8888/TCP

三 请求方介绍

本地IP地址 10.250.0.34,通过添加/etc/hosts解析域名。因为ingress-nginx的SVC是Nodeport使用的是本机 80与443端口,所以访问 192.168.44.141 的80 443端口即可访问域名

192.168.44.141 						nginx.jcrose.com

四 请求链路分析

开始分析iptables iptables -nL -t nat

iptables是按照规则从上至下逐条匹配,开始分析Prerouting

流入的报文在路由决策

raw.PREROUTING -> mangle.PREROUTING -> nat.PREROUTING -> mangle.FORWARD -> filter.FORWARD -> mangle.POSTROUTING -> nat.POSTROUTING
  • raw.PREROUTING:设置流量标记,跳过连接跟踪(可选)。
  • mangle.PREROUTING:修改流量属性或标记流量(如 QoS 或 TTL)。
  • nat.PREROUTING:目标地址转换(DNAT),将流量重定向到正确的后端服务。
  • mangle.FORWARD:在转发流量时修改流量属性(如标记),用于流量控制。
  • filter.FORWARD:过滤流量,决定是否允许流量继续转发(基于安全策略)。
  • mangle.POSTROUTING:在出站流量时修改流量属性(如标记、TTL)。
  • nat.POSTROUTING:源地址转换(SNAT),确保流量从正确的 IP 地址发送出去。

最重要的2个部分 nat.PREROUTING 目标地址转换(DNAT),nat.POSTROUTING源地址转换(SNAT)。

4.1 Nat.PREROUTING链

IP: 192.168.44.141:80

host: jupyter.jcrose.com

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
cali-PREROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* cali:6gwbT8clXdHdC1b1 */
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
CNI-HOSTPORT-DNAT  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

4.1.1 cali-PREROUTING规则

这里使用了 cali-fip-dnat(Calico 使用 IP-in-IP 或 VXLAN 隧道模式则不会使用该链)

Chain cali-PREROUTING (1 references)
target     prot opt source               destination         
cali-fip-dnat  all  --  0.0.0.0/0            0.0.0.0/0            /* cali:r6XmIziWUJsdOK6Z */

4.1.2 KUBE-SERVICES规则

规则如下

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
.............................         
KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
.............................

分析下面Chain KUBE-SERVICES的4条规则

Chain KUBE-SERVICES (2 references)
target     prot opt source               destination         
RETURN     all  --  127.0.0.0/8          0.0.0.0/0           
KUBE-MARK-MASQ  all  -- !172.16.0.0/12        0.0.0.0/0            /* Kubernetes service cluster ip + port for masquerade purpose */ match-set KUBE-CLUSTER-IP dst,dst
KUBE-NODE-PORT  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL	# 这里只有当请求的node IP是本机才会查询
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst
① RETURN规则

返回一切来自于 127.0.0.0本地请求

② KUBE-MARK-MASQ规则

match-set KUBE-CLUSTER-IP dst,dst 需要匹配ipset里面的地址是否存在。

因为 KUBE-CLUSTER-IP 是用于访问集群内部的IP而不是nodeport,因此此条规则也没有,跳过

Name: KUBE-CLUSTER-IP
Type: hash:ip,port
Revision: 6
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xd824d3cd
Size in memory: 536
References: 3
Number of entries: 7
Members:
10.97.82.53,tcp:8888
10.96.0.2,udp:53
10.96.0.2,tcp:53
10.100.104.51,tcp:80
10.100.104.51,tcp:443
10.108.32.102,tcp:443
10.96.0.1,tcp:443


Chain KUBE-MARK-MASQ (3 references)
target     prot opt source               destination         
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
③ KUBE-NODE-PORT规则

规则如下

Chain KUBE-SERVICES (2 references)
............
KUBE-NODE-PORT  all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL	# 这里只有当请求的node IP是本机才会查询
.................

因为本机IP为 192.168.44.141,请求过来的IP满足,因此进入下一条链 KUBE-NODE-PORT

Chain KUBE-NODE-PORT (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  tcp  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes nodeport TCP port for masquerade purpose */ match-set KUBE-NODE-PORT-TCP dst

KUBE-NODE-PORT-TCP 的ipset规则如下

root@master:~# ipset --list KUBE-NODE-PORT-TCP
Name: KUBE-NODE-PORT-TCP
Type: bitmap:port
Revision: 3
Header: range 0-65535
Size in memory: 8264
References: 1
Number of entries: 2
Members:
80
443

match-set KUBE-NODE-PORT-TCP dst 匹配 ipset的 KUBE-NODE-PORT-TCP,如果匹配到了则进入下一步

KUBE-MARK-MASQ

这里对经过的流量打上标签 0x4000 继续在当前链中向下匹配下一个规则

Chain KUBE-MARK-MASQ (3 references)
target     prot opt source               destination         
MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
④ ACCEPT规则(在上一步对流量打了标记之后来到这里)
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            match-set KUBE-CLUSTER-IP dst,dst

KUBE-CLUSTER-IP的ipset规则如下

root@master:~# ipset --list KUBE-CLUSTER-IP
Name: KUBE-CLUSTER-IP
Type: hash:ip,port
Revision: 6
Header: family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xd824d3cd
Size in memory: 536
References: 3
Number of entries: 7
Members:
10.97.82.53,tcp:8888
10.96.0.2,udp:53
10.96.0.2,tcp:53
10.100.104.51,tcp:80
10.100.104.51,tcp:443
10.108.32.102,tcp:443
10.96.0.1,tcp:443

没有找到相关目标:192.168.44.141的规则,所以跳过这条规则

4.1.3 CNI-HOSTPORT-DNAT

这里去 CNI-DN-50c24a55650b462c3ecc9 匹配 80与443端口

Chain CNI-HOSTPORT-DNAT (2 references)
target     prot opt source               destination         
CNI-DN-50c24a55650b462c3ecc9  tcp  --  0.0.0.0/0            0.0.0.0/0            /* dnat name: "k8s-pod-network" id: "f5c87b58cf224ed0b1ce05b973b73ab23ffdd9c5f92904961b08e7b09a8e6373" */ multiport dports 80,443
① CNI-DN-50c24a55650b462c3ecc9规则

这里有4个打标记 0x2000 的规则,这里不一一解释,只分析 2个DNAT的规则

Chain CNI-DN-50c24a55650b462c3ecc9 (1 references)
target     prot opt source               destination         
CNI-HOSTPORT-SETMARK  tcp  --  172.16.219.89        0.0.0.0/0            tcp dpt:80		#MARK  172.16.219.71   MARK or 0x2000
CNI-HOSTPORT-SETMARK  tcp  --  127.0.0.1            0.0.0.0/0            tcp dpt:80		#MARK  172.16.219.71   MARK or 0x2000
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.16.219.89:80
CNI-HOSTPORT-SETMARK  tcp  --  172.16.219.89        0.0.0.0/0            tcp dpt:443	#MARK  172.16.219.71   MARK or 0x2000
CNI-HOSTPORT-SETMARK  tcp  --  127.0.0.1            0.0.0.0/0            tcp dpt:443	#MARK  172.16.219.71   MARK or 0x2000
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443 to:172.16.219.89:443

这2个DNAT把来源的目标:192.168.44.141:80 (请求头 http://jupyter.jcrose.com) 修改为目标 172.16.219.89:80(ingress-nginx的 pod IP地址)

五 veth设备介绍

  1. Pod 流量的目的地是同一节点上的 Pod。
  2. Pod 流量的目的地是在不同节点上的 Pod。

整个工作流依赖于虚拟接口对和网桥,下面先来了解一下这部分的内容。

为了让一个 Pod 与其他 Pod 通信,它必须先访问节点的根命名空间。

通过虚拟以太网对来实现 Pod 和根命名空间的连接。

这些虚拟接口设备(veth 中的 v)连接并充当两个命名空间之间的隧道。

查看master节点上的网卡情况

ip a

3: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default 
    link/ether d6:37:7a:8c:62:e2 brd ff:ff:ff:ff:ff:ff
    inet 10.96.0.2/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.97.82.53/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.96.0.1/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.100.104.51/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever
    inet 10.108.32.102/32 scope global kube-ipvs0
       valid_lft forever preferred_lft forever

在 Calico 的 IPIP 模式 中,kube-ipvs0tunl0eth0 网卡分别有不同的角色,它们与集群中的流量转发和路由机制密切相关。下面我会解释它们各自的作用以及它们之间的关系。

5.1 kube-ipvs0 网卡

  • 作用kube-ipvs0 是在 IPVS 模式 下由 kube-proxy 创建的虚拟网卡。它用于实现 Kubernetes 服务的负载均衡。它会处理从集群外部(或其他 Pod)流向服务虚拟 IP(VIP)的流量,并将这些流量根据负载均衡规则转发到服务的后端 Pod。

  • 工作原理

    • 在 Kubernetes 中,kube-proxy 使用 IPVS(IP Virtual Server) 来管理负载均衡。kube-ipvs0 是用来承载这些负载均衡规则的网络设备,流量经过 kube-ipvs0 时会被转发到相应的后端 Pod。
    • kube-ipvs0 会将流量从服务的虚拟 IP(VIP)转发到实际的 Pod IP(如 172.16.64.206)。

5.2 tunl0 网卡

  • 作用tunl0 是 Calico 在启用 IPIP 模式 时创建的虚拟网卡,用于支持 IPIP 隧道。当 Pod 需要通过 IPIP 隧道跨节点通信时,流量会通过 tunl0 网卡进行封装。

  • 工作原理

    • 在 Calico IPIP 模式下,当流量从一个节点上的 Pod 发往另一个节点上的 Pod 时,流量会通过 tunl0 网卡进行封装。
    • tunl0 网卡会将流量封装为 IPIP 包,将其发送到目标节点的 tunl0 网卡。在目标节点上,calico-node 会解封装这个 IPIP 包,将流量转发到目标 Pod。
    • tunl0 网卡本身并不用于直接接收或发送应用层数据流量,它只是一个传输层的封装/解封装网卡。

5.3 eth0 网卡

  • 作用eth0 是 Kubernetes 节点上的 物理网卡,用于与集群外部或其他节点进行通信。

  • 工作原理

    • eth0 是节点与外部网络的主要接口。它用于处理来自外部网络的流量或集群内的普通数据流量。
    • 如果 Pod 在同一节点上,它们的流量通常通过 eth0 进行路由,而不需要经过 IPIP 隧道。
    • eth0 也可能用于与其他节点之间的通信(比如集群外部的访问请求),但是这取决于集群的路由策略和 Calico 配置。

5.4 这三者之间的关系

  1. 服务流量的转发(kube-ipvs0

    • 当 Pod 或外部请求访问某个服务的虚拟 IP(例如 10.97.82.53),流量会首先到达节点上的 kube-ipvs0 网卡。
    • kube-ipvs0 根据 IPVS 规则将流量转发到后端 Pod 的真实 IP(如 172.16.64.206)。这个转发过程是在同一节点内进行的,不需要 IPIP 隧道。
  2. 跨节点的 Pod 通信(tunl0

    • 如果目标 Pod 位于 不同节点,流量就需要通过 IPIP 隧道 进行跨节点传输。这时,tunl0 网卡会参与流量的封装。
    • 例如,流量从 ingress-nginx-controller Pod 发出,目标 Pod 在其他节点,流量会通过 tunl0 封装为 IPIP 包,通过节点的 eth0 网卡发送到目标节点。在目标节点,tunl0 解封装流量并将其转发给目标 Pod。
  3. 物理节点通信(eth0

    • eth0 是用于节点之间的通信(比如节点间的路由和外部通信)。
    • 对于 IPIP 模式下的跨节点流量,eth0 作为物理网络接口用于承载封装的 IPIP 流量,帮助传输流量到目标节点。

5.5 流量路径示例

ingress-nginx-controller Pod 中,流量访问服务 10.97.82.53:8888,目标 Pod IP 是 172.16.64.206:8888,并且目标 Pod 位于 不同节点

  1. 流量经过 kube-ipvs0

    • 请求首先到达 kube-ipvs0 网卡,kube-proxy 将流量从服务虚拟 IP(10.97.82.53)转发到后端 Pod IP(172.16.64.206)。
  2. 流量需要跨节点传输,进入 tunl0 隧道

    • 由于目标 Pod 位于另一个节点,calico-node 在源节点通过 tunl0 网卡将流量封装为 IPIP 包。
  3. 流量通过 eth0 传输到目标节点

    • 封装后的 IPIP 包通过源节点的 eth0 网卡发送到目标节点。
  4. 目标节点通过 tunl0 解封装流量并转发给目标 Pod

    • 在目标节点,calico-node 通过 tunl0 解封装 IPIP 包,并将流量转发(ARP)目标 Pod 172.16.64.206:8888

5.6 总结

  • kube-ipvs0:由 kube-proxy 创建,负责处理服务虚拟 IP 的负载均衡,将流量转发到后端 Pod。
  • tunl0:由 Calico 创建,负责在跨节点通信时封装和解封装 IPIP 包,确保流量能够穿越节点之间的隧道。
  • eth0:物理网卡,用于节点间的通信,承载封装后的 IPIP 包并将流量传输到目标节点(ARP)。

它们之间的关系是:kube-ipvs0 负责服务负载均衡,tunl0 负责 IPIP 隧道的封装与解封装,而 eth0 作为物理网卡用于在节点之间传输流量。

需要跨节点的时候,需要进行tunl0进行封包

1.png

六 ingress-nginx容器处理流量

容器 ingress-nginx-controller-556d4fff79-9jdmq

IP 172.16.219.89收到请求

进入容器 查看 nginx location规则找到 目标域名 jupyter.jcrose.com

kubectl exec -it ingress-nginx-controller-556d4fff79-9jdmq -n ingress-nginx -- cat /etc/nginx/nginx.conf

server jupyter.jcrose.com 部分指明了 namespace,service_name,service_port

        ## start server jupyter.jcrose.com
        server {
                server_name jupyter.jcrose.com ;

                listen 80  ;
                listen [::]:80  ;
                listen 443  ssl http2 ;
                listen [::]:443  ssl http2 ;

                set $proxy_upstream_name "-";

                ssl_certificate_by_lua_block {
                        certificate.call()
                }

                location / {

                        set $namespace      "default";
                        set $ingress_name   "demo-jupyter";
                        set $service_name   "jupyter-service";
                        set $service_port   "8888";
                        set $location_path  "/";
                        set $global_rate_limit_exceeding n;

                        rewrite_by_lua_block {
                                lua_ingress.rewrite({
                                        force_ssl_redirect = false,
                                        ssl_redirect = true,
                                        force_no_ssl_redirect = false,
                                        preserve_trailing_slash = false,
                                        use_port_in_redirects = false,
                                        global_throttle = { namespace = "", limit = 0, window_size = 0, key = { }, ignored_cidrs = { } },
                                })
                                balancer.rewrite()
                                plugins.run()
                        }

                        # be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any
                        # will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
                        # other authentication method such as basic auth or external auth useless - all requests will be allowed.
                        #access_by_lua_block {
                        #}

                        header_filter_by_lua_block {
                                lua_ingress.header()
                                plugins.run()
                        }

                        body_filter_by_lua_block {
                                plugins.run()
                        }

                        log_by_lua_block {
                                balancer.log()

                                monitor.call()

                                plugins.run()
                        }

                        port_in_redirect off;

                        set $balancer_ewma_score -1;
                        set $proxy_upstream_name "default-jupyter-service-8888";
                        set $proxy_host          $proxy_upstream_name;
                        set $pass_access_scheme  $scheme;

                        set $pass_server_port    $server_port;

                        set $best_http_host      $http_host;
                        set $pass_port           $pass_server_port;

                        set $proxy_alternative_upstream_name "";

                        client_max_body_size                    1m;

                        proxy_set_header Host                   $best_http_host;

                        # Pass the extracted client certificate to the backend

                        # Allow websocket connections
                        proxy_set_header                        Upgrade           $http_upgrade;

                        proxy_set_header                        Connection        $connection_upgrade;

                        proxy_set_header X-Request-ID           $req_id;
                        proxy_set_header X-Real-IP              $remote_addr;

                        proxy_set_header X-Forwarded-For        $remote_addr;

                        proxy_set_header X-Forwarded-Host       $best_http_host;
                        proxy_set_header X-Forwarded-Port       $pass_port;
                        proxy_set_header X-Forwarded-Proto      $pass_access_scheme;
                        proxy_set_header X-Forwarded-Scheme     $pass_access_scheme;

                        proxy_set_header X-Scheme               $pass_access_scheme;

                        # Pass the original X-Forwarded-For
                        proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;

                        # mitigate HTTPoxy Vulnerability
                        # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
                        proxy_set_header Proxy                  "";

                        # Custom headers to proxied server

                        proxy_connect_timeout                   5s;
                        proxy_send_timeout                      60s;
                        proxy_read_timeout                      60s;

                        proxy_buffering                         off;
                        proxy_buffer_size                       4k;
                        proxy_buffers                           4 4k;

                        proxy_max_temp_file_size                1024m;

                        proxy_request_buffering                 on;
                        proxy_http_version                      1.1;

                        proxy_cookie_domain                     off;
                        proxy_cookie_path                       off;

                        # In case of errors try the next upstream server before returning an error
                        proxy_next_upstream                     error timeout;
                        proxy_next_upstream_timeout             0;
                        proxy_next_upstream_tries               3;

                        proxy_pass http://upstream_balancer;

                        proxy_redirect                          off;

                }

        }
        ## end server jupyter.jcrose.com

七 ingress-nginx容器请求流量

在nginx location获取到的数据如下

       set $namespace      "default";
       set $ingress_name   "demo-jupyter";
       set $service_name   "jupyter-service";
       set $service_port   "8888";

发送的请求

jupyter-service.default.svc.cluster.local:8888

7.1 由coredns获取到 ip地址

服务名方向节点IPSVC地址端口容器IP
ingress-nginx-controller-556d4fff79-9jdmq源地址192.168.44.14110.100.104.5180(本次使用的)172.16.219.89(本次使用的)
jupyter-deployment-57454c6795-xpgfk目标地址192.168.44.14210.97.82.53(本次使用的)8888172.16.64.206

来源: 172.16.219.89:80(ingress-nginx的 pod ip以及端口)

请求的地址 10.97.82.53:8888(jupyter的svc地址)

7.2 查看该容器的路由表

ingress-nginx-controller-556d4fff79-9jdmq:/etc/nginx$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         169.254.1.1     0.0.0.0         UG    0      0        0 eth0
169.254.1.1     0.0.0.0         255.255.255.255 UH    0      0        0 eth0

可以看到 0.0.0.0 指向了 169.254.1.1(eth0),查看容器ip地址

ingress-nginx-controller-556d4fff79-9jdmq:/etc/nginx$ ip addr 
4: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1480 qdisc noqueue state UP 
    link/ether 3a:0d:53:fb:ec:92 brd ff:ff:ff:ff:ff:ff
    inet 172.16.219.83/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::380d:53ff:fefb:ec92/64 scope link 
       valid_lft forever preferred_lft forever

这里容器获取的是 /32 位主机地址,表示将容器 A 作为一个单点的局域网。

eth0@if9为在宿主机上创建的虚拟网桥的一端,另一端为 calibfbdf93cf51。

calibfbdf93cf51又开启了proxy arp,所以流量就从pod内部到达了master 节点

解释:

当一个数据包的目的地址不是本机时,就会查询路由表,从路由表中查到网关后,它首先会通过 ARP获得网关的 MAC 地址,然后在发出的网络数据包中将目标 MAC 改为网关的 MAC,而网关的 IP 地址不会出现在任何网络包头中。也就是说,没有人在乎这个 IP 地址究竟是什么,只要能找到对应的 MAC 地址,能响应 ARP 就行了。

Calico 利用了网卡的代理 ARP 功能。代理 ARP 是 ARP 协议的一个变种,当 ARP 请求目标跨网段时,网关设备收到此 ARP 请求,会用自己的 MAC 地址返回给请求者,这便是代理 ARP(Proxy ARP)。

图片

八 从Master节点流出的流量分析

服务名方向节点IPIP地址端口
ingress-nginx-controller-556d4fff79-9jdmq源地址192.168.44.141172.16.219.89(使用)80
jupyter-deployment-57454c6795-xpgfk目标地址192.168.44.14210.97.82.53(使用)8888

容器eth0 => calico虚拟网卡 => ipvs网卡 => 需要跨节点则 tunl网卡,封装ip(可选,不一定会用它) => 宿主机 eth0

  • 查看svc网段是否通过tunl0网卡的网段? 查看本机的 ip a的ipvs网卡,存在这个IP 10.97.82.53

8.1 查看ipvsadm的负载均衡

root@master:~# ipvsadm --list
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
.............
TCP  10.97.82.53:8888 rr
  -> 172.16.64.206:8888           Masq    1      0          0    
.....................

得到目标的pod地址,172.16.64.206

8.2 master节点的路由表

Master节点的路由表,可以看到有一条规则是

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.16.64.192   192.168.44.142  255.255.255.192 UG    0      0        0 tunl0

给定的网络信息是:

  • 网络地址:172.16.64.192
  • 子网掩码:255.255.255.192

首先,可以将子网掩码转换为网络范围。255.255.255.192(即 /26)表示每个子网有64个地址(2^6)。因此,这个网段的范围是:

  • 网络地址:172.16.64.192
  • 广播地址:172.16.64.255
  • 可用的IP范围:172.16.64.193 到 172.16.64.254

因此,该网段的IP范围是 172.16.64.193 到 172.16.64.254

目标 172.16.64.206 IP存在 于这个IP范围,因此主机的下一跳地址为:192.168.44.142主机的 Tunl0网卡。

root@master:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.44.2    0.0.0.0         UG    100    0        0 ens33
172.16.64.192   192.168.44.142  255.255.255.192 UG    0      0        0 tunl0
172.16.219.64   0.0.0.0         255.255.255.192 U     0      0        0 *
172.16.219.87   0.0.0.0         255.255.255.255 UH    0      0        0 cali141c3047c6b
172.16.219.88   0.0.0.0         255.255.255.255 UH    0      0        0 cali780b4ee0aa6
172.16.219.89   0.0.0.0         255.255.255.255 UH    0      0        0 calibfbdf93cf51
172.16.219.90   0.0.0.0         255.255.255.255 UH    0      0        0 calie7fabde01ba
192.168.44.0    0.0.0.0         255.255.255.0   U     100    0        0 ens33
192.168.44.2    0.0.0.0         255.255.255.255 UH    100    0        0 ens33

跨节点

  • IPIP模式下,node间的Pod访问会使用IPIP技术对出node的ip报进行隧道封装
  • Pod的ip都是由calico-node设置的IP地址池进行分配的,Calico会为每一个node分配一小段网络。

8.3 对tunl0网卡进行分析

  1. IPIP封装

    • 由于172.16.64.206位于另一个节点,Calico会使用IPIP隧道将流量封装。
    • 原始IP包(源IP为172.16.219.89,目标IP为172.16.64.206)会被封装在一个新的IP包中。
    • 新的IP包的源IP是192.168.44.141master节点的IP),目标IP是192.168.44.142slave节点的IP)。
    • 这个新的IP包会通过tunl0网卡发送出去。

封装后的IP包结构

  • 外层IP头

    • 源IP:192.168.44.141master节点的IP)
    • 目标IP:192.168.44.142slave节点的IP)
    • 协议类型:IPIP(协议号4)
  • 内层IP头

    • 源IP:172.16.219.89(原始Pod的IP)
    • 目标IP:172.16.64.206(目标Pod的IP)
    • 协议类型:TCP/UDP等(取决于原始流量)

九 k8s-slave节点分析

  • 流量到达slave节点

    • slave节点192.168.44.142接收到这个IPIP封装的包。
    • tunl0网卡会解封装这个包,提取出原始的IP包(源IP为172.16.219.89,目标IP为172.16.64.206)。
    • 然后,slave节点会根据本地的路由表将流量转发到目标Pod 172.16.64.206

2.png
3.png

省流版总结

源主机源端口目标地址目标端口注释
发起者10.250.0.32随机端口jupyter.jcrose.com80
Windows /etc/host解析域名10.250.0.32随机端口192.168.44.14180
Iptables规则解析Nodeport192.168.44.141随机端口172.16.219.8980通过nodeport的相关iptables获取到 ingress-nginx的pod IP
ingress-nginx发起请求172.16.219.898010.97.82.538888通过 nginx.conf获取 jupyter.jcrose.com的信息,通过coredns获取到 SVC地址。
ingress-nginx发起请求192.168.44.141随机端口192.168.44.1428888这里流量经过了tunl0网卡把封包,把源地址和目标地址都修改为了目标主机
jupyter容器处理流量172.16.219.89随机端口172.16.64.2068888经过slave tunl0网卡的流量自动解包 获取到真实的源地址和目标地址(ingress-nginx的配置可以修改显示源地址或者容器地址)

查看 ingress-nginx-controller的日志证实确实如下

192.168.44.141 - - [24/Jan/2025:09:23:17 +0000] "GET / HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" 459 0.005 [default-jupyter-service-8888] [] 172.16.64.206:8888 0 0.004 302 5a0bfabc5d693d4a7cae94921207f78c
192.168.44.141 - - [24/Jan/2025:09:23:17 +0000] "GET /lab? HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" 463 0.002 [default-jupyter-service-8888] [] 172.16.64.206:8888 0 0.001 302 b4218276d6b133d8c68c237ea856fe79
192.168.44.141 - - [24/Jan/2025:09:23:17 +0000] "GET /login?next=%2Flab%3F HTTP/1.1" 200 6251 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" 479 0.022 [default-jupyter-service-8888] [] 172.16.64.206:8888 6251 0.022 200 24d3466f6b14ca223118edb7b58fd367

源地址: 192.168.44.141(端口这里看不到)

目标地址: 172.16.64.206:8888

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/965344.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux中,软硬链接的作用和使用

一、软硬链接的作用 软硬链接&#xff0c;是大家所熟系的内容了。链接就是方便人使用电脑上访问文件、方便进程访问文件的工具。比如软连接大家都有见过&#xff0c;在安装某款软件的时候要不要添加快捷方式。在windows系统上&#xff0c;我们右键点击文件的时候按‘s’就能创建…

kalman滤波器C++设计仿真实例第三篇

1. 仿真场景 水面上有条船在做匀速直线航行&#xff0c;航行过程中由于风和浪的影响&#xff0c;会有些随机的干扰&#xff0c;也就是会有些随机的加速度作用在船身上&#xff0c;这个随机加速度的均方差大约是0.1&#xff0c;也就是说方差是0.01。船上搭载GPS设备&#xff0c;…

ubuntu20.04+RTX4060Ti大模型环境安装

装显卡驱动 这里是重点&#xff0c;因为我是跑深度学习的&#xff0c;要用CUDA&#xff0c;所以必须得装官方的驱动&#xff0c;Ubuntu的附件驱动可能不太行. 进入官网https://www.nvidia.cn/geforce/drivers/&#xff0c;选择类型&#xff0c;最新版本下载。 挨个运行&#…

[c语言日寄]浮点数在内存中的储存

【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋&#xff1a;这是一个专注于C语言刷题的专栏&#xff0c;精选题目&#xff0c;搭配详细题解、拓展算法。从基础语法到复杂算法&#xff0c;题目涉及的知识点全面覆盖&#xff0c;助力你系统提升。无论你是初学者&#xff0c;还是…

Yageo国巨的RC系列0402封装1%电阻库来了

工作使用Cadence多年&#xff0c;很多时候麻烦的就是整理BOM&#xff0c;因为设计原理图的时候图省事&#xff0c;可能只修改value值和封装。 但是厂家&#xff0c;规格型号&#xff0c;物料描述等属性需要在最后的时候一行一行的修改&#xff0c;繁琐又容易出错&#xff0c;过…

【文档智能】Qwen2.5-VL在版式分析和表格识别上的实际评测效果

qwen开年开源了Qwen2.5-VL系列权重模型&#xff0c;笔者观察到相较于传统的多模态系列&#xff0c;增加了文档理解功能。笔者以文档智能中两个比较重要的任务版式分析和表格识别&#xff0c;笔者直接测试下Qwen2.5-VL-72B的效果。 版式分析 case1 case2 这个case没有输出bbox…

【计算机组成原理】1_绪论

chap1 绪论 1. 国产芯片现状 MIPS阵营&#xff1a;龙芯X86阵营&#xff08;常见于桌面和服务器&#xff09;&#xff1a;兆芯&#xff08;VIA&#xff09;&#xff0c;海光&#xff08;AMD&#xff09;ARM阵营&#xff08;常见于移动嵌入式、手机平板等&#xff09;&#xff…

解锁反序列化漏洞:从原理到防护的安全指南

目录 前言 一、什么是反序列化 二、反序列化漏洞原理 三、反序列化漏洞的危害 &#xff08;一&#xff09;任意代码执行 &#xff08;二&#xff09;权限提升 &#xff08;三&#xff09;数据泄露与篡改 四、常见的反序列化漏洞场景 &#xff08;一&#xff09;PHP 反…

openGauss 3.0 数据库在线实训课程1:学习数据库状态查看

openGauss数据库状态查看 前提 我正在参加21天养成好习惯| 第二届openGauss每日一练活动 课程详见&#xff1a;openGauss 3.0.0数据库在线实训课程 学习目标 学习从操作系统层面和使用openGauss工具查看数据库的状态、版本和数据文件目录。 课程作业 gs_ctl是openGauss提…

[含文档+PPT+源码等]精品基于Python实现的django个性化健康餐计划订制系统

软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技术&#xff1a;JavaScript、VUE.js&#xff08;2.X&#xff09;、css3 开发工具&#xff1a;pycharm、Visual Studio Code、HbuildX 数据库&#xff1a;MySQL 5.7.26&am…

单机伪分布Hadoop详细配置

目录 1. 引言2. 配置单机Hadoop2.1 下载并解压JDK1.8、Hadoop3.3.62.2 配置环境变量2.3 验证JDK、Hadoop配置 3. 伪分布Hadoop3.1 配置ssh免密码登录3.2 配置伪分布Hadoop3.2.1 修改hadoop-env.sh3.2.2 修改core-site.xml3.2.3 修改hdfs-site.xml3.2.4 修改yarn-site.xml3.2.5 …

ZooKeeper单节点详细部署流程

ZooKeeper单节点详细部署流程 文章目录 ZooKeeper单节点详细部署流程 一.下载稳定版本**ZooKeeper**二进制安装包二.安装并启动**ZooKeeper**1.安装**ZooKeeper**2.配置并启动**ZooKeeper** ZooKeeper 版本与 JDK 兼容性3.检查启动状态4.配置环境变量 三.可视化工具管理**Zooke…

IMX6ULL环境搭建遇到的问题和解答更新

IMX6ULL环境搭建遇到的问题 开发板&#xff1a;正点原子IMX6ULL 终端软件串口控制&#xff1a;MobaXterm 1、网络环境搭建三方互ping不通 电脑无网口&#xff0c;使用绿联USB转网口&#xff0c;接网线直连开发板&#xff0c;电脑WiFi上网 按文档设置的 IP 地址&#xff0c;以…

Windows Docker笔记-Docker拉取镜像

通过在前面的章节《安装docker》中&#xff0c;了解并安装成功了Docker&#xff0c;本章讲述如何使用Docker拉取镜像。 使用Docker&#xff0c;主要是想要创建并运行Docker容器&#xff0c;而容器又要根据Docker镜像来创建&#xff0c;那么首当其冲&#xff0c;必须要先有一个…

51单片机07 串口通信

串口是一种应用十分广泛的通讯接口&#xff0c;串口成本低、容易使用、通信线路简单&#xff0c;可实现两个设备的互相通信。单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信。51单片机内部自带UART&#xff08;Universal Asynchronous Recei…

外置互感器导轨式电能表

1 概述 1 Overview ADL系列导轨式多功能电能表&#xff0c;是主要针对于光伏并网系统、微逆系统、储能系统、交流耦合系统等新能源发电系统而设计的一款智能仪表&#xff0c;产品具有精度高、体积小、响应速度快、安装方便等优点。具有对电力参数进行采样计量和监测&#xff…

微软发布基于PostgreSQL的开源文档数据库平台DocumentDB

我们很高兴地宣布正式发布DocumentDB——一个开源文档数据库平台&#xff0c;以及基于 vCore、基于 PostgreSQL 构建的 Azure Cosmos DB for MongoDB 的引擎。 过去&#xff0c;NoSQL 数据库提供云专用解决方案&#xff0c;而没有通用的互操作性标准。这导致对可互操作、可移植…

开放式TCP/IP通信

一、1200和1200之间的开放式TCP/IP通讯 第一步&#xff1a;组态1214CPU&#xff0c;勾选时钟存储器 第二步&#xff1a;防护与安全里面连接机制勾选允许PUT/GET访问 第三步&#xff1a;添加PLC 第四步&#xff1a;点击网络试图&#xff0c;选中网口&#xff0c;把两个PLC连接起…

【漫画机器学习】083.安斯库姆四重奏(Anscombe‘s quartet)

安斯库姆四重奏&#xff08;Anscombes Quartet&#xff09; 1. 什么是安斯库姆四重奏&#xff1f; 安斯库姆四重奏&#xff08;Anscombes Quartet&#xff09;是一组由统计学家弗朗西斯安斯库姆&#xff08;Francis Anscombe&#xff09; 在 1973 年 提出的 四组数据集。它们…

【C语言】指针运算与数组关系:详细分析与实例讲解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;1. 指针的基础运算1.1 指针的加减运算1.2 指针加整数与指针减整数1.3 指针与指针的运算 &#x1f4af;2. 指针的实际应用&#xff1a;模拟 strlen 函数2.1 使用指针模拟…