br-netfilter 與 bridge-nf-call-iptables 在 k8s 中會影響到 node 內 pod 之間的互通

Kubernetes 中,br_netfilter 和 bridge-nf-call-iptables 兩個設定,允許 iptables 規則作用在同個 node 的 pod 之間的流量上。如果這兩個設定未開啟,則回包會直接走二層轉發,導致無法原路返回。因此,在設定 Kubernetes 時,應注意這兩個設定是否已正確開啟。

Kiwi lee
10 min readJan 11, 2024
Photo by Federico Beccari on Unsplash

引言

這篇算是數篇文章自己閱讀後的記錄,主要是關於 kubernetes 中的 br-netfilterbridge-nf-call-iptables 兩個在 node 網路上的設定,會影響到同個 node 的 pod 互通。

從 Kubernetes 在節點的設定開始

節錄裡面的段落

  1. 網路連線轉發 IPv4 位址並讓 iptables 查看橋接器的流量
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF

2. 請 Kubernetes (K8S) 引用載入 br_netfilter, overlay 二個核心模組

sudo modprobe overlay sudo modprobe br_netfilter

3. 啟用 br_netfilter, overlay 二個核心模組

# sysctl params required by setup, params persist across reboots 
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

4. 在不重啟 node 下套用 sysctl 的參數

sudo sysctl --system

5. 驗證 br_netfilter, overlay modules

lsmod | grep br_netfilter 
lsmod | grep overlay

6. 驗證 net.bridge.bridge-nf-call-iptables, net.bridge.bridge-nf-call-ip6tables, and net.ipv4.ip_forward system variables are set to 1

sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

cni 中的參數簡述

CNI plugin 會建立自己的 bridge,不會沿用 node 本身的設定

  • br_netfilter 開啟,讓 iptables 的規則可以在二層的 linux bridge 上面運作,使經過的流量會經過 iptables chain
  • net.bridge.bridge-nf-call-iptables 開啟,讓二層的轉發仍會去使用 iptables 的三層規則(包含 conntrack)

br_netfilter

Linux 下 Netfilter 简介 : https://blog.csdn.net/qq_45571595/article/details/102769858

-br_netfiler作用:br_netfilter模块可以使 iptables 规则可以在 Linux Bridges 上面工作,用于将桥接的流量转发至iptables链

在基本使用过程中,如果没有加载br_netfilter模块,那么并不会影响不同node上的pod之间的通信,但是会影响同node内的pod之间通过service来通信

netfilter 框架是 Linux 中的包過濾框架,它提供了五個 hook 點,每個進入網路系統的包都會觸發這些 hook。

Iptables 與 netfilter 的關係: iptables是運行在 user namespace 的應用軟體,通過控制 Linux 核心 netfilter 模組,來管理網路封包的處理和轉發

iptable 的範例設定檔

iptables

  • 基於 netfilter 框架的防火牆工具,它可以用來控制網路流量。
  • 規則語法包括 table(表)、chain(鏈) 和 rules(規則) 三個部分。
  • 每個「表」指的是不同類型的封包處理流程
  • 每個表中又可以存在多個「鏈」,系統按照預訂的規則將封包通過某個內建鏈,例如將從本機發出的資料通過 OUTPUT chain
  • 在「鏈」中可以存在若干「規則」,這些規則會被逐一進行匹配,如果匹配,可以執行相應的動作,如修改封包,或者跳轉。
網路封包通過 Netfilter 時的工作流向

table 種類 — 封包處理流程

  • filter: 判斷是否允許 packet 通過
  • nat: network address translation,將 packet 轉送到無法直接訪問的網路
  • mangle: 修改 packet 的 IP
  • raw: iptables 會記錄狀態,conntrack 會記錄
  • security: SELinux 標記

Table 中會有不同的 chain — 通過指定的 chain

  • Incoming packets destined for the local system:
    PREROUTING -> INPUT
  • Incoming packets destined to another host:
    PREROUTING -> FORWARD -> POSTROUTING
  • Locally generated packets:
    OUTPUT -> POSTROUTING

Incoming packetes order:

First: PREROUTLING chain:

  1. raw
  2. mangle
  3. nat

Second: INPUT chain

  1. mangle
  2. filter
  3. security
  4. nat

Last: nat table delivered to local socker

常用的 iptables 規則包括允許、拒絕、重定向和修改等

bridge-nf-call-iptables

服務的訪問路徑:service -> ClusterIP -> PodIP

同個 node 上面 pod 互相打,不會經過 CNI plugin

clusterIP -> podIP 的可能問題

  • clusterIP 沒有正確的轉發到 podIP
  • 正確轉發後,卻沒有 response

如果 /proc/sys/net/bridge/bridge-nf-call-iptables = 0 則會導致 response 無法回來

虽然CNI使用的是flannel, 但flannel封装的也是linux bridge,linux bridge是虚拟的二层转发设备,而 iptables conntrack 是在三层上,所以如果直接访问同一网桥内的地址(ip同一网段),就会直接走二层转发,不经过 conntrack:

结合上面的图来看,同Node通过service访问pod的访问路径如下:

PodA 访问 service, 经过coreDNS解析成Cluster IP,不是网桥内的地址(ClusterIP一般跟PodIP不在一个网段),走Conntrack,进行DNAT,将ClusterIP转换成PodIP:Port

DNAT 后发现是要转发到了同节点上的 PodB,PodB 回包时发现目的 IP(此时是PodA的IP) 在同一网桥上(PodA与PodB的IP段一致),就直接走二层转发了,不会去调 conntrack

这样就导致回包时没有原路返回 没有返回包就导致请求方一直等直到超时退出. 这样也解释了为何访问在其它节点的应用的ClusterIP没有问题,因为目标PodIP与源PodIP不在同一个网段上,肯定要走conntrack.

kubernetes 訪問 service 都會走 DNAT,將 clusterIP:Port DNAT 成 endpoint (podIP:Port),然後登記在三層的 conntrack,這樣回傳時,conntrack 根據 table 反向 NAT

但若是關掉 bridge-nf-call-iptables 則會導致

  • 一開始是走 clusterIP 轉換,所以會走三層轉送,經過 DNAT 為 PodIP:Port
  • 回傳時發現是在同個 bridge,所以會直接走二層 bridge 轉發,沒有經過 conntrack,被視為不同的連接

結論

我自己是覺得,網路排障工具掌握得越多,知識累積得越多,通靈就會更準確🔮

就更有機會找到原因,不然一句「網路不通」其實超難解的啦

最近在公司一直遇到 cilium 的問題,特別是 iptables 中 cilium 的區塊整個不見,導致如上面 bridge-nf-call-iptables 沒開時無法 response,直到 timeout,所以很想研究看看裡面的玩意兒。也同時希望能把四個月前,筆記的 kube-proxy, coredns, nodelocaldns, cni plugin 能有機會轉化成有點條理的文章排序分享給大家 🫣

Reference:

Originally published at https://kiwilee-blog.netlify.app on January 11, 2024.

--

--

Kiwi lee
Kiwi lee

Written by Kiwi lee

Hi, I'm kiwi, Platform Engineer (SRE, DevOps). Python Engineer. Love art, books, longboard. https://kiwi-walk.com

No responses yet