帶你玩轉kubernetes-k8s(第35篇:核心組件運行機制-kube-proxy與 manger-controller)

獨特的Kubernetes Proxy API接口

      前面講到,Kubernetes API Server最主要的REST接口是資源對象的增、刪、改、查接口,除此之外,它還提供了一類很特殊的REST接口—Kubernetes Proxy API接口,這類接口的作用是代理REST請求,即Kubernetes API Server把收到的REST請求轉發到某個Node上的kubelet守護進程的REST端口,由該kubelet進程負責響應。
     首先來說說Kubernetes Proxy API裏關於Node的相關接口。該接口的REST路徑爲/api/v1/proxy/nodes/{name},其中{name}爲節點的名稱或IP地址,包括以下幾個具體接口:

/api/v1/proxy/nodes/{name}/pods/   #列出指定節點內所有Pod的信息
/api/v1/proxy/nodes/{name}/stats/   #列出指定節點內物理資源的統計信息
/api/v1/proxy/nodes/{name}/spec/    #列出指定節點的概要信息

例如,當前Node的名稱爲k8s-node1,用下面的命令即可獲取該節點上所有運行中的Pod

curl localhost:8080/api/v1/proxy/nodes/k8s-node1/pods

      需要說明的是:這裏獲取的Pod的信息數據來自Node而非etcd數據庫,所以兩者可能在某些時間點有所偏差。此外,如果kubelet進程在啓動時包含--enable-debugginghandlers =true參數,那麼Kubernetes Proxy API還會增加下面的接口:

/api/v1/proxy/nodes/{name}/run           #在節點上運行某個容器
/api/v1/proxy/nodes/{name}/exec          # 在節點上的某個容器中運行某條命令
/api/v1/proxy/nodes/{name}/attach        # 在節點上attach 某個容器
/api/v1/proxy/nodes/{name}/prorFoward    # 在節點上的Pod端口轉發
/api/v1/proxy/nodes/{name}/logs          # 列出節點的各類日誌信息
/api/v1/proxy/nodes/{name}/metrics       # 列出和該節點相關的Metrics信息
/api/v1/proxy/nodes/{name}/runingpods    # 列出節點內運行的pod信息
/api/v1/proxy/nodes/{name}/debug/pprof   # 包括CPU佔用情況和內存使用情況

        接下來說說Kubernetes Proxy API 裏關於Pod的相關接口,通過這些接口,我們可以訪問Pod裏某個容器提供的服務(如 Tomcat在8080端口的服務):

/api/v1/proxy/namespaces/{namespace}/pods/{name}/{path:*}  # 訪問pod的某個服務接口
/api/v1/proxy/namespaces/{namespace}/pods/{name}             #訪問Pod
/api/v1/namespaces/{namespace}/pods/{name}/proxy/{path:*}  # 訪問pod的某個服務接口
/api/v1/namespaces/{namespace}/pods/{name}/proxy    # 訪問pod

      在上面的4個接口裏,後面兩個接口的功能與前面兩個完全一樣,只是寫法不同。下

      Pod的Proxy接口的作用和意義了:在Kubernetes集羣之外訪問某個Pod容器的服務(HTTP服務)時,可以用Proxy API實現,這種場景多用於管理目的,比如逐一排查Service的Pod副本,檢查哪些Pod的服務存在異常。

      最後說說Service。Kubernetes Proxy API也有Service的Proxy接口,其接口定義與Pod的接口定義基本一樣:/api/v1/proxy/namespaces/{namespace}/services/{name}。比如,若我們想訪問MyWeb這個Service,則可以在瀏覽器裏輸入http://192.168.18.131:8080/api/v1/proxy/namespaces/default/services/myweb/demo/。

