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

server/2025/2/6 9:56:30/

前言

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

我个人的疑问点

  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:443Chain 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 a3: 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:ffinet 10.96.0.2/32 scope global kube-ipvs0valid_lft forever preferred_lft foreverinet 10.97.82.53/32 scope global kube-ipvs0valid_lft forever preferred_lft foreverinet 10.96.0.1/32 scope global kube-ipvs0valid_lft forever preferred_lft foreverinet 10.100.104.51/32 scope global kube-ipvs0valid_lft forever preferred_lft foreverinet 10.108.32.102/32 scope global kube-ipvs0valid_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

nginx_318">六 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.comserver {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 connectionsproxy_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-Forproxy_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 serverproxy_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 errorproxy_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

nginx_466">七 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:ffinet 172.16.219.83/32 scope global eth0valid_lft forever preferred_lft foreverinet6 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


http://www.ppmy.cn/server/165378.html

相关文章

Visual Studio Code应用本地部署的deepseek

1.打开Visual Studio Code&#xff0c;在插件中搜索continue&#xff0c;安装插件。 2.添加新的大语言模型&#xff0c;我们选择ollama. 3.直接点connect&#xff0c;会链接本地下载好的deepseek模型。 参看上篇文章&#xff1a;deepseek本地部署-CSDN博客 4.输入需求生成可用…

从DTFT到DFT:数字信号处理中的关键过渡

摘要 在数字信号处理领域&#xff0c;从离散时间傅里叶变换&#xff08;DTFT&#xff09;过渡到离散傅里叶变换&#xff08;DFT&#xff09;是一个至关重要的发展阶段。本文将深入浅出地阐述这一过渡过程&#xff0c;详细解释为什么需要用DFT来表示实际的信号。首先介绍DTFT的…

机器学习--python基础库之Matplotlib (2) 简单易懂!!!

python基础库之Matplotlib&#xff08;2&#xff09; python基础库之Matplotlib0 准备1 散点图的绘制2 柱状图绘制3 其他 python基础库之Matplotlib 上篇文章机器学习–python基础库之Matplotlib (1) 超级详细!!!主要讲解了python的基础库matplotlib中绘图的流程以及折线图的…

论文阅读(九):通过概率图模型建立连锁不平衡模型和进行关联研究:最新进展访问之旅

1.论文链接&#xff1a;Modeling Linkage Disequilibrium and Performing Association Studies through Probabilistic Graphical Models: a Visiting Tour of Recent Advances 摘要&#xff1a; 本章对概率图模型&#xff08;PGMs&#xff09;的最新进展进行了深入的回顾&…

【NLP251】NLP RNN 系列网络

NLP251 系列主要记录从NLP基础网络结构到知识图谱的学习 &#xff11;.原理及网络结构 &#xff11;.&#xff11;&#xff32;&#xff2e;&#xff2e; 在Yoshua Bengio论文中( http://proceedings.mlr.press/v28/pascanu13.pdf )证明了梯度求导的一部分环节是一个指数模型…

PHP 中 `foreach` 循环结合引用使用时可能出现的问题

问题背景 假设你有如下 PHP 代码&#xff1a; <?php $arr array(1, 2, 3, 4);// 使用引用遍历并修改数组元素 foreach ($arr as &$value) {$value $value * 2; } // 此时 $arr 变为 array(2, 4, 6, 8)// 再使用非引用方式遍历数组 foreach ($arr as $key > $val…

使用jmeter进行压力测试

使用jmeter进行压力测试 jmeter安装 官网安装包下载&#xff0c;选择二进制文件&#xff0c;解压 tar -xzvf apache-jmeter-x.tgz依赖jdk安装 yum install java-1.8.0-openjdk环境变量配置&#xff0c;修改/etc/profile文件&#xff0c;添加以下内容 export JMETER/opt/apa…

C#从XmlDocument提取完整字符串

方法1&#xff1a;通过XmlDocument的OuterXml属性&#xff0c;见XmlDocument类 该方法获得的xml字符串是不带格式的&#xff0c;可读性差 方法2&#xff1a;利用XmlWriterSettings控制格式等一系列参数&#xff0c;见XmlWriterSettings类 例子&#xff1a; using System.IO; …