Kubernetes基礎:編排調度的那些Controllers

0. 概述

Kubernetes提供了很多Controller資源來管理、調度Pod,包括Replication Controller、ReplicaSet、Deployments、StatefulSet、DaemonSet等等。本文介紹這些控制器的功能和用法。控制器是Kubernetes中的一種資源,用來方便管理Pod。可以把控制器想象成進程管理器,負責維護進程的狀態。進程掉了負責拉起,需要更多進程了負責增加進程,可以監控進程根據進程消耗資源的情況動態擴縮容。只是在Kubernetes中,控制器管理的是Pods。Controller通過API Server提供的接口實時監控整個集羣的每個資源對象的當前狀態,當發生各種故障導致系統狀態發生變化時,會嘗試將系統狀態修復到“期望狀態”。

1. ReplicationController

Replication Controller 通常縮寫爲 rc、rcs。RC同RS一樣,保持Pod數量始終維持在期望值。RC創建的Pod,遇到失敗後會自動重啓。RC的編排文件必須的字段包括apiVersion、kind、metadata、.spec.repicas、.spec.template。其中.spec.template.spec.restartPolicy 只能是 Always,默認爲空。看一下RC的編排文件。

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: docker.io/nginx
        ports:
        - containerPort: 80

1.1 常用管理操作

  • 刪除RC和相關的Pod,使用kubectl delete命令刪除RC,會同步刪除RC創建的Pods
  • 僅刪除RC,使用kubectl delete --cascade=false僅刪除RC而不刪除相關的Pods
  • 隔離Pod,通過修改標籤的方式隔離Pod

1.2 常用場景

  • Rescheduling,RC控制器會確保集羣中始終存在你設定數量的Pod在運行
  • Scaling,通過修改replicas字段,可以方便的擴容
  • Rolling updates,可以使用命令行工具kubectl rolling-update實現滾動升級
  • Multriple release tracks,配合label和service,可以實現金絲雀發佈
  • 與Services配合

RC沒有探測功能,也沒有自動擴縮容功能。也不會檢查

2. ReplicaSet

RS是RC的下一代,只有對於標籤選擇的支持上有所不同,RS支持集合方式的選擇,RC僅支持相等方式的選擇。ReplicasSet確保集羣在任何時間都運行指定數量的Pod副本,看一下RS的編排文件。

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
  labels:
    app: nginx
    tier: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      tier: frontend
    matchExpressions:
      - {key:tier, operator: In, values: [frontend]}
  template:
    metadata:
      labels:
        app: nginx
        tier: frontend
      spec:
        containers:
        - name: nginx
          image: docker.io/nginx
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
            ports:
            - containerPort: 80

編排文件必須的幾個字段包括:apiVersion、kind、metadata、spec以及spec.replicas、spec.template、spec.selector。

儘管ReplicaSet可以單獨使用,但是如今推薦使用Deployments做爲Pod編排的(新建、刪除、更新)的主要方式。Deploymnets是更高一級的抽象,提供了RS的管理功能,除非你要使用自定義的更新編排或者不希望所有Pod進行更新,否則基本上沒有用到RS的機會。

2.1 常用管理操作

  • 刪除RS和相關Pods,kubectl delete <rs-name>
  • 僅刪除RS,kubectl delete <rs-name> --cascade=false
  • Pod 隔離,通過修改Pod的label,可以將Pod隔離從而進行測試、數據恢復等操作。 - HPA 自動擴容,ReplicaSet可以作爲HPA的目標
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-scaler
spec:
  scaleTargetRef:
    kind: ReplicaSet
    name: nginx
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

3. Deployments

Deployment實際上是對RS和Pod的管理,它總先是創建RS,由RS創建Pods。由Deployment創建的RS的命名規則爲[DEPLOYMENT-NAME]-[POD-TEMPLATE-HASH-VALUE],建議不要手工維護Deployment創建的RS。Deployment的更新僅在Pod的template發生更新的情況下。

下面介紹幾個Deployment使用的典型場景。

3.1 創建部署 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment        //部署名稱
  labels:
    app: nginx