集羣功能模塊之間的通信

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

     常見的一個交互場景是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原理解析

    一般來說,智能系統和自動系統通常會通過一個“操作系統”來不斷修正系統的工作狀態。在Kubernetes集羣中,每個Controller都是這樣的一個“操作系統”,它們通過API Server提供的(List-Watch)接口實時監控集羣中特定資源的狀態變化,當發生各種故障導致某資源對象的狀態發生變化時,Controller會嘗試將其狀態調整爲期望的狀態。比如當某個Node意外宕機時,Node Controller會及時發現此故障並執行自動化修復流程,確保集羣始終處於預期的工作狀態。Controller Manager是Kubernetes中各種操作系統的管理者,是集羣內部的管理控制中心,也是Kubernetes自動化功能的核心

    Controller Manager內部包含Replication Controller、Node Controller、ResourceQuota Controller、Namespace Controller、ServiceAccount Controller、Token Controller、Service Controller及Endpoint Controller這8種Controller,每種Controller都負責一種特定資源的控制流程,而Controller Manager正是這些Controller的核心管理者。
    由於ServiceAccount Controller與Token Controller是與安全相關的兩個控制器,並且與Service Account、Token密切相關,所以我們將對它們的分析放到後面講解。

     在Kubernetes集羣中與Controller Manager並重的另一個組件是Kubernetes Scheduler,它的作用是將待調度的Pod(包括通過API Server新創建的Pod及RC爲補足副本而創建的Pod等)通過一些複雜的調度流程計算出最佳目標節點,然後綁定到該節點上。

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的職責,如下所述。
(1)確保在當前集羣中有且僅有N個Pod實例,N是在RC中定義的Pod副本數量。
(2)通過調整RC的spec.replicas屬性值來實現系統擴容或者縮容。
(3)通過改變RC中的Pod模板(主要是鏡像版本)來實現系統的滾動升級。

最後總結一下Replication Controller的典型使用場景,如下所述。

(1)重新調度(Rescheduling)。如前面所述,不管想運行1個副本還是1000個副本,副本控制器都能確保指定數量的副本存在於集羣中,即使發生節點故障或Pod副本被終止運行等意外狀況。
(2)彈性伸縮(Scaling)。手動或者通過自動擴容代理修改副本控制器的spec.replicas屬性值,非常容易實現增加或減少副本的數量。
(3)滾動更新(Rolling Updates)。副本控制器被設計成通過逐個替換Pod的方式來輔助服務的滾動更新。推薦的方式是創建一個只有一個副本的新RC,若新RC副本數量加1,則舊RC的副本數量減1,直到這個舊RC的副本數量爲0,然後刪除該舊RC。通過上述模式,即使在滾動更新的過程中發生了不可預料的錯誤,Pod集合的更新也都在可控範圍內。在理想情況下,滾動更新控制器需要將準備就緒的應用考慮在內,並保證在集羣中任何時刻都有足夠數量的可用Pod。

Node Controller

     kubelet進程在啓動時通過API Server註冊自身的節點信息,並定時向API Server彙報狀態信息,API Server在接收到這些信息後,會將這些信息更新到etcd中。在etcd中存儲的節點信息包括節點健康狀況、節點資源、節點名稱、節點地址信息、操作系統版本、Docker版本、kubelet版本等。節點健康狀況包含“就緒”(True)“未就緒”(False)和“未知”(Unknown)三種。
Node Controller通過API Server實時獲取Node的相關信息,實現管理和監控集羣中的各個Node的相關控制功能,Node Controller的核心工作流程如圖所示。

對流程中關鍵點的解釋如下。
(1)Controller Manager在啓動時如果設置了--cluster-cidr參數,那麼爲每個沒有設置Spec.PodCIDR的Node都生成一個CIDR地址,並用該CIDR地址設置節點的Spec.PodCIDR屬性,這樣做的目的是防止不同節點的CIDR地址發生衝突。
(2)逐個讀取Node信息,多次嘗試修改nodeStatusMap中的節點狀態信息,將該節點信息和Node Controller的nodeStatusMap中保存的節點信息做比較。如果判斷出沒有收到kubelet發送的節點信息、第1次收到節點kubelet發送的節點信息,或在該處理過程中節點狀態變成非“健康”狀態,則在nodeStatusMap中保存該節點的狀態信息,並用Node Controller所在節點的系統時間作爲探測時間和節點狀態變化時間。如果判斷出在指定時間內收到新的節點信息,且節點狀態發生變化,則在nodeStatusMap中保存該節點的狀態信息,並用Node Controller所在節點的系統時間作爲探測時間和節點狀態變化時間。如果判斷出在指定時間內收到新的節點信息,但節點狀態沒發生變化,則在nodeStatusMap中保存該節點的狀態信息,並用Node Controller所在節點的系統時間作爲探測時間,將上次節點信息中的節點狀態變化時間作爲該節點的狀態變化時間。如果判斷出在某段時間(gracePeriod)內沒有收到節點狀態信息,則設置節點狀態爲“未知”,並且通過API Server保存節點狀態。
(3)逐個讀取節點信息,如果節點狀態變爲非“就緒”狀態,則將節點加入待刪除隊列,否則將節點從該隊列中刪除。如果節點狀態爲非“就緒”狀態,且系統指定了Cloud Provider,則Node Controller調用Cloud Provider查看節點,若發現節點故障,則刪除etcd中的節點信息,並刪除和該節點相關的Pod等資源的信息。

