天天看點

《做一個不背鍋運維:K8S Service底層政策初探和分析》

作者:不背鍋運維

建立用于測試的Deployment和Service

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test-goweb
  name: test-goweb
spec:
  replicas: 6
  selector:
    matchLabels:
      app: test-goweb
  template:
    metadata:
      labels:
        app: test-goweb
    spec:
      containers:
      - image: 192.168.11.247/web-demo/goweb-demo:20221229v3
        imagePullPolicy: IfNotPresent
        name: goweb-demo
        ports:
        - containerPort: 8090
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: test-goweb
  name: test-goweb
spec:
  ports:
  - name: 80-8090
    nodePort: 30010
    port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: test-goweb
  type: NodePort
           

Service底層有哪些iptables鍊

當在 Kubernetes 中建立 Service 時,将會建立以下幾個 iptables 鍊。這些鍊都是用于實作 Service 的核心功能,下面列出所涉及到的鍊:

  1. PREROUTING 鍊:此鍊是由 kube-proxy 元件建立的,用于将 Service IP 位址映射到對應的 Pod IP 位址上。當請求進入節點時,該鍊将被觸發,它根據請求的 Service IP 位址來查找對應的 Pod IP 位址,并将請求轉發到該 Pod。
  2. KUBE-SERVICES 鍊:此鍊包含了一系列規則,用于将 Service IP 位址映射到對應的 Pod IP 位址上。當請求進入節點時,該鍊将被觸發,并根據請求的 Service IP 位址來查找對應的 Pod IP 位址。如果找到了對應的 Pod IP 位址,請求将被轉發到該 Pod。
  3. KUBE-SVC-XXX 鍊:此鍊包含了一系列規則,其中 XXX 代表 Service 的名稱。每個 Service 都有一個對應的 KUBE-SVC-XXX 鍊。當請求進入節點時,該鍊将被觸發,并根據 Service IP 位址查找對應的 KUBE-SVC-XXX 鍊。該鍊中的規則将請求轉發到對應的 Pod。
  4. KUBE-SEP-XXX 鍊:此鍊包含了一系列規則,其中 XXX 代表 Service 的名稱。每個 Service 都有一個對應的 KUBE-SEP-XXX 鍊。當請求進入節點時,該鍊将被觸發,并根據 Service IP 位址查找對應的 KUBE-SEP-XXX 鍊。該鍊中的規則将請求轉發到對應的 Pod。
  5. KUBE-FIREWALL 鍊:此鍊用于處理來自 Kubernetes 的内部流量。該鍊包含了一些規則,用于控制通路 Kubernetes 的 API、DNS 和其他一些服務。
  6. KUBE-NODEPORT 鍊:當 Service 類型為 NodePort 時,此鍊将被建立。該鍊包含了一些規則,用于将節點的端口映射到 Service 的端口上。
  7. KUBE-MARK-DROP 鍊:當請求被拒絕時,會觸發此鍊。該鍊包含了一些規則,用于标記被拒絕的資料包。
這些 iptables 鍊是 Kubernetes 中實作 Service 的關鍵元件。它們使得用戶端可以使用 Service 名稱來通路運作在 Pod 中的應用程式,而不必了解其具體 IP 位址。

檢視和這個service有關的iptables規則

# iptables-save | grep test-goweb

-A KUBE-EXT-XRKWZPWLY5ZGEEBK -m comment --comment "masquerade traffic for default/test-goweb:80-8090 external destinations" -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp --dport 30010 -j KUBE-EXT-XRKWZPWLY5ZGEEBK
-A KUBE-SEP-2KC5TQ77EILRJT77 -s 10.244.240.51/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-2KC5TQ77EILRJT77 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.51:8090
-A KUBE-SEP-5AVQRPMC6RQQAAKG -s 10.244.240.9/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-5AVQRPMC6RQQAAKG -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.9:8090
-A KUBE-SEP-7QBH2WDQDSESRX53 -s 10.244.240.19/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-7QBH2WDQDSESRX53 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.19:8090
-A KUBE-SEP-KGPYN3PAVPO2A2G3 -s 10.244.240.20/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-KGPYN3PAVPO2A2G3 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.20:8090
-A KUBE-SEP-VXCKMNYZWUWZOOOJ -s 10.244.240.38/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-VXCKMNYZWUWZOOOJ -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.38:8090
-A KUBE-SEP-XH5PMCJ3CYSK4B7L -s 10.244.240.56/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
-A KUBE-SEP-XH5PMCJ3CYSK4B7L -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.56:8090
-A KUBE-SERVICES -d 10.104.238.165/32 -p tcp -m comment --comment "default/test-goweb:80-8090 cluster IP" -m tcp --dport 80 -j KUBE-SVC-XRKWZPWLY5ZGEEBK
-A KUBE-SVC-XRKWZPWLY5ZGEEBK ! -s 10.244.0.0/16 -d 10.104.238.165/32 -p tcp -m comment --comment "default/test-goweb:80-8090 cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.19:8090" -m statistic --mode random --probability 0.16666666651 -j KUBE-SEP-7QBH2WDQDSESRX53
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.20:8090" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-KGPYN3PAVPO2A2G3
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.38:8090" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-VXCKMNYZWUWZOOOJ
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.51:8090" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-2KC5TQ77EILRJT77
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.56:8090" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-XH5PMCJ3CYSK4B7L
-A KUBE-SVC-XRKWZPWLY5ZGEEBK -m comment --comment "default/test-goweb:80-8090 -> 10.244.240.9:8090" -j KUBE-SEP-5AVQRPMC6RQQAAKG
           
