【Kubernetes詳解】(九)k8s 之 核心組件運行機制

一、Kubernetes API Server原理解析

總體來看,Kubernetes API Server的核心功能是提供Kubernetes各類資源對象(如Pod、RC、Service等)的增、刪、改、查及Watch等HTTP Rest接口,成爲集羣內各個功能模塊之間數據交互和通信的中心樞紐, 是整個系統的數據總線和數據中心。除此之外,它還有以下一些功能特性:

  • 是集羣管理的API入口。
  • 是資源配額控制的入口。
  • 提供了完備的集羣安全機制。

1.1、Kubernetes API Server概述

Kubernetes API Server通過一個名爲kube-apiserver的進程提供服務,該進程運行在Master上。在默認情況下,kube-apiserver進程在本機 的8080端口(對應參數–insecure-port)提供REST服務。我們可以同時啓動HTTPS安全端口(–secure-port=6443)來啓動安全機制,加強 REST API 訪問的安全性。
使用方式:

  • 我們通常可以通過命令行工具kubectl來與Kubernetes API Server交互,它們之間的接口是RESTful API。
  • 使用curl直接調用API Server 接口

使用場景:

  • 運行在Pod裏的用戶進程調用Kubernetes API,通 常用來實現分佈式集羣搭建的目標。
  • 開發基於Kubernetes的管理平臺。比如調用 Kubernetes API來完成Pod、Service、RC等資源對象的圖形化創建和管理界面。

由於API Server是Kubernetes集羣數據的唯一訪問入口,因此安全性與高性能就成爲API Server設計和實現的兩大核心目標。通過採用 HTTPS安全傳輸通道與CA簽名數字證書強制雙向認證的方式,API Server的安全性得以保障。此外,爲了更細粒度地控制用戶或應用對 Kubernetes資源對象的訪問權限,Kubernetes啓用了RBAC訪問控制策 略。
API Server的性能是決定Kubernetes集羣整體性能的關鍵因素,因此 Kubernetes的設計者綜合運用以下方式來最大程度地保證API Server的性能。

  • API Server擁有大量高性能的底層代碼。在API Server源碼中 使用協程(Coroutine)+隊列(Queue)這種輕量級的高性能併發代碼, 使得單進程的API Server具備了超強的多核處理能力,從而以很快的速度併發處理大量的請求。
  • 普通List接口結合異步Watch接口,不但完美解決了 Kubernetes中各種資源對象的高性能同步問題,也極大提升了Kubernetes 集羣實時響應各種事件的靈敏度。
  • 採用了高性能的etcd數據庫而非傳統的關係數據庫,不僅解決了數據的可靠性問題,也極大提升了API Server數據訪問層的性能。在 常見的公有云環境中,一個3節點的etcd集羣在輕負載環境中處理一個請 求的時間可以低於1ms,在重負載環境中可以每秒處理超過30000個請求。

正是由於採用了上述提升性能的方法,API Server可以支撐很大規 模的Kubernetes集羣。

1.2、API Server架構解析

API Server的架構從上到下可以分爲以下幾層,如下圖所示:
在這裏插入圖片描述

  • API層:主要以REST方式提供各種API接口,除了有 Kubernetes 資源對象的CRUD和Watch等主要API,還有健康檢查、UI、 日誌、性能指標等運維監控相關的API。Kubernetes從1.11版本開始廢棄 Heapster 監控組件,轉而使用 Metrics Server 提供Metrics API接口,進一 步完善了自身的監控能力。
  • 訪問控制層:當客戶端訪問API接口時,訪問控制層負責對用戶身份鑑權,驗明用戶身份,覈准用戶對Kubernetes資源對象的訪問權限,然後根據配置的各種資源訪問許可邏輯(Admission Control),判斷是否允許訪問。
  • 註冊表層:Kubernetes把所有資源對象都保存在註冊表 (Registry)中,針對註冊表中的各種資源對象都定義了:資源對象的類型、如何創建資源對象、如何轉換資源的不同版本,以及如何將資源編碼和解碼爲JSON或ProtoBuf格式進行存儲。
  • etcd數據庫:用於持久化存儲Kubernetes資源對象的KV數據庫。etcd的watch API接口對於API Server來說至關重要,因爲通過這個接口,API Server 創新性地設計了List-Watch這種高性能的資源對象實時同步機制,使Kubernetes可以管理超大規模的集羣,及時響應和快速處理集羣中的各種事件。