ResourceQuota Controller

    作爲完備的企業級的容器集羣管理平臺,Kubernetes也提供了ResourceQuota Controller(資源配額管理)這一高級功能,資源配額管理確保了指定的資源對象在任何時候都不會超量佔用系統物理資源,避免了由於某些業務進程的設計或實現的缺陷導致整個系統運行紊亂甚至意外宕機,對整個集羣的平穩運行和穩定性有非常重要的作用。
目前Kubernetes支持如下三個層次的資源配額管理。
(1)容器級別,可以對CPU和Memory進行限制。
(2)Pod級別,可以對一個Pod內所有容器的可用資源進行限制。
(3)Namespace級別,爲Namespace(多租戶)級別的資源限制,包括:
◎ Pod數量;
◎ Replication Controller數量;
◎ Service數量;
◎ ResourceQuota數量;
◎ Secret數量;
◎ 可持有的PV數量。
      Kubernetes的配額管理是通過Admission Control(准入控制)來控制的,Admission Control當前提供了兩種方式的配額約束,分別是LimitRanger與ResourceQuota。其中LimitRanger作用於Pod和Container,ResourceQuota則作用於Namespace,限定一個Namespace裏的各類資源的使用總額。

     如果在Pod定義中同時聲明瞭LimitRanger,則用戶通過API Server請求創建或修改資源時,Admission Control會計算當前配額的使用情況,如果不符合配額約束,則創建對象失敗。對於定義了ResourceQuota的Namespace,ResourceQuota Controller組件則負責定期統計和生成該Namespace下的各類對象的資源使用總量,統計結果包括Pod、Service、RC、Secret和Persistent Volume等對象實例個數,以及該Namespace下所有Container實例所使用的資源量(目前包括CPU和內存),然後將這些統計結果寫入etcd的resourceQuotaStatusStorage目錄(resourceQuotas/status)下。寫入resourceQuotaStatusStorage的內容包含Resource名稱、配額值(ResourceQuota對象中spec.hard域下包含的資源的值)、當前使用值(ResourceQuota Controller統計出來的值)。隨後這些統計信息被Admission Control使用,以確保相關Namespace下的資源配額總量不會超過ResourceQuota中的限定值。

Namespace Controller

       用戶通過API Server可以創建新的Namespace並將其保存在etcd中,Namespace Controller定時通過API Server讀取這些Namespace的信息。如果Namespace被API標識爲優雅刪除(通過設置刪除期限實現,即設置DeletionTimestamp屬性),則將該NameSpace的狀態設置成Terminating並保存到etcd中。同時Namespace Controller刪除該Namespace下的ServiceAccount、RC、Pod、Secret、PersistentVolume、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資源。

Service Controller與Endpoints Controller

      本節講解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的負載均衡功能。在後面的章節中會深入講解這部分內容。
     接下來說說Service Controller的作用,它其實是屬於Kubernetes集羣與外部的雲平臺之間的一個接口控制器。Service Controller監聽Service的變化,如果該Service是一個LoadBalancer類型的Service(externalLoadBalancers=true),則Service Controller確保在外部的雲平臺上該Service對應的LoadBalancer實例被相應地創建、刪除及更新路由轉發表(根據Endpoints的條目)。

 

小結:

         今天的內容到此爲止,最近都是原理蛤,大家簡單瞭解一下就可以了。

         謝謝大家的支持,多多點關注哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章