天天看点

kubernetes的service开启NodePort在宿主机无法找到监听端口?

作者:云原生驿站

前言

不知道一直在玩k8的朋友有没有发现一个问题,开启了

ipvs

之后,

service

开启

NodePort

之后,在宿主机压根找不到该监听端口,本篇文章将带着大家解开这层面纱。

iptable回顾

四表五链的处理顺序是先作用链,再作用表!!!

四表五链的处理顺序是先作用链,再作用表!!!

四表五链的处理顺序是先作用链,再作用表!!!

链的访问顺序是:

  1. 数据包到达网卡时,首先经过

    PREROUTING

    链,进行预路由处理。
  2. 然后,在经过

    PREROUTING

    链后,根据路由规则确定目标地址和接口,选择目标主机或者进行转发。
  3. 如果数据包是发往本地主机的,那么接下来会经过INPUT链,进行输入数据包的处理。
  4. 如果数据包是转发的,那么接下来会经过

    FORWARD

    链,进行数据包的转发处理。
  5. 如果数据包是由本地主机发出的,那么接下来会经过

    OUTPUT

    链,进行输出数据包的处理。
  6. 最后,数据包离开网卡之前,会经过

    POSTROUTING

    链,进行后路由处理。

每条链上有什么表呢?

  1. PREROUTING链:
    • raw表:用于处理连接跟踪之前的数据包,可以修改数据包的源地址。
    • mangle表:用于处理数据包的特殊修改,如修改TTL(生存时间)字段、标记数据包等。
  2. INPUT链:
    • mangle表:用于处理数据包的特殊修改。
    • nat表:用于网络地址转换,通常用于

      DNAT

      (目标地址转换)和

      MASQUERADE

      (源地址转换)。
  3. FORWARD链:
    • mangle表:用于处理数据包的特殊修改。
    • filter表:用于过滤数据包,决定是否允许数据包通过路由转发。
  4. OUTPUT链:
    • raw表:用于处理连接跟踪之前的数据包,可以修改数据包的源地址。
    • mangle表:用于处理数据包的特殊修改。
    • nat表:用于网络地址转换,通常用于

      SNAT

      (源地址转换)。
  5. POSTROUTING链:
    • mangle表:用于处理数据包的特殊修改。
    • nat表:用于网络地址转换,通常用于

      SNAT

      (源地址转换)和

      MASQUERADE

      (源地址转换)。

这些表的作用是在五个主要的链上进行数据包处理和转换。根据规则的配置,

iptables

可以对数据包进行源地址转换、目标地址转换、标记、过滤等操作,从而实现网络流量的控制和管理。每个链上可以同时使用多个表,可以根据需求组合不同的规则来实现复杂的网络处理逻辑。

kube-proxy定义的链条

除了

iptable

本身的四表五链之外,

kube-proxy

也自定义了一系列链条,这里我们只基于

NodePort

并且开启

ipvs

kube-proxy

进行讨论

[root@openeuler-controlplane-jtzv-0 ~]# iptables -nL -t nat
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
......
Chain KUBE-SERVICES (2 references)
target prot opt source destination
KUBE-MARK-MASQ all -- !10.233.64.0/18 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
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set KUBE-CLUSTER-IP dst,dst
......
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
.....
           

在这里我们可以看到一条链 PREROUTING ➡️ KUBE-SERVICES ➡️ KUBE-NODE-PORT

KUBE-NODE-PORT

链条的内容解析如下

  1. 链名称:

    KUBE-NODE-PORT

  2. 目标:

    KUBE-MARK-MASQ

    ,表示如果规则匹配成功,则执行名为

    KUBE-MARK-MASQ

    的目标规则。
  3. 协议:

    tcp

    ,表示该规则仅处理 TCP 协议的流量。
  4. 源地址 (

    source

    ):

    0.0.0.0/0

    ,表示任何源地址都会被匹配。
  5. 目标地址 (

    destination

    ):

    0.0.0.0/0

    ,表示任何目标地址都会被匹配。
  6. 注释 (

    /* Kubernetes nodeport TCP port for masquerade purpose */

    ):对该规则的简要说明,用于标识该规则的用途。

该规则使用了

match-set

来匹配集合

KUBE-NODE-PORT-TCP

中的目标端口(NodePort)。当外部请求到达 NodePort 时,该规则会将流量标记为

KUBE-MARK-MASQ

,以便进行后续的

MASQUERADE

处理。

在 Kubernetes 中,

KUBE-MARK-MASQ

是一个

iptables

链的标记,它用于标记要进行源地址转换(

MASQUERADE

)的数据包。

MASQUERADE

是一种

Network Address Translation (NAT)

技术,它允许修改数据包的源 IP 地址,以便返回的数据包能够正确返回给发起请求的客户端。

具体来说,当请求从 Kubernetes 集群中的

NodePort

(服务暴露在宿主机上的端口)到达时,

KUBE-NODE-PORT

链的规则会匹配该请求,并将其标记为

KUBE-MARK-MASQ

。然后,

KUBE-MARK-MASQ

链的规则将对这些标记的数据包进行

MASQUERADE

处理,将它们的源 IP 地址替换为宿主机的 IP 地址,以确保响应的数据包能够正确返回到请求的客户端。

这个过程确保了外部请求能够正确路由到

Kubernetes

集群中的

Service

Pod

,并在返回时正确返回给请求的客户端。这是实现

Kubernetes Service

NodePort

类型所必需的一部分。

既然使用了

march-set

,我们不妨先看看

ipset

[root@openeuler-controlplane-jtzv-0 ~]# ipset list |grep KUBE-NODE-PORT-TCP -A 12
Name: KUBE-NODE-PORT-TCP
Type: bitmap:port
Revision: 3
Header: range 0-65535
Size in memory: 8296
References: 1
Number of entries: 4
Members:
30000
30090
31037
31428
           

可以看到我们的目标

NodePort(31037)

ipvs

工作在

input

链(内核空间)利用

ipvsadm

(用户空间)定义的转发规则对数据包进行校验,或者说此时

INPUT

链不再生效了,

IPVS

会拦截进入本机的数据包,并根据负载均衡的规则将其转发给后端的真实服务器(

Real Server

)处理

我们可以通过

ipvsadm -S -n

映射内容,到这一步基本就已经知道原因了,可以看到你的

NodeIP:NodePort

映射到

PodIP

,往下分析无非就是走完这个链条,本篇文章就不再展开赘述了。