上面看到的這一堆規則,就是由 kube-proxy 元件自動建立和維護 iptables 規則,繼續往下看,抽幾條規則做個簡單的分析。

簡單分析

  1. 先看整體看看這1條規則
-A KUBE-EXT-XRKWZPWLY5ZGEEBK -m comment --comment "masquerade traffic for default/test-goweb:80-8090 external destinations" -j KUBE-MARK-MASQ
           

這是上面第一條iptables規則,它用于Kubernetes叢集中的網絡轉發和流量僞裝。具體來說,這個規則将來自Kubernetes服務“default/test-goweb”的流量僞裝為外部目标,以便它們可以通過叢集外部通路。

規則中的參數解釋如下:

  • -A:将規則添加到鍊的末尾
  • KUBE-EXT-XRKWZPWLY5ZGEEBK:鍊的名稱
  • -m comment --comment "masquerade traffic for default/test-goweb:80-8090 external destinations":添加一條注釋,說明此規則是用于僞裝“default/test-goweb”的流量,并指定了流量端口範圍和目标類型
  • -j KUBE-MARK-MASQ:将流量标記為需要進行僞裝的流量,以便其能夠離開叢集并在目标處正确路由
請注意,KUBE-EXT-XRKWZPWLY5ZGEEBK、KUBE-MARK-MASQ是自定義的鍊名稱,它在Kubernetes叢集中的不同部分可能會有所不同。在實際使用時,鍊的名稱可能會因不同的部署而有所變化,但規則的作用通常是相似的。
  1. 大概看看第2條
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp --dport 30010 -j KUBE-EXT-XRKWZPWLY5ZGEEBK
           

它的作用是将從 NodePort 類型的 Service 通路到的流量(目标端口為 30010/tcp)轉發到名為 KUBE-EXT-XRKWZPWLY5ZGEEBK 的鍊上進行進一步處理。

  1. 大概看看第3條
-A KUBE-SEP-2KC5TQ77EILRJT77 -s 10.244.240.51/32 -m comment --comment "default/test-goweb:80-8090" -j KUBE-MARK-MASQ
           

它的作用是将來自 IP 位址為 10.244.240.51 的源位址流量進行 SNAT 轉換,以便将源 IP 位址更改為 Node 的 IP 位址,進而使流量能夠傳回到用戶端。該規則使用名為 KUBE-MARK-MASQ 的鍊進行轉換。

  1. 再看看第4條
-A KUBE-SEP-2KC5TQ77EILRJT77 -p tcp -m comment --comment "default/test-goweb:80-8090" -m tcp -j DNAT --to-destination 10.244.240.51:8090
           

它的作用是将從叢集内某個節點上的 Pod 通路 Service 的流量進行 DNAT 轉換,以便将流量重定向到特定 Pod 的 IP 位址和端口上。

k8s的iptables規則是由k8s自身自動維護的,它使用 kube-proxy 元件來自動建立和維護 iptables 規則,當建立一個 Service 時,kube-proxy 會自動為該 Service 建立一組 iptables 規則,當 Pod 被添加或删除時,kube-proxy 會相應地更新這些規則。是以,不需要人為手動管理這些規則,簡直是香到不行。

将Service底層的代理模式改為IPVS後

tantianran@test-b-k8s-master:~$ kubectl get svc test-goweb
NAME         TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
test-goweb   NodePort   10.104.238.165   <none>        80:30010/TCP   25h
           

在其中一台節點上看虛拟伺服器資訊

