K8S Pod控制器應用進階

一、Pod控制器類別

1.1 ReplicaSet

ReplicaSet控制器用來管理無狀態的Pod資源,核心作用在於代用戶創建指定數量的Pod副本,並確保Pod副本數量一直等於用戶期望的數量。而且還支持Pod滾動更新、及自動擴縮容等機制;它被稱新一代的ReplicationCtroller。

ReplicaSet主要有三個組件組成:

  1. 用戶期望的Pod副本數量;
  2. 標籤選擇器,用來選定由自己管理或控制的Pod副本,如果通過標籤選擇器挑選到的Pod少於定義的Pod副本數量,則會利用Pod資源模版來創建Pod副本,以達到規定的Pod數量;
  3. Pod資源模版。

但是Kubernetes卻不建議用戶直接使用ReplicaSet,而是應該使用Deployment

1.2 Deployment

Deployment也是Pod控制器,但是它是工作在ReplicaSet之上的。Deployment是通過控制ReplicaSet,從而來控制Pod。Deployment能夠提供比ReplicaSet更爲強大的功能。比如:Pod版本回滾、聲明式配置(聲明式配置是已經創建的Pod可以隨時更改配置並應用到Pod)。Deployment是目前管理無狀態應用最好的控制器。

1.3 DaemonSet

DaemonSet用於確保集羣中的每一個節點只運行一個特定的Pod副本,這種特定的Pod通常是用來實現系統級的後臺任務。把這樣的任務託管在Kubernetes之上的好處是:如果這個後臺任務宕了以後,會由DaemonSet控制器自動重建一個Pod;新建一個Node節點,它也會在新節點上創建一個這樣的Pod運行。

約束:我們也可以根據自己的需求,在K8S羣集中的部分滿足條件的節點上僅運行一個Pod副本。

總結: Deployment和DaemonSet管理的Pod中運行的服務都是無狀態的,且是守護進程類的(必須始終持續運行在後臺)。但是對於那種只希望運行一次就結束的任務,顯然以上兩種控制器是不能夠使用的。例如:我們需要對數據庫進行備份,備份結束後,任務就應該結束了,而不是讓任務持續運行在後臺。那麼對於這種任務只運行一次,只要任務完成就正常退出,沒有完成纔會重建,這就應該選擇使用Job這種控制器了。

1.4 Job

Job控制器控制只能執行一次作業的任務,它確保這個任務確實是正常完成而退出的,如果是異常退出,則Job控制器會重建任務再次執行直到任務正常完成。

那麼對於週期性的任務呢?顯然Job控制器也是無法勝任的。這就需要CronJob了。

1.5 CronJob

CronJob與Job類似,也是運行一次就退出。不同之處在於,Job是隻運行一次,CronJob是週期性運行。但每次運行都會有正常退出的時間。如果前一次任務還沒執行完成,又到了下一次任務執行的時間點了怎麼辦呢?CronJob也可以解決這種問題。

1.6 StatufulSet

StatufulSet控制器能夠管理有狀態的Pod副本,而且每一個Pod副本都是被單獨管理的,它擁有自己獨有的標誌和獨有的數據集。一旦這個副本故障了,在重建Pod之前會做許多初始化操作。以Redis羣集爲例:如果Redis集羣中三個節點中的某一個節點宕機了,爲了確保每個節點宕機後數據不丟失,我們傳統的做法就是對每個節點做主從複製,當主節點宕機後,需要人爲的把從節點提升爲主節點,想要恢復從節點,就需要很多運維操作了。

但是利用StatufulSet去定義管理Redis或Mysql或者Zookeeper,它們的配置是不一樣的。例如:配置管理Redis主從複製和配置管理Mysql主從複製中間的操作步驟是不一樣的。所以這樣的配置沒有任何規律可循。StatufulSet給我們提供了一個封裝,用戶把需要人爲操作的複雜的執行邏輯定義成腳本,放置在StatufulSet的Pod模板中。這樣在每次Pod節點故障後,能通過腳本自動恢復過來。

總結:真正想把有狀態的應用託管在Kubernetes之上,還是有相當的難度。

1.7 CDR

Custom Defined Resources K8S 1.8+,用戶自定義資源。

1.8 Helm

任何不把用戶當傻瓜的應用,都難以取得成功。K8S資源清單定義起來,門檻過高,難度大。這就誕生了Helm,Helm對於Kubernetes來說,就相當於Linux系統中的yum。以後在再部署大型的應用,就可以用Helm直接安裝部署。不過Helm到目前爲止,誕生也不超過兩年的時間。到目前爲止,許多大型主流的應用,已經可以通過Helm去部署。

