無狀態工作負載(Deployment)

什麼是Deployment

在Pod:Kubernetes中的最小調度對象這個章節介紹了Pod,Pod是Kubernetes創建或部署的最小單位,但是Pod是被設計爲相對短暫的一次性實體,Pod可以被驅逐(當節點資源不足時)、隨着集羣的節點崩潰而消失。Kubernetes提供了Controller(控制器)來管理Pod,Controller可以創建和管理多個Pod,提供副本管理、滾動升級和自愈能力,其中最爲常用的就是Deployment。

圖1 Deployment
無狀態工作負載(Deployment)
一個Deployment可以包含一個或多個Pod副本,每個Pod副本的角色相同,所以系統會自動爲Deployment的多個Pod副本分發請求。

Deployment集成了上線部署、滾動升級、創建副本、恢復上線的功能,在某種程度上,Deployment實現無人值守的上線,大大降低了上線過程的複雜性和操作風險。

創建Deployment

以下示例爲創建一個名爲nginx的Deployment負載,使用nginx:latest鏡像創建兩個Pod,每個Pod佔用100m core CPU、200M內存。

apiVersion: apps/v1      # 注意這裏與Pod的區別,Deployment是apps/v1而不是v1
kind: Deployment         # 資源類型爲Deployment
metadata:
  name: nginx            # Deployment的名稱
spec:
  replicas: 2            # Pod的數量,Deployment會確保一直有2個Pod運行         
  selector:              # Label Selector
    matchLabels:
      app: nginx
  template:              # Pod的定義,用於創建Pod,也稱爲Pod template
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: container-0
        resources:
          limits:
            cpu: 100m
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
      imagePullSecrets:
      - name: default-secret

從這個定義中可以看到Deployment的名稱爲nginx,spec.replicas定義了Pod的數量,即這個Deployment控制2個Pod;spec.selector是Label Selector(標籤選擇器),表示這個Deployment會選擇Label爲app=nginx的Pod;spec.template是Pod的定義,內容與Pod中的定義完全一致。

將上面Deployment的定義保存到deployment.yaml文件中,使用kubectl創建這個Deployment。

使用kubectl get查看Deployment和Pod,可以看到READY值爲2/2,前一個2表示當前有2個Pod運行,後一個2表示期望有2個Pod,AVAILABLE爲2表示有2個Pod是可用的。

$ kubectl create -f deployment.yaml
deployment.apps/nginx created

$ kubectl get deploy
NAME           READY     UP-TO-DATE   AVAILABLE   AGE
nginx          2/2       2            2           4m5s

Deployment如何控制Pod

繼續查詢Pod,如下所示。

$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-7f98958cdf-tdmqk   1/1       Running   0          13s
nginx-7f98958cdf-txckx   1/1       Running   0          13s

如果刪掉一個Pod,您會發現立馬會有一個新的Pod被創建出來,如下所示,這就是前面所說的Deployment會確保有2個Pod在運行,如果刪掉一個,Deployment會重新創建一個,如果某個Pod故障或有其他問題,Deployment會自動拉起這個Pod。

$ kubectl delete pod nginx-7f98958cdf-txckx

$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-7f98958cdf-tdmqk   1/1       Running   0          21s
nginx-7f98958cdf-tesqr   1/1       Running   0          21s

看到有如下兩個名爲nginx-7f98958cdf-tdmqk和nginx-7f98958cdf-tesqr的Pod, 其中nginx是直接使用Deployment的名稱,-7f98958cdf-tdmqk和-7f98958cdf-tesqr是kubernetes隨機生成的後綴。

您也許會發現這兩個後綴中前面一部分是相同的,都是7f98958cdf,這是因爲Deployment不是直接控制Pod的,Deployment是通過一種名爲ReplicaSet的控制器控制Pod,通過如下命令可以查詢ReplicaSet,其中rs是ReplicaSet的縮寫。

$ kubectl get rs
NAME               DESIRED   CURRENT   READY     AGE
nginx-7f98958cdf   2         2         2         1m

這個ReplicaSet的名稱爲nginx-7f98958cdf,後綴-7f98958cdf也是隨機生成的。

