3.3 控制器——Deployments(部署)

3.3 Deployments(部署)

 Deployments控制器(Deployment controller,Deployment應該也是控制器的一種吧)提供了Pod和ReplicaSets的聲明式更新。在Deployment對象中,可以描述對應的desired state,Deployments controller將會已可控的頻率去改變實際狀態變成desired state,可以定義Deployments創建新的ReplicaSets,或者移除已有的Deployments並讓新的Deployment接管已有的Pod。類似的,不推薦直接管理ReplicaSets,而應該通過操縱Deployment對象去管理。

【使用場景】

  1. 創建Deployment,用於推出副本集:副本集子在幕後創建,檢查推出的狀態是否成功;
  2. 聲明Pod的新狀態:更新Deployment的Pod模板規約PodTemplateSpec,一個新的ReplicationSet將會被創建,Deployment管理將Pod以一個可控的速度移到新的副本集中,每個新的副本集都會更新Deployment的修改。
  3. 回滾Deployment的早期版本:如果當前的Deployment的狀態不穩定,每個回滾更新Deployment;
  4. 擴大Deployment以方便更多的負載;
  5. 暫停Deployments以對其podTemplatespec應用多個修復程序,然後恢復Deployments以啓動新的滾動;
  6. 使用Deployment的狀態作爲滾動卡住的標識;
  7. 清理不再需要的老的ReplicaSets;

【創建Deployment】

Deployment需要一個apiVersionkindmetadata字段,當然也需要.spec的東西了,其中.spec.template.spec.selector是必需的,.spec.strategy表示替換舊Pod的策略,.spec.strategy.type可以設置爲Recreate(在新Pod創建之前殺死所有已有的Pod)或RollingUpdate(默認值,可以指定maxUnavailablemaxSurge控制升級進程)。

下面是創建一個Nginx的Deployment的實例,3個Pod副本:

apiVersion: apps/v1
kind: Deployment
metadata:
  # Deployment的名字
  name: nginx-deployment
  labels:
    app: nginx
spec:
  # Pod的副本數,默認爲1,可缺省
  replicas: 3
  # 定義了Deployment發現Pod的標籤選擇器
  selector:
    # 這裏的選擇器必須和下面的template.metadata.labels一樣!否則api不接受該請求
    matchLabels:
      # 選擇那些帶有 app: nginx 標籤的Pod進行管理
      app: nginx
  # Pod的創建模板
  template:
    metadata:
      # Pod的標籤
      labels:
        app: nginx
    spec:
      containers:
      # 指定運行容器的名字爲 nginx
      - name: nginx
        # 指定鏡像版本
        image: nginx:1.7.9
        ports:
        # 指定容器端口
        - containerPort: 80

注:matchLabels也是鍵值對,如果內部只有一對{key: value},就和matchExpressions一樣。

創建上述的Deployment可以使用kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml,查看集羣中的Deployments:

# 獲取默認命名空間中的deployments
kubectl get deployments

# 結果
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
curl       1/1     1            1           16d
jenkins    1/1     1            1           12d
my-nginx   0/0     0            0           16d

返回的結果有如下字段:

  • NAME:即Deployment的名字;
  • READY:是x/x的格式,其實就是舊版的CURRENTDESIRED參數,前者表示當前正在運行副本的數量(即.status.replicas),後者表示期待的副本數量,就是創建Deployment定義的.spec.replicas那個數字;
  • UP-TO-DATE:表示已經更新到desired state的Pod的數量,通過.status.updatedReplicas值獲取;
  • AVAILABLE:表示用戶可得APP副本的數目,通過.status.availableReplicas獲取;
  • AGE:表示應用運行的時間;

上述的值都可以從Deployment的規約中得到,查看Deployment的推出狀態信息,可以通過kubectl rollout status deployment.v1.apps/nginx-deployment,也可以查看由Deployment創建的副本集(ReplicaSet):kubectl get rs,如下的一些形式:

# 查看副本集
kubectl  get rs

# 結果
NAME                  DESIRED   CURRENT   READY   AGE
curl-66959f6557       1         1         1       16d
jenkins-7958858b5d    1         1         1       12d
my-nginx-64fc468bd4   2         2         2       16d

副本集的名字都是[DEPLOYMENT-NAME]-[RANDOM-STRING]的形式,其中[RANDOM-STRING]隨機串是由 pod-template-hash 產生的,使用--show-labels可以獲取每個pod的自動生成的標籤:

kubectl get pods --show-labels

# 結果
NAME                        READY   STATUS    RESTARTS   AGE   LABELS
curl-66959f6557-pn49b       1/1     Running   2          16d   pod-template-hash=66959f6557,run=curl
jenkins-7958858b5d-27qlx    1/1     Running   1          12d   name=jenkins,pod-template-hash=7958858b5d
my-nginx-64fc468bd4-cgd7r   1/1     Running   0          20m   pod-template-hash=64fc468bd4,run=my-nginx
my-nginx-64fc468bd4-ss95t   1/1     Running   0          21m   pod-template-hash=64fc468bd4,run=my-nginx

【更新Deployment】

 修改Deployment的Pod模板(即.spec.template)將會觸發一個Deployment的推出,比如標籤或容器的鏡像更新了,但其他的更新,如Deployment的伸縮將不會觸發一個rollout。比如現在想將之前Nginx的Pod使用的鏡像改變爲nginx:1.9.1,那可以這麼幹:

# 第一個my-nginx爲deployment的名字,第2個my-nginx,第3個my-nginx是容器的名字
kubectl --record deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1

# 輸出
deployment.apps/my-nginx image updated
deployment.apps/my-nginx image updated

查看對應的信息,注意看Age:

# 查看副本集的信息
kubectl get rs
# 結果
NAME                  DESIRED   CURRENT   READY   AGE
curl-66959f6557       1         1         1       16d
jenkins-7958858b5d    1         1         1       12d
my-nginx-5fbd7db759   2         2         2       3m55s
my-nginx-64fc468bd4   0         0         0       16d

# 查看pod
kubectl get pods
# 結果
NAME                        READY   STATUS    RESTARTS   AGE
curl-66959f6557-pn49b       1/1     Running   2          16d
jenkins-7958858b5d-27qlx    1/1     Running   1          12d
my-nginx-5fbd7db759-fxp6m   1/1     Running   0          5m38s
my-nginx-5fbd7db759-rgr22   1/1     Running   0          6m4s

所以下次需要更新Pod的時候只需要更新Deployment中的Pod模板即可。Deployment在升級Pod時可以確保僅有部分數量的Pod可能會被停止,默認情況確保至少比所需的Pod數量少25%(最多25%不可用)。

 Rollover(又叫multiple updates in-flight),每次一個新的Deployment對象都會被Deployment controller監測到,如果沒有副本集ReplicationSet接管這些Pod就會創建一個新的副本集。現存的副本集控制的Pod的標籤應該和.spec.selector一致,但那些模板不和.spec.selector匹配的副本集應該按比例縮減,最終的結果應該是:新副本集ReplicationSet將會伸展成.spec.replicas數量,舊的副本集ReplicationSet應該縮減爲0。如果在更新Deployment過程中還存在rollout,Deployment將會創建新的ReplicationSet,並開始向上擴展該副本集,同時將回滾以前正在擴展的副本集–將其添加到舊副本集列表中,並開始向下擴展(其實就是擴大新副本集的規模、縮減舊副本集的規模)。

 選擇器更新,一般是不推薦去更新選擇器的,如果非要這麼幹,請謹慎!

【回滾Deployment】

有時如果Deployment不穩定需要回滾到之前的版本,比如下面的更新了一個Nginx的Deployment,先看一下它的信息:

# 查看
kubectl describe deployment/my-nginx