1.3、List-Watch機制

從本質上看,API Server與常見的MIS或ERP系統中的DAO模塊類似,可以將主要處理邏輯視作對數據庫表的CRUD操作。這裏解讀API Server中資源對象的List-Watch機制。下圖以一個完整的Pod調度過程爲例,對API Server的List-Watch機制進行說明。在這裏插入圖片描述
首先,藉助etcd提供的Watch API接口,API Server可以監聽 (Watch)在etcd上發生的數據操作事件,比如Pod創建事件、更新事件、刪除事件等,在這些事件發生後,etcd會及時通知API Server。上圖中API Server與etcd之間的交互箭頭表明了這個過程:當一個 ReplicaSet對象被創建並被保存到etcd中後(圖中的2.Create RepliatSet箭頭),etcd會立即發送一個對應的Create事件給API Server(圖中的 3.Send RepliatSet Create Event箭頭),與其類似的6、7、10、11箭頭都是針對Pod的創建、更新事件的。
然後,爲了讓Kubernetes中的其他組件在不訪問底層etcd數據庫的情況下,也能及時獲取資源對象的變化事件,API Server模仿etcd的 Watch API接口提供了自己的Watch接口,這樣一來,這些組件就能近乎實時地獲取它們感興趣的任意資源對象的相關事件通知了。圖中 controller-manager、scheduler、kublet等組件與API Server之間的3個標記 有List-Watch的虛框表明了這個過程。同時,在監聽自己感興趣的資源的時候,客戶端可以增加過濾條件,以List-Watch 3爲例,node1節點上的kubelet進程只對自己節點上的Pod事件感興趣。
最後,Kubernetes List-Watch用於實現數據同步的代碼邏輯。客戶端首先調用API Server的List接口獲取相關資源對象的全量數據並將其緩存到內存中,然後啓動對應資源對象的Watch協程,在接收到Watch事件後,再根據事件的類型(比如新增、修改或刪除)對內存中的全量資源對象列表做出相應的同步修改,從實現上來看,這是一種全量結合增量的、高性能的、近乎實時的數據同步方式。

1.4、集羣功能模塊之間的通信

Kubernetes API Server作爲集羣的核心,負責 集羣各功能模塊之間的通信。集羣內的各個功能模塊通過API Server將 信息存入etcd,當需要獲取和操作這些數據時,則通過API Server提供的 REST接口(用GET、LIST或W A TCH方法)來實現,從而實現各模塊之 間的信息交互。在這裏插入圖片描述

  • 常見的一個交互場景是kubelet進程與API Server的交互。每個Node 上的kubelet每隔一個時間週期,就會調用一次API Server的REST接口報 告自身狀態,API Server在接收到這些信息後,會將節點狀態信息更新 到etcd中。此外,kubelet也通過API Server的Watch接口監聽Pod信息, 如果監聽到新的Pod副本被調度綁定到本節點,則執行Pod對應的容器創 建和啓動邏輯;如果監聽到Pod對象被刪除,則刪除本節點上相應的Pod 容器;如果監聽到修改Pod的信息,kubelet就會相應地修改本節點的Pod 容器。
  • 另一個交互場景是kube-controller-manager進程與API Server的交互。kube-controller-manager中的Node Controller模塊通過API Server提供 的Watch接口實時監控Node的信息,並做相應處理。
  • 還有一個比較重要的交互場景是kube-scheduler與API Server的交 互。Scheduler通過API Server的Watch接口監聽到新建Pod副本的信息 後,會檢索所有符合該Pod要求的Node列表,開始執行Pod調度邏輯, 在調度成功後將Pod綁定到目標節點上。

爲了緩解集羣各模塊對API Server的訪問壓力,各功能模塊都採用 緩存機制來緩存數據。各功能模塊定時從API Server獲取指定的資源對 象信息(通過List-Watch方法),然後將這些信息保存到本地緩存中, 功能模塊在某些情況下不直接訪問API Server,而是通過訪問緩存數據 來間接訪問API Server。

二、Controller Manager原理解析

2.1、Replication Controller

