作者:shengdong
當我們嘗試去了解K8S叢集工作原理的時候,控制器肯定是一個難點。這是因為控制器有很多,具體實作大相徑庭;且控制器的實作用到了一些較為晦澀的機制,不易了解。但是,我們又不能繞過控制器,因為它是叢集的“大腦”。今天這篇文章,我們通過分析一個簡易冰箱的設計過程,來深入了解叢集控制器的産生,功能以及實作方法。
大圖
下圖是K8S叢集的核心元件,包括資料庫etcd,排程器scheduler,叢集入口API Server,控制器Controller,服務代理kube-proxy以及直接管理具體業務容器的kubelet。這些元件邏輯上可以被分為三個部分:核心元件etc資料庫,對etcd進行直接操作的入口元件API Server,以及其他元件。這裡的“其他元件”之是以可以被劃分為一類,是因為它們都可以被看做是叢集的控制器。

今天我們要講的就是叢集控制器原理。
控制器原理
雖然控制器是K8S叢集中比較複雜的元件,但控制器本身對我們來說并不陌生的。我們每天使用的洗衣機、冰箱、空調等,都是依靠控制器才能正常工作。在控制器原理這一節,我們通過思考一個簡易冰箱的設計過程,來了解K8S叢集控制器的原理。
簡易的冰箱
這個冰箱包括五個元件:箱體、制冷系統、照明系統、溫控器以及門。冰箱隻有兩個功能:當有人打開冰箱門的時候,冰箱内的燈會自動開啟;當有人按下溫控器的時候,制冷系統會根據溫度設定,調節冰箱内溫度。
統一入口
對于上邊的冰箱,我們可以簡單抽象成兩個部分:統一的操作入口和冰箱的所有元件。在這裡,使用者隻有通過入口,才能操作冰箱。這個入口提供給使用者兩個接口:開關門和調節溫控器。使用者執行這兩個接口的時候,入口會分别調整冰箱門和溫控器的狀态。
控制器
控制器就是為了解決上邊的問題産生的。控制器就是使用者的操作,和冰箱各個元件的正确狀态之間的一座橋梁:當使用者打開門的時候,控制器觀察到了門的變化,它替使用者打開冰箱内的燈;當使用者按下溫控器的時候,控制器觀察到了使用者設定的溫度,它替使用者管理制冷系統,調節冰箱内溫度。
控制器管理器
冰箱有照明系統和制冷系統,顯然相比一個控制器管理着兩個元件,我們替每個元件分别實作一個控制器是更為合理的選擇。同時我們實作一個控制器管理器來統一維護所有這些控制器,來保證這些控制器在正常工作。
SharedInformer
上邊的控制器和控制器管理器,看起來已經相當不錯了。但是當冰箱功能增加,勢必有很多新的控制器加進來。這些控制器都需要通過冰箱入口,時刻監控自己關心的元件的狀态變化。比如照明系統控制器就需要時刻監控冰箱門的狀态。當大量控制器不斷的和入口通信的時候,就會增加入口的壓力。
這個時候,我們把監控冰箱元件狀态變化這件事情,交給一個新的子產品SharedInformer來實作。SharedInformer作為控制器的代理,替控制器監控冰箱元件的狀态變化,并根據控制器的喜好,把不同元件狀态的變化,通知給對應的控制器。通過優化,這樣的SharedInformer可以極大的緩解冰箱入口的壓力。
ListWatcher
假設SharedInformer和冰箱入口通過http協定通信的話,那麼http分塊編碼(chunked transfer encoding)就是實作ListWatcher的一個好的選擇。控制器通過ListWatcher給冰箱入口發送一個查詢然後等待,當冰箱元件有變化的時候,入口通過分塊的http響應通知控制器。控制器看到chunked響應,會認為響應資料還沒有發送完成,是以會持續等待。
舉例
以上我們從一個簡易冰箱的進化過程中,了解了控制器産生的意義,扮演的角色,以及實作的方式。現在我們回到K8S叢集。K8S叢集實作了大量的控制器,而且在可以預見的未來,新的功能的控制器會不斷出現,而一些舊的控制器也會被逐漸淘汰。
目前來說,我們比較常用的控制器,如pod控制器、deployment控制器、service控制器、replicaset控制器等。這些控制器一部分是由kube controller manager這個管理器實作和管理,而像route控制器和service控制器,則由cloud controller manager實作。
之是以會出現cloud controller manager,是因為在不同的雲環境中,一部分控制器的實作,會因為雲廠商、雲環境的不同,出現很大的差别。這類控制器被劃分出來,由雲廠商各自基于cloud controller manager分别實作。
這裡我們以阿裡雲K8S叢集cloud controller manager實作的route控制器和service控制器為例,簡單說明K8S控制器的工作原理。
服務控制器
首先,使用者請求API Server建立一個LoadBalancer類型的服務,API Server收到請求并把這個服務的詳細資訊寫入etcd資料庫。而這個變化,被服務控制器觀察到了。服務控制器了解LoadBalancer類型的服務,除了包括存放在etcd内部的服務記錄之外,還需要一個SLB作為服務入口,以及若幹endpoints作為服務後端。是以服務控制器分别請求SLB的雲openapi和API Server,來建立雲上SLB資源,和叢集内endpoints資源。
路由控制器
在叢集網絡一章中,我們提到過,當一個節點加入一個K8S叢集的時候,叢集需要在VPC路由表裡增加一條路由,來搭建這個新加入節點到pod網絡的主幹道。而這件事情,就是路由控制器來做的。路由控制器完成這件事情的流程,與上邊服務控制器的處理流程非常類似,這裡不再贅述。
結束語
基本上來說,K8S叢集的控制器,其實扮演着叢集大腦的角色。有了控制器,K8S叢集才有機會擺脫機械和被動,變成一個自動、智能、有大用的系統。