spec:
  replicas: 3                   //副本數量
  selector:                     //Pod選擇規則
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:                   //Pods標籤
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.io/nginx:1.7.9
        ports:
        - contaienrPort: 80
kubectl apply -f dp.yaml
kubectl get deployment nginx-deployment
kubectl rollout status deployment nginx-deployment
kubectl get pods --show-labels

3.2 更新部署 Deployment

如果需要對已經創建的Deployment進行更新有兩種方法,一種是修改編排文件並應用更新,一種是直接通過命令的方式更新部署的參數,分別介紹如下。

命令方式更新 更新鏡像文件的版本

kubectl set image depolyment/nginx-deployment nginx=docker.io/nginx:1.9.1

更新編排文件的方式 首先修改編排文件,然後執行

kubectl apply -f dp.yaml

如果一個Deployment已經創建完成,更新Deployment會創建新的RS並逐漸的替換舊的RS(按一定的速率創建新的Pod,確保新的Pod運行正常後,刪掉舊的Pod)。因此如果查看Pods,可能會發現一段時間Pods的總量會超過replicas設定的數量。如果一個Deployment正在創建還沒有完成,此時更新Deployment會導致剛創建的Pods馬上被殺掉,並開始創建新的Pods。

3.3 回滾更新

有時部署的版本存在問題,我們需要回滾到之前的版本,Deployment也提供了這種功能。默認情況下,Deployment的更新保存在系統中,我們能夠據此實現版本的回滾。

只有更新.spec.template的內容纔會觸發版本記錄,單純的擴容不會記錄歷史。因此回滾也不會造成Pods數量的變化。

kubectl apply -f dp.yaml
kubectl set image deployment/nginx-deployment nginx=docker.io/nginx:1.91
kubectl rollout status deployments nginx-deployment
kubectl get rs
kubectl get pods
# kubectl rollout history deployment/nginx-deployment
kubectl rollout history deployment/nginx-deployment --revision=2
kubectl rollout undo deployment/nginx-deployment
kubectl rollout undown deployment/nginx-deployment --to-revision=2
kubectl get deployment

默認記錄10個版本,可以通過.spec.revisionHistoryLimit修改。

3.4 擴容

# kubectl scale deployment nginx-deployment --replicas=5

如果集羣打開了自動擴容功能,還可以設置自動擴容的條件。

# kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80

3.5 暫停Deployment

創建部署之後,我們可以暫停和重啓部署過程,並在此期間執行一些操作。

$ kubectl rollout pause deployment/nginx-deployment
$
$ kubectl rollout resume deployment/nginx-deployment

3.6 Deployment的狀態

Deployment包含幾種可能的狀態。

  • Progressing
    • 創建了新的ReplicaSet
    • 正在對新的ReplicaSet進行Scaling up
    • 正在對舊的ReplicaSet進行Scaling down
    • 新的Pods準備就緒
  • Complete
    • 所有的副本都已更新爲最新狀態
    • 所有的副本都已可用
    • 沒有舊的副本正在運行
  • Failed
    • Quota不足
    • Readiness探測失敗
    • 鏡像拉取失敗
    • 權限不足
    • 應用運行錯誤

3.7 一些參數

  • Strategy .spec.strategy,這個有兩個選項,分別是Recreate和RollingUpdate,默認爲第二種。第一種的策略爲先殺死舊Pods再創建新Pods,第二種爲一邊創建新Pods,一邊殺掉舊Pods
  • Max Unavailable .spec.strategy.rollingUpdate.maxUnavailable,更新過程中允許不可用Pods的最大比率,默認爲25%
  • Max Surge .spec.strategy.rollingUpdate.maxSurge,更新過程中允許超過replicas的最大Pods數量,默認爲25%
  • Progress Deadline Seconds .spec.progressDeadlineSeconds ,可選參數,設置系統報告進展的時間
  • Min Ready Seconds .spec.minReadySeconds,可選參數,設置新建Pod能正常運行的最小時間間隔
  • Revision History Limit .spec.revisionHistoryLimit 可選參數,設置歷史記錄數量