tantianran@test-b-k8s-node01:~$ sudo ipvsadm-save
-A -t test-b-k8s-node01:30001 -s rr
-a -t test-b-k8s-node01:30001 -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:30010 -s rr
-a -t test-b-k8s-node01:30010 -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.63:8090 -m -w 1
-A -t test-b-k8s-node01:30001 -s rr
-a -t test-b-k8s-node01:30001 -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:30010 -s rr
-a -t test-b-k8s-node01:30010 -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.63:8090 -m -w 1
-A -t test-b-k8s-node01:https -s rr
-a -t test-b-k8s-node01:https -r test-b-k8s-master:6443 -m -w 1
-A -t test-b-k8s-node01:domain -s rr
-a -t test-b-k8s-node01:domain -r 10.244.82.19:domain -m -w 1
-a -t test-b-k8s-node01:domain -r 10.244.240.60:domain -m -w 1
-A -t test-b-k8s-node01:9153 -s rr
-a -t test-b-k8s-node01:9153 -r 10.244.82.19:9153 -m -w 1
-a -t test-b-k8s-node01:9153 -r 10.244.240.60:9153 -m -w 1
-A -t test-b-k8s-node01:https -s rr
-a -t test-b-k8s-node01:https -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:8000 -s rr
-a -t test-b-k8s-node01:8000 -r 10.244.240.16:8000 -m -w 1
-A -t test-b-k8s-node01:http -s rr
-a -t test-b-k8s-node01:http -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:http -r 10.244.240.63:8090 -m -w 1
-A -t test-b-k8s-node01:https -s rr
-a -t test-b-k8s-node01:https -r 10.244.240.15:4443 -m -w 1
-A -t test-b-k8s-node01:30001 -s rr
-a -t test-b-k8s-node01:30001 -r 10.244.240.11:8443 -m -w 1
-A -t test-b-k8s-node01:30010 -s rr
-a -t test-b-k8s-node01:30010 -r 10.244.240.24:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.48:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.52:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.54:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.62:8090 -m -w 1
-a -t test-b-k8s-node01:30010 -r 10.244.240.63:8090 -m -w 1
-A -u test-b-k8s-node01:domain -s rr
-a -u test-b-k8s-node01:domain -r 10.244.82.19:domain -m -w 1
-a -u test-b-k8s-node01:domain -r 10.244.240.60:domain -m -w 1
           

要注意了,在上面的虛拟伺服器資訊中可以看到,有的是-a,有的是-A,這兩個選項都可以用于向IPVS中添加一個新的服務(virtual server)。它們的差別不僅僅在于是大小寫的差別,更大的差別在于添加服務的方式和語義上略有不同:

  • -a選項将添加一個新的服務,并将其附加到一個現有的排程器上。如果排程器不存在,則會建立一個新的排程器。
  • -A選項将添加一個新的服務,并将其附加到一個現有的排程器上。如果排程器不存在,則不會建立新的排程器。如果排程器已經存在,則服務将被添加到現有的排程器中。

拿這條政策來看看

-a -t test-b-k8s-node01:http -r 10.244.240.24:8090 -m -w 1
           

以下是每個選項的含義:

  • -a: 添加虛拟服務
  • -t test-b-k8s-node01:http: 虛拟服務的名稱和協定。
  • -r 10.244.240.24:8090: 後端真實伺服器的IP位址和端口号,也就是POD的。
  • -m: 使用IPVS的NAT模式。
  • -w 1: 将權重設定為1,即将1個請求發送給該伺服器。
總而言之它的作用是:它将添加一個名為test-b-k8s-node01的HTTP虛拟服務,并将用戶端的請求源IP位址改為工作節點的IP位址,并将請求發送到後端伺服器10.244.240.24:8090,其中隻有一個後端伺服器,它的服務能力是1。

最後的總結

k8s中的Service底層不管是iptables還是ipvs,它們的政策規則都是k8s自身自動維護的。具體來說,當建立一個Service時,Kubernetes會在底層為該Service建立一個虛拟IP(VIP),并自動配置iptables或者ipvs規則,使得這個VIP可以将流量轉發到Service中的多個Pod執行個體。

當使用iptables時,Kubernetes會在每個節點上建立iptables規則,通過iptables NAT功能實作負載均衡和服務發現。而當使用ipvs時,Kubernetes會在每個節點上建立ipvs規則,并使用ipvs的負載均衡算法實作服務發現和流量轉發。

無論是使用iptables還是ipvs,Kubernetes都會自動維護這些規則,保證Service的負載均衡和高可用性。當Service中的Pod執行個體發生變化時,Kubernetes會自動更新iptables或ipvs規則,以確定流量能夠正确地轉發到新的Pod執行個體上。Kubernetes通過自動化的方式,簡化了Service的配置和維護。

本文轉載于WX公衆号:不背鍋運維(喜歡的盆友關注我們):https://mp.weixin.qq.com/s/3LGRf9NMs9qkMlGvTqVAcA

上一篇: arm彙編輸出

繼續閱讀