Kubernetes 核心原理

本文主要介紹 k8s 的核心原理,包括淺析各個模塊的運行邏輯和 k8s 中的網絡通訊。

第一部分:模塊

核心架構

以上是在 k8s 中的各個模塊,下面就來詳細介紹一下各個模塊的作用和原理。

1、API Server

API Server 是集羣管理的 API 入口,控制資源配額,提供了完備的安全機制,包括增刪改查的 Rest API,也包括一些實時監聽的 Watch 接口。
以下是一個簡單的樣例,通過訪問 API 可以直接獲取信息:

[root@VM-0-11-centos ~]# curl -i 'http://localhost:8080/api'
HTTP/1.1 200 OK
Content-Type: application/json
Date: Tue, 24 Oct 2023 00:40:21 GMT
Content-Length: 183

{
  "kind""APIVersions",
  "versions"[
    "v1"
  ],
  "serverAddressByClientCIDRs"[
    {
      "clientCIDR""0.0.0.0/0",
      "serverAddress""172.27.0.11:6443"
    }
  ]
}

通過 API Server 的接口可以操作 k8s 集羣或者查看集羣內的詳細信息,除了上面的接口還有如下接口可以嘗試:

curl localhost:8080/api/v1/pods # 返回集羣的pod列表
curl localhost:8080/api/v1/services # 返回集羣的service列表
curl localhost:8080/api/v1/replicationcontrollers # 返回集羣的rc列表

通過 API Server 我們不僅可以查詢 Master 上面的信息,還可以通過 API Server 將請求轉發到某個 Node 上,如:

curl -i 'http://127.0.0.1:8080/api/v1/proxy/nodes/127.0.0.1/pods/' # 指定節點127.0.0.1上的所有Pod信息
curl -i 'http://127.0.0.1:8080/api/v1/proxy/nodes/127.0.0.1/stats/' # 指定節點內物理資源的統計信息
curl -i 'http://127.0.0.1:8080/api/v1/proxy/nodes/127.0.0.1/spec/' # 指定節點的概要信息
curl -i 'http://127.0.0.1:8080/api/v1/proxy/nodes/127.0.0.1/metrics' # 節點上的metrics信息
curl -i 'http://127.0.0.1:8080/api/v1/proxy/nodes/127.0.0.1/logs/' # 節點上的日誌信息
... # 其他一些相關的API可以查看官方文檔

2、模塊之間通訊

從 k8s 的基礎架構圖中我們知道,k8s 包括:API Server,kubelet,etcd,controller-manager,scheduler 等,那他們之間是如何通訊的?
(1)etcd 是存儲各個模塊的狀態信息,操作數據等;
(2)每個 Node 節點上運行着 kubelet 進程,每隔一個時間週期就會調用一次 API Server 的接口,報告當前 Node 狀態,同時 API Server 收到這些信息以後,存入 etcd 中;
(3)kubelet 除了定時上報信息,還有監聽 API Server 的 Watch 接口,如果需要在本節點調度 Pod,則會執行創建或者銷燬等邏輯;
(4)controller-manager 也會與 API Server 交互,通過 API Server 的 Watch 接口,監聽 kubelet 上報過來的 Node 信息,如果 Node 掛了則負責重新調度,當然 controller-manager 還控制着其他各個 controller 模塊;
(5)scheduler 是通過 API Server 監聽 Pod 信息後,負責檢索所有符合該 Pod 條件的 Node 列表,執行 Pod 的調度,調度成功後將 Pod 綁定到目標節點上;

3、contoller-manager

contoller-manager 是集羣內的管理中心,負責集羣的 Node,Pod,Endpoint,Namespace,ServiceAccount,ResourceQuota 等的管理,當 Node 出現問題時,contoller-manager 負責及時發現故障,並執行自動修復流程,確保達到預期的工作狀態。

在 k8s 中有一些邏輯 contoller,分別管理集羣的每一個部分的控制權,下面是常用的介紹:

4、scheduler