二、ReplicaSet資源清單

ReplicaSet資源清單定義時的一級字段:

apiVersion: apps/v1
kind: ReplicaSet
metadata: 
spec: 

spec下一級核心字段主要的有三個:

replicas    <integer>       # 定義Pod副本數量
selector    <Object>        # 選擇器
template    <Object>        # 模板

 template字段中嵌套的就是Pod資源清單定義的字段:

metadata    <Object>        # 這是定義Pod的元數據
spec        <Object>        # Pod的spec

接下來,我們來定義一個ReplicaSet的資源清單:rs-demo.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp
  namespace: default
spec:
  replicas: 2    #pod副本數量爲2
  selector:
    matchLabels:    #pod模板中的labels必須能被ReplicaSet的標籤選擇匹配到
      app: myapp
      release: canary
  template:
    metadata:
      name: myapp-pod
      labels:      #pod模板中的labels必須能被ReplicaSet的標籤選擇匹配到
        app: myapp
        release: canary   
        environment: qa
    spec:
      containers:
      - name: myapp-container
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80

 利用上述清單創建一個名爲myapp的ReplicaSet:

[root@s1 ~]# kubectl create -f rs-demo.yaml 
replicaset.apps/myapp created
[root@s1 ~]# kubectl get rs
NAME               DESIRED   CURRENT   READY   AGE
myapp              2         2         2       16s
myapp-7c468db58f   2         2         2       23h

ReplicaSet可以簡寫爲rs。

值得注意的是,在Pod模板中定義的Pod名稱(如上代碼:name: myapp-pod)實際上是不起作用的。因爲通過控制器清單文件創建的Pod名稱是由按照 控制器名稱-隨機字符串這樣的形式命名的。如下圖:

獲取創建的Pod:

[root@s1 ~]# kubectl get pods -o wide -l app
NAME          READY   STATUS    RESTARTS   AGE     IP            NODE   NOMINATED NODE   READINESS GATES
myapp-fdb9l   1/1     Running   0          3m35s   10.244.2.15   n2     <none>           <none>
myapp-ngm2v   1/1     Running   0          3m35s   10.244.1.16   n1     <none>           <none>

三、Deployment資源清單

Deployment管理保留的ReplicaSet版本數量可以由用戶自定義,默認保留10個歷史版本。Deployment能夠使用聲明式配置,聲明式配置是使用kubectl apply -f demo.yaml命令。對於聲明式配置的資源,將來還可以在命令行使用patch子命令去打補丁實現配置修改更新。

Deployment在控制Pod滾動更新時,還可以配置Pod的滾動更新邏輯。

Deployment、ReplicaSet、Pod三者之間的關係:


更新Pod容器的鏡像後,新版本Pod更新示意圖:

Deployment可以簡寫爲deploy
接下來看看Deployment資源清單一級字段:

apiVersion: apps/v1
kind: Deployment
metadata: 
spec:

Deployment的spec與ReplicaSet的spec區別不大。
Deployment中的spec字段:

replicas    <integer>   # Pod副本數量
selector    <Object>    # 標籤選擇器
template    <Object> -required-     # Pod模板
strategy    <Object>    # 定義Pod更新策略
paused      <boolean>
revisionHistoryLimit    <integer>

 3.1 strategy(Pod更新策略)

spec:
  strategy:
    type:                     # <string>
    rollingUpdate:            # <Object>

strategy.type字段取值:

  • Recreate: 重建更新,就是刪除一個Pod,再重建一個Pod。當typerecreate時,與type同級的rollingUpdate字段就失效了。當typerollingUpdate,與type同級的rollingUpdate字段定義滾動更新的策略。
  • RollingUpdate滾動更新

strategy.rollingUpdate字段:

  • maxSurgePod滾動更新時,最多能超出replicas定義的Pod副本數的個數。有兩種取值方式:1. 直接指定一個數字(ex: 5);2. 指定一個百分比(ex: 10%)。
  • maxUnavailablePod滾動更新時,最多有幾個不可用。假設replicas值爲5,maxUnavailable值爲1,那麼可用的Pod數量至少爲5-1=4個。此字段同樣可以指定一個百分比做爲值。

例如:Pod滾動更新時,多則只能多2個,少則只能少1個,則可以這樣定義:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 1

3.2 revisionHistoryLimit

revisionHistoryLimit <integer>表示要保留以允許回滾的舊ReplicaSet的數量。默認是10個。如果值爲0,表示不保存舊版本。