爲了區分Controller Manager中的Replication Controller(副本控制 器)和資源對象Replication Controller,我們將資源對象Replication Controller簡寫爲RC,而本節中的Replication Controller是指“副本控制器”,以便於後續分析。
Replication Controller的核心作用是確保在任何時候集羣中某個RC 關聯的Pod副本數量都保持預設值。如果發現Pod的副本數量超過預期 值,則Replication Controller會銷燬一些Pod副本;反之,Replication Controller會自動創建新的Pod副本,直到符合條件的Pod副本數量達到 預設值。需要注意:只有當Pod的重啓策略是Always時 (RestartPolicy=Always),Replication Controller纔會管理該Pod的操作(例如創建、銷燬、重啓等)。在通常情況下,Pod對象被成功創建後 不會消失,唯一的例外是當Pod處於succeeded或failed狀態的時間過長 (超時參數由系統設定)時,該Pod會被系統自動回收,管理該Pod的副 本控制器將在其他工作節點上重新創建、運行該Pod副本。
RC中的Pod模板就像一個模具,模具製作出來的東西一旦離開模 具,它們之間就再也沒關係了。同樣,一旦Pod被創建完畢,無論模板 如何變化,甚至換成一個新的模板,也不會影響到已經創建的Pod了。 此外,Pod可以通過修改它的標籤來脫離RC的管控。該方法可以用於將 Pod從集羣中遷移、數據修復等調試。對於被遷移的Pod副本,RC會自 動創建一個新的副本替換被遷移的副本。需要注意的是,刪除一個RC 不會影響它所創建的Pod。如果想刪除一個被RC所控制的Pod,則需要 將該RC的副本數(Replicas)屬性設置爲0,這樣所有的Pod副本就都會 被自動刪除。
最好不要越過RC直接創建Pod,因爲Replication Controller會通過RC 管理Pod副本,實現自動創建、補足、替換、刪除Pod副本,這樣能提高 系統的容災能力,減少由於節點崩潰等意外狀況造成的損失。即使你的 應用程序只用到一個Pod副本,我們也強烈建議你使用RC來定義Pod。
總結一下Replication Controller的職責,如下所述:

  • 確保在當前集羣中有且僅有N個Pod實例,N是在RC中定義的Pod副本數量。
  • 通過調整RC的spec.replicas屬性值來實現系統擴容或者縮容。
  • 通過改變RC中的Pod模板(主要是鏡像版本)來實現系統的 滾動升級。

2.2、Node Controller

kubelet進程在啓動時通過API Server註冊自身的節點信息,並定時 向API Server彙報狀態信息,API Server在接收到這些信息後,會將這些 信息更新到etcd中。在etcd中存儲的節點信息包括節點健康狀況、節點 資源、節點名稱、節點地址信息、操作系統版本、Docker版本、kubelet 版本等。節點健康狀況包含“就緒”(True)“未就緒”(False)和“未 知”(Unknown)三種。

2.3、ResourceQuota Controller

作爲完備的企業級的容器集羣管理平臺,Kubernetes也提供了 ResourceQuota Controller(資源配額管理)這一高級功能,資源配額管 理確保了指定的資源對象在任何時候都不會超量佔用系統物理資源,避 免了由於某些業務進程的設計或實現的缺陷導致整個系統運行紊亂甚至 意外宕機,對整個集羣的平穩運行和穩定性有非常重要的作用。
目前Kubernetes支持如下三個層次的資源配額管理。

  • 容器級別,可以對CPU和Memory進行限制。
  • Pod級別,可以對一個Pod內所有容器的可用資源進行限制。
  • Namespace級別,爲Namespace(多租戶)級別的資源限制, 包括:
    • Pod數量;
    • Replication Controller數量;
    • Service數量;
    • ResourceQuota數量;
    • Secret數量;
    • 可持有的PV數量。

Kubernetes的配額管理是通過Admission Control(准入控制)來控制 的,Admission Control當前提供了兩種方式的配額約束,分別是 LimitRanger與ResourceQuota。其中LimitRanger作用於Pod和Container, ResourceQuota則作用於Namespace,限定一個Namespace裏的各類資源 的使用總額。

2.4、Namespace Controller

