kube-proxy與iptables

身為DevOps工程師
6 min readJun 9, 2022

--

kube-proxy

Photo by Nick Seagrave on Unsplash

kube-proxy是一個執行在k8s cluster中的worker node中,負責讓流量可以正確被傳送到Pod上的Component。

不知道大家有沒有想過,為什麼我們在建立Service後拿到的ClusterIP可以直接打到Pod上,中間是藉由什麼方式達成的?其實都是靠這個kube-proxy來替我們做到的,而它後面有以下三種模式來達成

  • userspace
  • iptables
  • ipvs

如果我們不特別去修改ProxyMode,預設就會使用iptables的方式。在使用iptables做為ProxyMode時,一但有新的service或endpoints被建立時,就會去修改iptables。我們可以在iptables nat的表格中看到封包都怎麼轉發的。

iptables簡介

擁有三個大項:

  • 表(Tables)
  • 鏈(chain)
  • 規則(rules)

而表又分成了四種,

  • filter: 通常是用來過濾封包。(預設的表)
  • nat: 用於位址轉換(來源IP[SNAT] 與 目標IP[DNAT])
  • mangle: 用於處理封包
  • raw: 用於處理異常

以下為列出iptables的command

# 列出預設表格(filter)的iptables
iptables -L
# 列出NAT表格的iptables
iptables -L -t nat

Deployment & Service

雖然知道會去kube-proxy會去修改iptables來處理封包的轉發,但對iptables不太熟悉,所以一直都沒有實際往下追。趁著這次機會重新來好好的認識kube-proxy是怎麼跟iptables合作的。

建立一個deployment: nginx與service來試試

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80

kube-proxy — iptables

我們來看看kube-proxy是怎麼幫助我們轉發Service的資料,以下截取部分的iptables的資料

$ sudo iptables -L -t nat
...
Chain KUBE-SVC-V2OKYYMBY3REGZOG (1 references)
target prot opt source destination
KUBE-SEP-X7WBOA4PTAJA3GNK all -- anywhere anywhere /* default/nginx-service */ statistic mode random probability 0.33333333349
KUBE-SEP-I53TFYWHN2OKR6FH all -- anywhere anywhere /* default/nginx-service */ statistic mode random probability 0.50000000000
KUBE-SEP-WU6475GP2VYJZBGF all -- anywhere anywhere /* default/nginx-service */
Chain KUBE-SEP-X7WBOA4PTAJA3GNK (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 192.168.104.146 anywhere /* default/nginx-service */
DNAT tcp -- anywhere anywhere /* default/nginx-service */ tcp DNAT [unsupported revision]
...

💡 一開始只有使用 sudo iptables -L 的方式,想來找kube-proxy修改的部分。但一直都沒找到,後來發現直接下 -L 不使用 -t 指定 table的話預設為filter

在我們YAML的設計中,deployment的replicas設定為3。iptables的rules是從上到下執行的,我們可以看到在 Chain KUBE-SVC-V2OKYYMBY3REGZOG 的第一條rule,觸發的機率是 0.33,後面一條為0.5。乍看之下好像怪怪的,但其實是很平均的。

讓我們來精算一下

  • 33.33 % (這應該沒懸念)
  • 此時要選到第二條的機率看似 50%,但因為前面已經先有 33.33%了。所以結果是 (100% — 33%) * 0.5 大約也是33.33 %
  • 如果前面都沒選到,就直接最後一條。

來看看 KUBE-SEP-X7WBOA4PTAJA3GNK(192.168.104.146) 會將封包發送的目標IP是不是pod的endpoints

$ kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 10.140.0.25:6443 24h
nginx-service 192.168.104.146:80,192.168.104.147:80,192.168.238.78:80 75m
$ kubectl get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-66b6c48dd5-d8jvg 1/1 Running 0 79m 192.168.104.147 cka-training-master01 <none> <none>
nginx-deployment-66b6c48dd5-g2whs 1/1 Running 0 79m 192.168.104.146 cka-training-master01 <none> <none>
nginx-deployment-66b6c48dd5-wlwg4 1/1 Running 0 79m 192.168.238.78 cka-training-worker01 <none> <none>

Summary

kube-proxy在進入iptables的方式後,其實也慢慢的也在cluster的規模愈來愈大的情況遇到了效能的瓶頸。所以開始有了使用IPVS做底層來處理k8s cluster中的proxy。不過對網路實在有點苦手,下次有機會再來研究看看IPVS的kube-proxy是怎麼回事。

--

--

身為DevOps工程師

目前在蓋亞資訊擔任DevOps Consultant。最近才從後端的世界轉成投向DevOps的懷抱,目前專注在Kubernetes, GitLab, DevSecOps的學習中。