1. 程式人生 > >Kubernetes工作負載之控制器(2):Replication Controller

Kubernetes工作負載之控制器(2):Replication Controller

注意:建議使用Deployment配置ReplicaSet的方法控制pod副本數。

1. 什麼是Replication Controller ?

Replication Controller保證了在所有時間內,都有特定數量的Pod副本在執行:如果太多了,Replication Controller就殺死幾個;如果太少了,Replication Controller會新建幾個。與直接建立pod不同的是,Replication Controller會替換掉那些刪除的或者被終止的pod,不管刪除的原因是什麼(維護阿,更新啊,Replication Controller都不關心)。

基於這個理由,我們建議:即使只建立一個pod,我們也要使用Replication Controller。Replication Controller就像一個程序管理器,監管著不同node上的多個pod,而不是單單監控一個node上的pod,Replication Controller會委派本地容器來啟動一些節點上服務(如kubelet,docker)。

  • Replication Controller只對含有RestartPolicy = Always的Pod的生效

正如我們在pod的生命週期中討論的,Replication Controller只會對RestartPolicy = Always的Pod的生效(RestartPolicy的預設值就是Always),Replication Controller 不會管理有不同啟動策略的pod。

如我們在issue #503討論的,我們希望在將來別的控制器被加入到Kubernete中來管理一些例如負載阿,測試等相關功能

Replication Controller永遠不會自己關閉,但是我們並不希望Replication Controller成為一個長久存在的服務。服務可能會由多個Pod組成,這些Pod又被多個Replication Controller控制著,我們希望Replication Controller會在服務的生命週期中被刪除和新建(例如在這些pod中釋出一個更新)。對於服務和使用者來說,Replication Controller是通過一種無形的方式來維持著服務的狀態。

2. ReplicationController工作原理

2.1 template

一個Replication Controller通過模版來建立pod,這個是Replication Controller內建的功能,但是我們計劃要把這個功能從Replication Controller中剝離出來。

Pod模版是一個Pod副本的期望狀態,它更像是一個製作餅乾的模具:一旦從這個模具中出來之後,餅乾就和餅乾模具沒有任何關聯。Pod模版的改變和更改對已經存在的pod沒有任何影響:在建立pod之後,我們可以直接修改Replication Controller的yaml檔案。這對Pod來說非常重要:這樣就定製了Pod中所有容器的期望狀態。這從根本上簡化系統複雜度,增加了靈活性,正如使用例項。

無狀態服務

儘管Pod的rc配置檔案可能會隨著時間變化而不一樣,但Replication Controller建立的Pod可以相互替代和保持語義上相同,這非常適合無狀態服務。

動態分配機制(高可用,共享,work-pool類應用程式)
Replication Controller也可以被用在保持主從的高可用,共享,work-pool類應用程式,這樣的程式應該使用的是動態分配機制,例如etcd的lock module和RabbitMQ佇列。相對於靜態或一次性定製的Pod配置檔案,任何定製化的Pod(例如垂直的自動伸縮資源(cpu,記憶體)),應該被其它的線上Controller管理,而不是Replication Controller。

2.2 labels

由Replication Controller監控的Pod數量是由label selector(標籤選擇器)決定的。在Replication Controller和被控制的Pod之間,label selector建立了一個鬆耦合的關係(Pod與其定義檔案的關係密切)。我們不使用固定長度的陣列來儲存被管理的Pod,因為根據我們的經驗,不論是系統還是客戶,這樣都會增加管理的複雜度。

replication controller需要確認從特定模版創建出來的pod擁有label selector所要求的標籤,儘管,它還沒有這麼作,我們需要通過確認replication controllers的label selectors 沒有覆蓋設定來確定僅有一個Replication Controller控制所指定的Pod(這段話有點怪)

記住這個:replication controller自己也可以由標籤,would generally carry the labels their corresponding pods have in common,但是這些標籤並不影響replication controller的行為

Pod會被replication controller刪除,如果修改那些pod的標籤,這個功能可能會被應用在從服務中刪除pod來作測試,資料恢復等。Pod如果是以這種方式被刪除的話,那麼那個pod會被自動的替換(前提是宗的副本數量未修改)

類似的,刪除一個replication controller不會影響它建立的pod,如果向刪除那些它那些控制的pod,需要首先拔replcas的值設定為0(注意,使用者端工具kubectl 提供了一個命令stop,來刪除replication controller以及它控制的pod,但是,這個功能在現在的api中不存在)

3. replication controller的職責

replication controller的任務就是保證預計數量的pod並保證其可用性。目前,只有那些被終止的Pod是從總數量中排除的,在將來,可讀性以及其它系統資訊可能會被納入統計,我們可能會增加更多的替代策略,並且我們計劃可以執行其它外部程式可以使使用並實現複雜的替換或者策略。

replication controller的任務永遠都只會是單一的。它自身不會進行是否可讀和是否可用的檢測,相比與自動進行縮放和放大,replication controller更傾向與使用外部的自動平衡工具,這些外部工具要作的僅僅是修改replicas的值來實現Pod數量的變化,我們不會增加replication controller的排程策率,也不會讓replication controller來驗證受控的Pod是否符合特定的模版,因為這些都會阻礙自動調整和其它的自動的程序。類似的,完成時限,需求依賴,配置擴充套件,等等都屬於其它的部分。