3.3 paused

paused <boolean> 表示部署Pod時是否暫停,通常情況下是不暫停的,執行命令後會立即部署Pod。

3.4 template

template <Object> -required- Pod模板與ReplicaSet中Pod模板定義一致。

3.5 Deployment資源清單示例

編輯yaml文件:deploy-demo.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary 
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80

這裏我們用聲明式創建: 

[root@s1 ~]# kubectl create -f deploy-demo.yaml 
deployment.apps/myapp-deploy created
[root@s1 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
myapp-deploy-7d574d56c7   2         2         2       92s
[root@s1 ~]# kubectl get pods
NAME                            READY   STATUS        RESTARTS   AGE
myapp-deploy-7d574d56c7-rwrxv   1/1     Running       0          5s
myapp-deploy-7d574d56c7-znnvg   1/1     Running       0          5s
pod-demo                        0/2     Terminating   0          6m

自動創建的ReplicaSet命名規則:deploy名稱-Pod模板hash值

Pod的命令規則:deploy名稱-Pod模板hash值-隨機字符串

 這時我們想要改變Pod副本數量,可以直接vim deploy-demo.yaml修改replicas: 4,然後再執行kubectl apply -f deploy-demo.yaml

注意:聲明式創建,相同的yaml文件可以多次執行kubectl apply。而kubectl create只能執行一次。

上述示例清單中,有很多字段我們都沒有定義。Kubernetes會自動填充默認值。可以通過命令:kubectl get deploy myapp-deploy -o yaml查看。

3.5.1 更新操作

我們先修改deploy-demo.yaml,將容器的鏡像版本修改爲v2:
 

[root@s1 ~]# vim deploy-demo.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v2
        ports:
        - name: http
          containerPort: 80

再次部署:

[root@s1 ~]# kubectl apply -f deploy-demo.yaml 
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps/myapp-deploy configured
[root@s1 ~]# kubectl get pods -l app=myapp -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP            NODE   NOMINATED NODE   READINESS GATES
myapp-deploy-798dc9b584-r9rpm   1/1     Running   0          23s   10.244.2.17   n2     <none>           <none>
myapp-deploy-798dc9b584-vm6w8   1/1     Running   0          24s   10.244.1.19   n1     <none>           <none>

 訪問pod,查看版本號:

[root@s1 ~]# curl 10.244.2.17
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@s1 ~]# curl 10.244.1.19
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>

查看滾動歷史記錄:

[root@s1 ~]# kubectl rollout history deployment myapp-deploy 
deployment.apps/myapp-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>

3.5.2 通過打補丁的方式更新資源清單配置

可以看到Pod副本個數立即更新到5個了

[root@s1 ~]# kubectl patch deployment myapp-deploy -p '{"spec": {"replicas": 5}}'
deployment.apps/myapp-deploy patched
[root@s1 ~]# kubectl get pod -l release=canary
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-798dc9b584-h9tch   1/1     Running   0          32s
myapp-deploy-798dc9b584-hn8bk   1/1     Running   0          32s
myapp-deploy-798dc9b584-r9rpm   1/1     Running   0          5m37s
myapp-deploy-798dc9b584-vm6w8   1/1     Running   0          5m38s
myapp-deploy-798dc9b584-z4tzh   1/1     Running   0          32s

通過打補丁的方式修改滾動更新策略:

[root@s1 ~]# kubectl patch deployment myapp-deploy -p '{"spec": {"strategy": {"type": "RollingUpdate", "rollingUpdate": {"maxSurge": 1, "maxUnavailable": 0}}}}'
deployment.apps/myapp-deploy patched

查看一下滾動更新策略,已經應用修改:

3.5.3 暫停Pod更新

爲了做這個示例,我們可以先修改鏡像版本,然後立即暫停滾動更新。
修改鏡像版本除了使用vim命令直接編輯yaml文件或使用kubectl patch打補丁外,還可以使用kubectl set image直接修改鏡像。示例:kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
命令如下:

[root@s1 ~]#  kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment myapp-deploy 
deployment.apps/myapp-deploy image updated
deployment.apps/myapp-deploy paused

另開啓一個終端,監控label爲app=myapp的Pod:

[root@s1 ~]# kubectl get pods -l app=myapp -w
NAME                            READY   STATUS    RESTARTS   AGE
myapp-deploy-798dc9b584-h9tch   1/1     Running   0          16m
myapp-deploy-798dc9b584-hn8bk   1/1     Running   0          16m
myapp-deploy-798dc9b584-r9rpm   1/1     Running   0          21m
myapp-deploy-798dc9b584-vm6w8   1/1     Running   0          21m
myapp-deploy-798dc9b584-z4tzh   1/1     Running   0          16m


myapp-deploy-5dc9c974d7-kk5vg   0/1     Pending   0          0s
myapp-deploy-5dc9c974d7-kk5vg   0/1     Pending   0          0s
myapp-deploy-5dc9c974d7-kk5vg   0/1     ContainerCreating   0          0s
myapp-deploy-5dc9c974d7-kk5vg   1/1     Running             0          2s

通過上圖可以看到,滾動更新暫停命令執行後,會先創建一個新Pod並運行,然後就暫停住了,舊Pod也沒有刪除一個。此時有6個Pod,如下圖:

其中一個使用是新版本v3的image,其餘的是v2:

[root@s1 ~]# kubectl get deployment myapp-deploy -o wide
NAME           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                 SELECTOR
myapp-deploy   6/5     1            6           30m   myapp        ikubernetes/myapp:v3   app=myapp,release=canary

通過命令:kubectl rollout status deployment myapp-deploy可以看到滾動更新的狀態,如下圖:

[root@s1 ~]# kubectl rollout status deployment myapp-deploy
Waiting for deployment "myapp-deploy" rollout to finish: 1 out of 5 new replicas have been updated...

圖中提示信息告訴我們:等待部署“myapp-deploy”部署完成:5個新副本中的1個已更新...

接下來我們恢復Pod更新...

3.5.4 恢復Pod更新

恢復Pod更新使用命令:

[root@s1 ~]# kubectl rollout resume deployment myapp-deploy 
deployment.apps/myapp-deploy resumed
[root@s1 ~]# kubectl rollout status deployment myapp-deploy 
deployment "myapp-deploy" successfully rolled out

從圖中可以看出,滾動更新完成。

看一下ReplicaSet的狀態:

從上圖中可以看到鏡像已經更新到v3版了,而且有5個Pod已經準備就緒了。

接下來執行回滾操作。。。

3.5.5 回滾操作

假如新版本的應用Pod有問題,想要回滾,就要使用命令:kubectl rollout undo,默認回滾前一個版本。

[root@s1 ~]# kubectl rollout undo deployment myapp-deploy --to-revision=1
deployment.apps/myapp-deploy rolled back

--to-revision=1 表示回滾到第1版,如果不指定--to-revision選項,則默認是回滾到前一個版本。可以通過命令kubectl rollout history deployment myapp-deploy查看。

[root@s1 ~]# kubectl rollout history deployment myapp-deploy
deployment.apps/myapp-deploy 
REVISION  CHANGE-CAUSE
4         <none>
5         <none>
6         <none>

 再來 看看ReplicaSet狀態:

從上圖中可以看到,已經回滾到v1版了,v1版有5個Pod準備就緒了。而v3版的Pod數爲0 。

四、DaemonSet資源清單

DaemonSet控制器能夠在指定節點上運行能夠實現系統級的管理功能的Pod,而且每個指定節點只運行一個這樣的Pod副本。還可以把節點的目錄掛載至Pod中,通過Pod實現某些管理功能。

DaemonSet定義資源清單時,不再需要用replicas字段指定副本數量了。

DaemonSet資源清單文件中spec字段包含的子字段:

revisionHistoryLimit    <integer>   # rs歷史版本保存個數,與Deployment中的此字段意義相同。
selector    <Object>    # 標籤選擇器
template    <Object> -required-     # Pod模板
updateStrategy  <Object>            # Pod更新策略

DaemonSet的Pod更新策略有兩種:"RollingUpdate""OnDelete",只有類型爲RollingUpdate時,與type同級的字段rollingUpdate才生效。rollingUpdate字段下只有maxUnavailable一個字段。也就是說DaemonSet的Pod更新時,只能少,不能多。

DaemonSet資源清單示例:

apiVersion: apps/v1
kind: DaemonSet
metadata: 
  name: filebeat-ds
  namespace: default
spec: 
  selector:
    matchLabels:
      app: filebeat
      release: stable
  template:
    metadata: 
      labels:
        app: filebeat
        release: stable
    spec: 
      containers:
      - name: filebeat
        image: ikubernetes/filebeat:5.6.5-alpine
        env: 
        - name: REDIS_HOST
          value: redis-svc
        - name: REDIS_LOG_LEVEL
          value: info

 

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