用戶通過API Server可以創建新的Namespace並將其保存在etcd中, Namespace Controller定時通過API Server讀取這些Namespace的信息。如 果Namespace被API標識爲優雅刪除(通過設置刪除期限實現,即設置 DeletionTimestamp屬性),則將該NameSpace的狀態設置成Terminating 並保存到etcd中。同時Namespace Controller刪除該Namespace下的 ServiceAccount、RC、Pod、Secret、PersistentV olume、ListRange、 ResourceQuota和Event等資源對象。
在Namespace的狀態被設置成Terminating後,由Admission Controller的NamespaceLifecycle插件來阻止爲該Namespace創建新的資 源。同時,在Namespace Controller刪除該Namespace中的所有資源對象 後,Namespace Controller對該Namespace執行finalize操作,刪除Namespace的spec.finalizers域中的信息。
如果Namespace Controller觀察到Namespace設置了刪除期限,同時 Namespace的spec.finalizers域值是空的,那麼Namespace Controller將通過API Server刪除該Namespace資源。

2.5、Service Controller與Endpoints Controller

2.5.1、Endpoints Controller

在這之前,讓我們先看看Service、 Endpoints與Pod的關係。如下圖所示,Endpoints表示一個Service對應的所有Pod副本的訪問地址
Endpoints Controller就是負責生成和維護所有Endpoints對象的控制器:
在這裏插入圖片描述
它負責監聽Service和對應的Pod副本的變化,如果監測到Service被 刪除,則刪除和該Service同名的Endpoints對象。如果監測到新的Service 被創建或者修改,則根據該Service信息獲得相關的Pod列表,然後創建 或者更新Service對應的Endpoints對象。如果監測到Pod的事件,則更新 它所對應的Service的Endpoints對象(增加、刪除或者修改對應的 Endpoint條目)。

那麼,Endpoints對象是在哪裏被使用的呢?
答案是每個Node上的 kube-proxy進程,kube-proxy進程獲取每個Service的Endpoints,實現了 Service的負載均衡功能。

2.5.2、Service Controller

它其實是屬於Kubernetes集羣 與外部的雲平臺之間的一個接口控制器。Service Controller監聽Service 的變化,如果該Service是一個LoadBalancer類型的 Service(externalLoadBalancers=true),則Service Controller確保在外部 的雲平臺上該Service對應的LoadBalancer實例被相應地創建、刪除及更 新路由轉發表(根據Endpoints的條目)

三、Scheduler原理解析

前面深入分析了Controller Manager及它所包含的各個組件的運行機 制,本節將繼續對Kubernetes中負責Pod調度的重要功能模塊— Kubernetes Scheduler的工作原理和運行機制做深入分析。

Kubernetes Scheduler在整個系統中承擔了“承上啓下”的重要功 能,“承上”是指它負責接收Controller Manager創建的新Pod,爲其安排 一個落腳的“家”—目標Node;“啓下”是指安置工作完成後,目標Node上 的kubelet服務進程接管後繼工作,負責Pod生命週期中的“下半生”。
具體來說,Kubernetes Scheduler的作用是將待調度的Pod(API新創 建的Pod、Controller Manager爲補足副本而創建的Pod等)按照特定的調度算法和調度策略綁定(Binding)到集羣中某個合適的Node上,並將 綁定信息寫入etcd中。在整個調度過程中涉及三個對象,分別是待調度 Pod列表、可用Node列表,以及調度算法和策略。簡單地說,就是通過 調度算法調度爲待調度Pod列表中的每個Pod從Node列表中選擇一個最 適合的Node。
隨後,目標節點上的kubelet通過API Server監聽到Kubernetes Scheduler產生的Pod綁定事件,然後獲取對應的Pod清單,下載Image鏡像並啓動容器。完整的流程如下圖:
在這裏插入圖片描述
Kubernetes Scheduler當前提供的默認調度流程分爲以下兩步:

  • 預選調度過程,即遍歷所有目標Node,篩選出符合要求的候 選節點。爲此,Kubernetes內置了多種預選策略(xxx Predicates)供用 戶選擇。
  • 確定最優節點,在第1步的基礎上,採用優選策略(xxx Priority)計算出每個候選節點的積分,積分最高者勝出。

Kubernetes Scheduler的調度流程是通過插件方式加載的“調度算法 提供者”(AlgorithmProvider)具體實現的。一個AlgorithmProvider其實 就是包括了一組預選策略與一組優先選擇策略的結構體。

四、kubelet運行機制解析

在Kubernetes集羣中,在每個Node(又稱Minion)上都會啓動一個 kubelet服務進程。該進程用於處理Master下發到本節點的任務,管理 Pod及Pod中的容器。每個kubelet進程都會在API Server上註冊節點自身 的信息,定期向Master彙報節點資源的使用情況,並通過cAdvisor監控 容器和節點資源。