4. StatefulSets

SteatefulSets我專門有一篇文件介紹,大家可以參考這裏

5. DaemonSet

DaemonSet確保所有的Node上都運行了一份Pod的副本,只要Node加入到集羣中,Pod就會在Node上創建。典型的應用場景包括:運行一個存儲集羣(glusterd,ceph)、運行一個日誌收集集羣(fluentd,logstash)、運行監控程序(Prometheus Node Exporter,collectd,Datadog等)。默認情況下DaemonSet由DaemonSet控制器調度,如果設置了nodeAffinity參數,則會有默認的scheduler調度。

典型的編排文件如下。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-es
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-es
    template:
      metadata:
        labels:
          name: fluentd-es
      spec:
        tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
        containers:
        - name: fluentd-es
          image: docker.io/fluentd:1.20
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 200Mi
          volumeMounts:
          - name: varlog
            mountPath: /var/log
          - name: varlibdockercontainers
            mountPath: /var/lib/docker/containers
            readOnly: true
          terminationGracePeriodSeconds: 30
          volumes:
          - name: varlog
            hostPath:
              path: /var/log
          - name: varlibdockercontainers
            hostPath:
              path: /var/lib/docker/contaienrs

6. Grabage Collection

Kubernetes中一些對象間有從屬關係,例如一個RS會擁有一組Pod。Kubernetes中的GC用來刪除那些曾經有過屬主,但是後來沒有屬主的對象。Kubernetes中擁有屬主的對象有一個metadata.ownerReferences屬性指向屬主。在Kubernetes的1.8版本之後,系統會自動爲ReplicationController、ReplicaSet、StatefulSet、DaemonSet、Deployment、Job和CronJob創建的對象設置ownerReference。

之前各種控制器中我們提到過級聯刪除,就是通過這個屬性來實現的。級聯刪除有兩種形式 Foreground 以及 Background ,Foreground模式中,選擇級聯刪除後GC會自動將所有ownerReference.blockOwnerDeletion=true的對象刪除,最後再刪除owner對象。Background模式中,owner對象會被立即刪除,然後GC在後臺刪除其他依賴對象。如果我們在刪除RS的時候,選擇不進行級聯刪除,那麼這個RS創建的Pods就變成了沒有屬主的孤兒。

7. Jobs

Job通過創建一個或多個Pod來運行特定的任務,當正常完成任務的Pod數量達到設定標準時,Job就會結束。刪除Job會將Job創建的所有Pods刪除。

典型的編排文件

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  backoffLimit: 4
  activeDeadlineSeconds: 100
  template:
    spec:
      containers:
      - name: pi
        image: docker.io/perl
        command: ["perl", "-Mbignum=bpi", "-wle", "print bpid(2000)"]
      restartPolicy: Never

主要有三種類型的Job

  • 非並行的Job,通常只啓動一個Pod執行任務
  • 帶有固定完成數量的並行Job,需要將.spec.completions設置爲非零值
  • 與隊列結合的並行Job,不需要設置.spec.completions,設置.spec.parallelism

Note that even if you specify .spec.parallelism = 1 and .spec.completions = 1 and .spec.template.spec.restartPolicy = "Never", the same program may sometimes be started twice. 感覺有坑啊。

Kubernetes提供的並行Job並不適合科學計算或者執行相關的任務,更適合執行郵件發送、渲染、文件轉義等等單獨的任務。

8. CronJob

Cron Job是根據時間來自動創建Job對象。類似於Crontab,週期性的執行一個任務。每次執行期間,會創建一個Job對象。也可能會創建兩個或者不創建Job,這個情況可能會發生,因此應該保證Job是冪等的。

For every CronJob, the CronJob controller checks how many schedules it missed in the duration from its last scheduled time until now. If there are more than 100 missed schedules, then it does not start the job and logs the error 如果錯過太多,就不要追了

典型的編排文件

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: docker.io/busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

所有的編排文件都上傳到了我的Github上,大家可以自行下載

參考資料

  1. Kubernetes ReplicaSet
  2. Running Automated Tasks with a CronJob
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章