# 結果
Name:                   my-nginx
Namespace:              default
CreationTimestamp:      Mon, 08 Apr 2019 17:28:01 +0800
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 4
                        kubectl.kubernetes.io/last-applied-configuration:
                          {"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"my-nginx","namespace":"default"},"spec":{"replicas":2,"se...
                        kubernetes.io/change-cause: kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.7.9 --record=true
Selector:               run=my-nginx
Replicas:               2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  run=my-nginx
  Containers:
   my-nginx:
    Image:        nginx:1.7.9
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   my-nginx-55bbf58cd5 (2/2 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  118s  deployment-controller  Scaled up replica set my-nginx-765c8d656d to 1
  Normal  ScalingReplicaSet  107s  deployment-controller  Scaled down replica set my-nginx-765c8d656d to 0
  Normal  ScalingReplicaSet  107s  deployment-controller  Scaled up replica set my-nginx-55bbf58cd5 to 1
  Normal  ScalingReplicaSet  87s   deployment-controller  Scaled down replica set my-nginx-5fbd7db759 to 1
  Normal  ScalingReplicaSet  87s   deployment-controller  Scaled up replica set my-nginx-55bbf58cd5 to 2
  Normal  ScalingReplicaSet  64s   deployment-controller  Scaled down replica set my-nginx-5fbd7db759 to 0
[root@k8s-node1 networking]# kubectl rollout history deployment.v1.apps/my-nginx
deployment.apps/my-nginx
REVISION  CHANGE-CAUSE
1         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx nginx=nginx:1.9.1 --record=true
2         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1 --record=true
3         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx: --record=true
4         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.7.9 --record=true

可以看到當前的獎鏡像版本是之前更新的nginx:1.7.9,再看一下Deployment的Rollout歷史:

# 查看my-nginx的歷史版本
kubectl rollout history deployment.v1.apps/my-nginx

# 輸出,最近的升級在最下面
deployment.apps/my-nginx
REVISION  CHANGE-CAUSE
1         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx nginx=nginx:1.9.1 --record=true
2         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1 --record=true
3         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx: --record=true
4         kubectl deployment.apps/my-nginx set image deployment.v1.apps/my-nginx my-nginx=nginx:1.7.9 --record=true

目前的鏡像版本是nginx:1.7.9,我本地更新過4次,現在進行回滾到最近一次:kubectl rollout undo deployment.v1.apps/my-nginx,或者直接使用--to-revision指定回滾到某個版本,比如:kubectl rollout undo deployment.v1.apps/my-nginx --to-revision=1,然後describe一下可以看到改變。

【伸縮Deployment】

 可以已經部署的Deployment進行伸縮:kubectl scale deployment.v1.apps/my-nginx --replicas=1,如果集羣開啓了“自動水平Pod伸縮”的功能,那就可以基於已存在的Pod所在的CPU效率選擇Pod的最大值和最小值,比如:kubectl autoscale deployment.v1.apps/my-nginx --min=10 --max=15 --cpu-percent=80

 按比例伸縮,滾動升級支持APP的多個版本同時運行,當在rollout期間在對Deployment進行滾動升級,那Deployment Controller爲了降低風險將會在現有的副本集中平衡額外的副本,這種行爲就是按比例伸縮(proportional scaling)。

【Deployment的暫停和繼續】

 在觸發1個或多個更新前可以暫停Deployment,然後再繼續,這將允許在暫停和恢復之間應用多個修復程序,而不會觸發不必要的rollout,比如之前的Deployment,暫停:kubectl rollout pause deployment.v1.apps/my-nginx,然後更新Deployment:kubectl set image deployment.v1.apps/my-nginx my-nginx=nginx:1.9.1,這樣不會有新的rollout開始,可以查看:kubectl rollout history deployment.v1.apps/my-nginx,在暫停的這個時間段可以做很多資源的更新,並且資源的更新是可以被使用的,比如:kubectl set resources deployment.v1.apps/my-nginx -c=my-nginx --limits=cpu=200m,memory=512Mi-c表示容器的名字)。Deployment初始狀態要比暫停的優先級高,所以他會繼續運行,但只要Deployment是暫停的Deployment新的更新將不會影響Deployment,最後恢復Deployment:kubectl rollout resume deployment.v1.apps/my-nginx,可以看到新的副本集出現:kubectl get rs -wkubectl get rs

【Deployment status】

 Deployment有各種狀態,可以通過kubectl rollout status deployments.v1.apps/my-nginx查看,主要有如下的幾種:

  1. Progressing Deployment:即正在運行狀態,Deployment此時應該出現某些行爲:創建新的副本集ReplicaSet、擴大最新的副本集、縮減舊的副本集、新Pod變爲ready或avaliable狀態;
  2. Complete Deployment:即完成狀態,Deployment應該是:所有和Deployment相關的副本集都已經更新至最新、且這些副本都處於available狀態、沒有Deployment的舊副本在運行;
  3. Failed Deployment:即失敗狀態,Deployment發生這種情況的因素可能是:配額不足、準備就緒探測器(即就緒探針)故障、鏡像拉取錯誤、權限不足、配置錯誤;

【清理策略】

 可以指定通過設置.spec.revisionHistoryLimit字段指定Deployment要維護多少舊的副本集ReplicaSet,重置後臺將會進行垃圾清理,默認爲10,這個其實就是在Deployment的更新歷史記錄的數量,如果將它設置爲0,那就不能進行回滾了。

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