4.1、節點管理

kubelet在啓動時通過API Server註冊節點信息,並定時向API Server 發送節點的新消息,API Server在接收到這些信息後,將這些信息寫入 etcd。通過kubelet的啓動參數“–node-status- update-frequency”設置 kubelet每隔多長時間向API Server報告節點狀態,默認爲10s。

節點通過設置kubelet的啓動參數“–register-node”,來決定是否向 API Server註冊自己。如果該參數的值爲true,那麼kubelet將試着通過 API Server註冊自己。
當前每個kubelet都被授予創建和修改任何節點的權限。但是在實踐中,它僅僅創建和修改自己。將來,我們計劃限制kubelet的權限,僅允許它修改和創建所在節點的權限。如果在集羣運行過程中遇到集羣資源不足的情況,用戶就很容易通過添加機器及運用kubelet的自注冊模式來 實現擴容。

4.2、Pod管理

kubelet通過以下幾種方式獲取自身Node上要運行的Pod清單。

  • 文件:kubelet啓動參數“–config”指定的配置文件目錄下的文 件(默認目錄爲“/etc/ kubernetes/manifests/”)。通過–file-check- frequency設置檢查該文件目錄的時間間隔,默認爲20s。
  • HTTP端點(URL):通過“–manifest-url”參數設置。通過-- http-check-frequency設置檢查該HTTP端點數據的時間間隔,默認爲 20s。
  • API Server:kubelet通過API Server監聽etcd目錄,同步Pod列表。

kubelet監聽etcd,所有針對Pod的操作都會被kubelet監聽。如果發現有新的綁定到本節點的Pod,則按照Pod清單的要求創建該Pod。
如果發現本地的Pod被修改,則kubelet會做出相應的修改,比如在刪除Pod中的某個容器時,會通過Docker Client刪除該容器。 如果發現刪除本節點的Pod,則刪除相應的Pod,並通過DockerClient刪除Pod中的容器。 kubelet讀取監聽到的信息,如果是創建和修改Pod任務,則做如下處理:

  • 爲該Pod創建一個數據目錄。
  • 從API Server讀取該Pod清單。
  • 爲該Pod掛載外部卷(External Volume)。下載Pod用到的Secret。
  • 檢查已經運行在節點上的Pod,如果該Pod沒有容器或Pause容 器(“kubernetes/pause”鏡像創建的容器)沒有啓動,則先停止Pod裏所 有容器的進程。如果在Pod中有需要刪除的容器,則刪除這些容器。
  • 用“kubernetes/pause”鏡像爲每個Pod都創建一個容器。該Pause 容器用於接管Pod中所有其他容器的網絡。每創建一個新的Pod,kubelet 都會先創建一個Pause容器,然後創建其他容器。“kubernetes/pause”鏡像 大概有200KB,是個非常小的容器鏡像。
  • 爲Pod中的每個容器做如下處理。
    • 爲容器計算一個Hash值,然後用容器的名稱去查詢對應Docker 容器的Hash值。若查找到容器,且二者的Hash值不同,則停止Docker中 容器的進程,並停止與之關聯的Pause容器的進程;若二者相同,則不做任何處理。
    • 如果容器被終止了,且容器沒有指定的restartPolicy(重啓策 略),則不做任何處理
    • 調用Docker Client下載容器鏡像,調用Docker Client運行容器。

4.3、容器健康檢查

Pod通過兩類探針來檢查容器的健康狀態。

  • 一類是LivenessProbe探 針,用於判斷容器是否健康並反饋給kubelet。如果LivenessProbe探針探 測到容器不健康,則kubelet將刪除該容器,並根據容器的重啓策略做相 應的處理。如果一個容器不包含LivenessProbe探針,那麼kubelet認爲該 容器的LivenessProbe探針返回的值永遠是Success;
  • 另一類是 ReadinessProbe探針,用於判斷容器是否啓動完成,且準備接收請求。 如果ReadinessProbe探針檢測到容器啓動失敗,則Pod的狀態將被修改, Endpoint Controller將從Service的Endpoint中刪除包含該容器所在Pod的IP 地址的Endpoint條目。

4.4、cAdvisor資源監控