前面說到 controller 是負責創建 Pod,那麼如何調度到目標節點?scheduler 的作用就是將待調度的 Pod,按照特定的調度算法和調度策略調度到合適的 Node 節點上,並將信息保存到 etcd 中,scheduler 寫入信息後,節點上的 kubelet 通過監聽 API Server 獲取到對應需要調度的 Pod,執行鏡像下載,啓動容器等。

scheduler 架構圖

scheduler 調度簡單分爲兩步:
(1)預選調度過程,遍歷所有的目標 Node,篩選候選節點;
(2)確定最優節點,通過策略計算每個候選節點的分數,然後最高分數節點獲勝後確認調度節點;

其中 scheduler 調度流程可以通過 AlgorithmProvider 實現,其註冊函數如下:

func RegisterAlgorithmProvider(name string, predicateKeys, priorityKeys util.StringSet)

5、kubelet

在 k8s 集羣中,每個 Node 節點上都會啓動一個 kubelet 進程,從前面可以看出 kubelet 主要作用是符合幫助 Master 代理執行各種在 Node 上的命令,那具體會執行哪些呢?

(1)註冊

kubelet 啓動後,可以向 API Server 註冊,定時向 API Server 發送節點的新消息,然後 API Server 收到消息後都會寫入 etcd 中,有一些常用的啓動命令如下。

(2)Pod 管理

kubelet 主要的作用就是監聽 Pod 任務,創建或者刪除,其步驟是:

(3)監控

kubelet 在節點上要監聽 Pod 和 Node,這樣才能將信息上報給 API Server,以便 Master 節點做出決策。

6、kube-proxy

從前面的文章我們已經知道,可以通過 Service 提供對集羣外的服務,其背後的服務實際上是 Node 上的 kube-proxy 模塊,那 kube-proxy 具體做了哪些事情?
(1)每個 Node 上都會啓動 kube-proxy 進程,該進程相當於是一個透明代理,功能是將請求轉發到後端的 Pod 上;
(2)kube-proxy 運行過程中,動態創建與 Service 相關的 Iptables 規則,實現 Cluster IP+NodePort 的流量重定向,並將流量都轉發到 kube-proxy 對應服務的代理端口中;
(3)kube-proxy 查詢和監聽 API Server 中的 Service 和 Endpoints 的變化,創建服務代理對象,創建一個隨機端口,將 Pod 與 Node 本地端口映射,然後通過修改 Iptables 的規則,將請求轉發給映射端口,從而經過 DNAT 轉發到 Pod 內部;

不過值得注意的是現在 k8s 提供 IPVS 的模式,解決了 Iptables 配置規則太多導致的性能問題,具體網絡的一些詳細的內容放到網絡部分具體講解。

第二部分:網絡

k8s 實現網絡通訊主要包括兩個部分:集羣內和集羣外,其中集羣內通訊又包括 Pod 之間的通訊,容器之間的通訊,具體容器之間的通訊可以看《雲原生二十篇 | Docker 網絡篇》這篇文章,這裏已經詳細講述 Docker 的通訊原理,其他的部分接下來我們一起探索。

1、Pod 到 Pod 之間的網絡

Pod 與 Pod 的網絡通訊包括同一個 Node 下的 Pod 和不同 Node 下的 Pod:

(1)相同 Node 下的 Pod

bridge

同一個 Pod 下的通訊其實就是容器和容器之間通訊,其容器通訊如下:

(2)不同 Node 下的 Pod

2、Service 到 Pod 之間網絡

官方架構圖

Service 是一組 pod 的服務抽象,相當於一組 pod 的 LB,負責將請求分發給對應的 pod,Service 會爲這個 LB 提供一個 IP,一般稱爲 cluster IP,下面我們來查看一下 Service,並查看路由轉發規則:

執行如下

[root@VM-0-11-centos ~]# kubectl get services
NAME          CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubernetes    10.254.0.1       <none>        443/TCP        14d
ngx-service   10.254.214.193   <nodes>       80:32500/TCP   5m

查看 iptable,執行 iptables-save:

...
[root@VM-0-11-centos ~]# iptables-save|grep 32500
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/ngx-service:" -m tcp --dport 32500 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/ngx-service:" -m tcp --dport 32500 -j KUBE-SVC-UY6H3HDLGIYXAG5H

[root@VM-0-11-centos ~]# iptables-save|grep KUBE-SVC-UY6H3HDLGIYXAG5H
:KUBE-SVC-UY6H3HDLGIYXAG5H - [0:0]
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/ngx-service:" -m tcp --dport 32500 -j KUBE-SVC-UY6H3HDLGIYXAG5H
-A KUBE-SERVICES -d 10.254.214.193/32 -p tcp -m comment --comment "default/ngx-service: cluster IP" -m tcp --dport 80 -j KUBE-SVC-UY6H3HDLGIYXAG5H
-A KUBE-SVC-UY6H3HDLGIYXAG5H -m comment --comment "default/ngx-service:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-NRDWGG4MSHANWBLB
-A KUBE-SVC-UY6H3HDLGIYXAG5H -m comment --comment "default/ngx-service:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-AV5WRKSNPI6I35GT
-A KUBE-SVC-UY6H3HDLGIYXAG5H -m comment --comment "default/ngx-service:" -j KUBE-SEP-T3MMHN7MMLAMVXYV

[root@VM-0-11-centos ~]# iptables-save|grep KUBE-SEP-AV5WRKSNPI6I35GT
:KUBE-SEP-AV5WRKSNPI6I35GT - [0:0]
-A KUBE-SEP-AV5WRKSNPI6I35GT -s 172.17.0.4/32 -m comment --comment "default/ngx-service:" -j KUBE-MARK-MASQ
-A KUBE-SEP-AV5WRKSNPI6I35GT -p tcp -m comment --comment "default/ngx-service:" -m tcp -j DNAT --to-destination 172.17.0.4:8081
-A KUBE-SVC-UY6H3HDLGIYXAG5H -m comment --comment "default/ngx-service:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-AV5WRKSNPI6I35GT

從上面信息可以看到 clusterIP 的 Port 和 NodePort 都會將 32500 和 80 轉發(執行iptables-save|grep KUBE-SVC-UY6H3HDLGIYXAG5H的輸出)到KUBE-SVC-UY6H3HDLGIYXAG5H,然後KUBE-SVC-UY6H3HDLGIYXAG5H對應-j KUBE-SVC-UY6H3HDLGIYXAG5H,最後KUBE-SEP-AV5WRKSNPI6I35GT映射到-A KUBE-SEP-AV5WRKSNPI6I35GT -p tcp -m comment --comment "default/ngx-service:" -m tcp -j DNAT --to-destination 172.17.0.4:8081,將流量進行導向到後端的 pod 上。
當有多個 Pod 服務,Service 如何實現負載均衡呢?可以看到上面的第二行命令iptables-save|grep KUBE-SVC-UY6H3HDLGIYXAG5H輸出--mode random --probability,這是利用了 iptables 的 --probability 的特性,一定概率進入某個 Pod 中。

3、開源的網絡組件

以下是一些支持 k8s 的開源網絡組件,這裏簡單介紹:

(1)Flannel

Flannel主要功能:

(2)Calico

Calico是一個純三層的虛擬網絡方案,Calico爲每個容器分配一個 IP,每個 host 都是 router,把不同 host 的容器連接起來,與 VxLAN 不同的是,Calico不對數據包做額外封裝,不需要 NAT 和端口映射,擴展性和性能都很好,Calico依賴etcd在不同主機間共享和交換信息,存儲Calico網絡狀態。

(3)Weave

Weave是 Weaveworks 開發的容器網絡解決方案,Weave創建的虛擬網絡可以將部署在多個主機上的容器連接起來。

參考

(1)https://zhuanlan.zhihu.com/p/476740348
(2)https://zhuanlan.zhihu.com/p/450263411?utm_id=0
(3)https://zhuanlan.zhihu.com/p/637672338

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/FiXMBmoC_NhYNbI2To7u0Q