replication controller的目的是成為一個原始的積木,我們希望在replication controller上層的api或者工具來為使用者提供方便,現在kubectl支援的巨集觀操作,比如run,stop,scale,rolling-update就是這個概念的例子。舉例來說,我們可以想象和“天庭”管理著replication controller,auto-scalers, services, scheduling policies, canaries等等。

4. RC常見的使用方式

4.1 Rescheduling(重新規劃)

無論你有1個還是1000個Pod需要執行,Replication Controller會確保指定數量的Pod存在,即使發生節點故障或Pod終止(由於其他控制代理的操作)也是如此。

4.2 Scaling(伸縮)

Replication Controller讓我們更容易地控制Pod副本數量,不管是手動修改yaml檔案還是通過其它的自動管理的工具,都需要修改replicas值

無論手動修改還是用自動伸縮控制代理,通過更新欄位replicas的值,ReplicationController可以輕鬆地增加或減少Pod副本數量。

4.3 Rolling updates(滾動更新)

Replication Controller支援動態更新。當我們更新一個service時,RC允許我們一個個的替換Pod:推薦的方法是建立一個新的只有1個Pod副本(replicas值為1)的Replication Controller,然後新的RC每次加1,舊的RC每次減1,直到舊RC的replicas值變成0,然後我們刪除舊的RC。這樣就可以規避升級過程中出現的未知錯誤。

理論上,動態更新控制器要考慮應用服務的可用性,確保足夠數量的Pod提供服務,並在任何時間都能正常訪問服務。

兩個Replication Controller建立的Pod至少要有一個不同的標籤(映象的tag,因為一般映象的更新都會帶來一個新的映象tag)。我們需要通過# kubectl rolling-update來實現動態更新。

4.4 Multiple release tracks(多版本釋出追蹤)

在程式更新過程中,我們可以通過多版本的追蹤,讓多個版本額外執行一段時間,也可以在一段時間內持續地執行多個版本(新舊共存)(版本追蹤是通過label實現)

例如:一個服務可能繫結的Pod是tier in (frontend), environment in (prod)。現在假設由10個Pod副本組成這個tier,現在我們要釋出一個新的映象版本canary(金絲雀)。這時,我們應該建立一個Replication Controller,並且設定replcas值為9,標籤為tier=frontend, environment=prod, track=stable;再另外設定一個Replication Controller,設定replacas值為1,標籤為tier=frontend, environment=prod, track=canary。

現在,該服務就可以同時使用canary(金絲雀)和非金絲雀版本的Pod了,這時我們可以通過不同的Replication Controller進行一些測試,監控。

4.5 Using ReplicationControllers with Services(使用ReplicationControllers與關聯的Services)

5. RC的替代方法

5.1 ReplicaSet

ReplicaSet是支援基於集合的label selector的下一代ReplicationController 。它主要用於Deployment協調pod建立、刪除和更新。請注意,除非需要自定義更新編排或根本不需要更新,否則建議使用Deployment而不是直接使用ReplicaSet。

5.2 Deployment(推薦)

Deployment是一個高階的API物件,以類似的方式# kubectl rolling-update,更新其底層的ReplicaSets和RS的Pods。如果你希望使用滾動更新功能,建議使用Deployment進行部署。因為使用# kubectl rolling-update部署Deployment,是宣告式的,伺服器端的,並具有其他功能。

5.3 Bare Pods(使用者直接建立的Pod,不使用控制器)

與使用者直接建立Pod的情況不同,ReplicationController會替換由於任何原因而被刪除或終止的Pod,例如在節點故障或節點破壞(例如核心升級)的情況下。 出於這個原因,即使您的應用程式只需要一個Pod,我們也建議您使用ReplicationController。 與流程管理器類似,ReplicationController可以監控多個節點上的多個Pod,而不是單個節點上的單個程序。ReplicationController會將本地容器重新啟動,再委託給節點上的某個代理(如kubelet或docker)。

5.4 Job

對於預期會自行終止的Pod(即批處理作業),使用Job而不是ReplicationController。

5.5 DaemonSet

對於提供主機級別功能(如主機監控或主機日誌記錄)的Pod,請使用DaemonSet而不是ReplicationController進行管理。使用DaemonSet管理的Pod壽命與主機生命週期相關:DaemonSet管理的Pod需要在其他Pod啟動之前在主機上執行,並且在主機準備好重啟/關機時,可以安全終止。

6. 使用例項

此ReplicationController配置執行三個副本的nginx伺服器。

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx       # 如果映象不指定tag,預設是latest
        ports:
        - containerPort: 10001

然後我們執行以下命令,k8s會自動下載所需映象:

# kubectl create -f replication.yaml

檢查ReplicationController的狀態

# kubectl describe replicationcontroller/nginx

一段時間過後,k8s建立了三個pod,並顯示:3 Running / 0 Waiting / 0 Succeeded / 0 Failed

以機器可讀的形式,列出屬於ReplicationController的所有Pod

//定義環境變數pods,其值封裝了關於pod的查詢命令
# pods=$(kubectl get pods --selector=app=nginx --output=jsonpath={.items..metadata.name})                 

# echo $pods            // 輸出nginx-cjf74 nginx-ck2cv nginx-vml6q

在這裡,上述的selector與ReplicationController的selector相同(在kubectl describe replicationcontrollers/nginx的輸出中可以看到;也可在replication.yaml中看到)。--output = jsonpath選項指定一個表示式,它以返回列表的形式,從每個pod中獲取名稱。