在Kubernetes集羣中,應用程序的執行情況可以在不同的級別上監 測到,這些級別包括:容器、Pod、Service和整個集羣。作爲Kubernetes 集羣的一部分,Kubernetes希望提供給用戶詳細的各個級別的資源使用信息,這將使用戶深入地瞭解應用的執行情況,並找到應用中可能的瓶頸。

cAdvisor是一個開源的分析容器資源使用率和性能特性的代理工 具,它是因爲容器而產生的,因此自然支持Docker容器;在Kubernetes 項目中,cAdvisor被集成到Kubernetes代碼中,kubelet則通過cAdvisor獲 取其所在節點及容器的數據。cAdvisor自動查找所有在其所在Node上的容器,自動採集CPU、內存、文件系統和網絡使用的統計信息。在大部分Kubernetes集羣中,cAdvisor通過它所在Node的4194端口暴露一個簡單的UI。
kubelet作爲連接Kubernetes Master和各Node之間的橋樑,管理運行在Node上的Pod和容器。 kubelet將每個Pod都轉換成它的成員容器,同時從cAdvisor獲取單獨的容器使用統計信息,然後通過該REST API暴露 這些聚合後的Pod資源使用的統計信息。

cAdvisor只能提供2~3min的監控數據,對性能數據也沒有持久化,因此在Kubernetes早期版本中需要依靠Heapster來實現集羣範圍內全部容器性能指標的採集和查詢功能。從Kubernetes 1.8版本開始,性能指標數據的查詢接口升級爲標準的Metrics API,後端服務則升級爲全新的 Metrics Server。因此,cAdvisor在4194端口提供的UI和API服務從Kubernetes 1.10版本開始cAdvisor進入棄用流程,並於1.12版本完全關閉。如果還希望使用cAdvisor的這個特性,則從1.13版本開始可以通過部署一個 DaemonSet在每個Node上啓動一個cAdvisor來提供UI和API,請參考 cAdvisor在GitHub上的說明(https://github.com/google/cadvisor)。
在新的Kubernetes監控體系中,Metrics Server用於提供Core Metrics(核心指標),包括Node和Pod的CPU和內存使用數據。其他 Custom Metrics(自定義指標)則由第三方組件(如Prometheus)採集和存儲。

五、kube-proxy運行機制解析

我們在前面已經瞭解到,爲了支持集羣的水平擴展、高可用性, Kubernetes抽象出了Service的概念。Service是對一組Pod的抽象,它會根 據訪問策略(如負載均衡策略)來訪問這組Pod。

Kubernetes在創建服務時會爲服務分配一個虛擬的IP地址,客戶端通過訪問這個虛擬的IP地址來訪問服務,服務則負責將請求轉發到後端 的Pod上。這不就是一個反向代理嗎?沒錯,這就是一個反向代理。但是,它和普通的反向代理有一些不同:首先,它的IP地址是虛擬的,想從外面訪問還需要一些技巧;其次,它的部署和啓停是由Kubernetes統 一自動管理的。
在很多情況下,Service只是一個概念,而真正將Service的作用落實的是它背後的kube-proxy服務進程。只有理解了kube-proxy的原理和機 制,我們才能真正理解Service背後的實現邏輯。

在Kubernetes集羣的每個Node上都會運行一個kube-proxy服務進程,我們可以把這個進程看作Service的透明代理兼負載均衡器,其核心功能是將到某個Service的訪問請求轉發到後端的多個Pod實例上。此外,Service的Cluster IP與NodePort等概念是kube-proxy服務通過iptables 的NAT轉換實現的,kube-proxy在運行過程中動態創建與Service相關的 iptables規則,這些規則實現了將訪問服務(Cluster IP或NodePort)的請 求負載分發到後端Pod的功能。由於iptables機制針對的是本地的kube-proxy端口,所以在每個Node上都要運行kube-proxy組件,這樣一來,在 Kubernetes集羣內部,我們可以在任意Node上發起對Service的訪問請求。綜上所述,由於kube-proxy的作用,在Service的調用過程中客戶端無須關心後端有幾個Pod,中間過程的通信、負載均衡及故障恢復都是透明的。

起初,kube-proxy進程是一個真實的TCP/UDP代理,類似HA Proxy,負責從Service到Pod的訪問流量的轉發,這種模式被稱爲 userspace(用戶空間代理)模式。如下圖所示,當某個Pod以Cluster IP方式訪問某個Service的時候,這個流量會被Pod所在本機的iptables轉 發到本機的kube-proxy進程,然後由kube-proxy建立起到後端Pod的 TCP/UDP連接,隨後將請求轉發到某個後端Pod上,並在這個過程中實 現負載均衡功能。
在這裏插入圖片描述
關於Cluster IP與Node Port的實現原理,以及kube-proxy與API Server 的交互過程,下圖給出了較爲詳細的說明,由於這是最古老的kube- proxy的實現方式,所以不再贅述:
在這裏插入圖片描述

Kubernetes從1.2版本開始,將iptables作爲kube- proxy的默認模式。iptables模式下的kube-proxy不再起到Proxy的作用, 其核心功能:通過API Server的Watch接口實時跟蹤Service與Endpoint的 變更信息,並更新對應的iptables規則,Client的請求流量則通過iptables 的NAT機制“直接路由”到目標Pod。 如下圖:
在這裏插入圖片描述

根據Kubernetes的網絡模型,一個Node上的Pod與其他Node上的Pod 應該能夠直接建立雙向的TCP/IP通信通道,所以如果直接修改iptables規 則,則也可以實現kube-proxy的功能,只不過後者更加高端,因爲是全 自動模式的。與第1代的userspace模式相比,iptables模式完全工作在內 核態,不用再經過用戶態的kube-proxy中轉,因而性能更強。
iptables模式雖然實現起來簡單,但存在無法避免的缺陷:在集羣中 的Service和Pod大量增加以後,iptables中的規則會急速膨脹,導致性能 顯著下降,在某些極端情況下甚至會出現規則丟失的情況,並且這種故 障難以重現與排查,於是Kubernetes從1.8版本開始引入第3代的 IPVS(IP Virtual Server)模式,如下圖所示。IPVS在Kubernetes 1.11 中升級爲GA穩定版:
在這裏插入圖片描述
iptables與IPVS雖然都是基於Netfilter實現的,但因爲定位不同,二者有着本質的差別:iptables是爲防火牆而設計的;IPVS則專門用於高 性能負載均衡,並使用更高效的數據結構(Hash表),允許幾乎無限的規模擴張,因此被kube-proxy採納爲第三代模式。

與iptables相比,IPVS擁有以下明顯優勢:

  • 爲大型集羣提供了更好的可擴展性和性能;
  • 支持比iptables更復雜的複製均衡算法(最小負載、最少連接、 加權等);
  • 支持服務器健康檢查和連接重試等功能;
  • 可以動態修改ipset的集合,即使iptables的規則正在使用這個集合。

由於IPVS無法提供包過濾、airpin-masquerade tricks(地址僞裝)、 SNA T等功能,因此在某些場景(如NodePort的實現)下還要與iptables 搭配使用。在IPVS模式下,kube-proxy又做了重要的升級,即使用 iptables的擴展ipset,而不是直接調用iptables來生成規則鏈。
iptables規則鏈是一個線性的數據結構,ipset則引入了帶索引的數據 結構,因此當規則很多時,也可以很高效地查找和匹配。我們可以將 ipset簡單理解爲一個IP(段)的集合,這個集合的內容可以是IP地址、 IP網段、端口等,iptables可以直接添加規則對這個“可變的集合”進行操 作,這樣做的好處在於可以大大減少iptables規則的數量,從而減少性能損耗。
假設要禁止上萬個IP訪問我們的服務器,則用iptables的話,就需要 一條一條地添加規則,會在iptables中生成大量的規則;但是用ipset的 話,只需將相關的IP地址(網段)加入ipset集合中即可,這樣只需設置 少量的iptables規則即可實現目標。

kube-proxy針對Service和Pod創建的一些主要的iptables規則如下。

  • KUBE-CLUSTER-IP:在masquerade-all=true或clusterCIDR指定的情況下對Service Cluster IP地址進行僞裝,以解決數據包欺騙問題。
  • KUBE-EXTERNAL-IP:將數據包僞裝成Service的外部IP地址。
  • KUBE-LOAD-BALANCER、KUBE-LOAD-BALANCER-LOCAL:僞裝Load Balancer 類型的Service流量。
  • KUBE-NODE-PORT-TCP、KUBE-NODE-PORT-LOCAL- TCP、KUBE-NODE-PORTUDP、KUBE-NODE-PORT-LOCAL-UDP: 僞裝NodePort類型的Service流量。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章