Deployment控制Pod的方式如圖2所示,Deployment控制ReplicaSet,ReplicaSet控制Pod。

圖2 Deployment通過ReplicaSet控制Pod

無狀態工作負載(Deployment)

如果使用kubectl describe命令查看Deployment的詳情,您就可以看到ReplicaSet,如下所示,可以看到有一行NewReplicaSet: nginx-7f98958cdf (2/2 replicas created),而且Events裏面事件確是把ReplicaSet的實例擴容到2個。在實際使用中您也許不會直接操作ReplicaSet,但瞭解Deployment通過控制ReplicaSet來控制Pod會有助於您定位問題。

**$ kubectl describe deploy nginx**
Name:                   nginx
Namespace:              default
CreationTimestamp:      Sun, 16 Dec 2018 19:21:58 +0800
Labels:                 app=nginx

...

**NewReplicaSet:   nginx-7f98958cdf (2/2 replicas created)**
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  5m    deployment-controller  Scaled up replica set nginx-7f98958cdf to 2

升級

在實際應用中,升級是一個常見的場景,Deployment能夠很方便的支撐應用升級。

Deployment可以設置不同的升級策略,有如下兩種。

  • RollingUpdate:滾動升級,即逐步創建新Pod再刪除舊Pod,爲默認策略。
  • Recreate:替換升級,即先把當前Pod刪掉再重新創建Pod。
    Deployment的升級可以是聲明式的,也就是說只需要修改Deployment的YAML定義即可,比如使用kubectl edit命令將上面Deployment中的鏡像修改爲nginx:alpine。修改完成後再查詢ReplicaSet和Pod,發現創建了一個新的ReplicaSet,Pod也重新創建了。
$ kubectl edit deploy nginx

$ kubectl get rs
NAME               DESIRED   CURRENT   READY     AGE
nginx-6f9f58dffd   2         2         2         1m
nginx-7f98958cdf   0         0         0         48m

$ kubectl get pods
NAME                     READY     STATUS    RESTARTS   AGE
nginx-6f9f58dffd-tdmqk   1/1       Running   0          21s
nginx-6f9f58dffd-tesqr   1/1       Running   0          21s

Deployment可以通過maxSurge和maxUnavailable兩個參數控制升級過程中同時重新創建Pod的比例,這在很多時候是非常有用,配置如下所示。

spec:
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
  • maxSurge:與Deployment中spec.replicas相比,可以有多少個Pod存在,默認值是25%,比如spec.replicas爲 4,那升級過程中就不能超過5個Pod存在,即按1個的步伐升級,實際升級過程中會換算成數字,且換算會向上取整。這個值也可以直接設置成數字。
  • maxUnavailable:與Deployment中spec.replicas相比,可以有多少個Pod失效,也就是刪除的比例,默認值是25%,比如spec.replicas爲4,那升級過程中就至少有3個Pod存在,即刪除Pod的步伐是1。同樣這個值也可以設置成數字。
    在前面的例子中,由於spec.replicas是2,如果maxSurge和maxUnavailable都爲默認值25%,那實際升級過程中,maxSurge允許最多3個Pod存在(向上取整,21.25=2.5,取整爲3),而maxUnavailable則不允許有Pod Unavailable(向上取整,20.75=1.5,取整爲2),也就是說在升級過程中,一直會有2個Pod處於運行狀態,每次新建一個Pod,等這個Pod創建成功後再刪掉一箇舊Pod,直至Pod全部爲新Pod。

回滾

回滾也稱爲回退,即當發現升級出現問題時,讓應用回到老的版本。Deployment可以非常方便的回滾到老版本。

例如上面升級的新版鏡像有問題,可以執行kubectl rollout undo命令進行回滾。

$ kubectl rollout undo deployment nginx
deployment.apps/nginx rolled back

Deployment之所以能如此容易的做到回滾,是因爲Deployment是通過ReplicaSet控制Pod的,升級後之前ReplicaSet都一直存在,Deployment回滾做的就是使用之前的ReplicaSet再次把Pod創建出來。Deployment中保存ReplicaSet的數量可以使用revisionHistoryLimit參數限制,默認值爲10。

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