k8s工作負載資源之deployment

iqsing發表於2021-09-22

首先我們要理解:一個應用跑在k8s叢集上了,那麼這個應用就是一個工作負載(workloads)。

在k8s中會用pod的來承載這個應用,那麼負責管理這個pod的東西就叫工作負載資源(workload resources

我們可以簡單理解為是這樣的:

image-20210918102050547

工作負載資源又支援jj自定義或使用第三方資源,這裡我們先認識內建的,k8s內建工作負載資源包含如下:

  • deployment
  • replicaset
  • statefulset
  • daemonset
  • jobs
  • cronjob
  • TTL Controller for Finished Resources
  • ReplicationController (逐步被ReplicaSet替代)

那讓我們從最常用的deployment開始吧。

一個 Deployment 為 Pods和 ReplicaSets提供宣告式的更新能力,我們從下面幾個方面開始上手:

  1. 建立 Deployment 將 ReplicaSet 上線。 ReplicaSet 在後臺建立 Pods。 檢查 ReplicaSet 的上線狀態,檢視其是否成功。
  2. **通過更新 Deployment 的 Pod模板(TemplateSpec),宣告 Pod 的新狀態 。 **新的 ReplicaSet 會被建立,Deployment 以受控速率將 Pod 從舊 ReplicaSet 遷移到新 ReplicaSet。 每個新的 ReplicaSet 都會更新到 Deployment 的修訂版本。
  3. 如果 Deployment 與你的預期不符,可以回滾到較早的 Deployment 版本。 每次回滾都會更新到 Deployment 修訂的新版本。
  4. 通過Deployment 擴大應用規模承擔更多負載
  5. 暫停 Deployment ,對 PodTemplateSpec 做修改然後恢復執行,讓pod更新到新版本。

deployment建立

說了這麼多還不如手動寫一個deployment的yml宣告實在(如果你喜歡json也可以是json格式,本質上還是將yml轉換為json格式請求的api)。

下面deployment建立了一個replicaset,這個replicaset將會啟動三個nginx的pod:

nginx-deployment.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-web
        image: nginx:latest
        ports:
        - containerPort: 80

通過kubectl apply 將宣告檔案轉換為api提交給apiserver

$ kubectl apply -f nginx-deployment.yml 
deployment.apps/nginx-deployment created

檢視deployment資源建立的物件nginx-deployment(這裡的物件與程式語言中物件同義)

$ kubectl get deployment
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3/3     3            3           67m

檢視nginx-deplyment建立的replicat物件nginx-deployment-767cf44bff

$kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-767cf44bff   3         3         3       68m

最後是nginx-deployment-767cf44bff建立的三個pod物件

$ kubectl get pod 

NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE
default       nginx-deployment-767cf44bff-9fj8q   1/1     Running   0          13m
default       nginx-deployment-767cf44bff-f746l   1/1     Running   0          13m
default       nginx-deployment-767cf44bff-ktbzl   1/1     Running   0          13m

也可以通過rollout status 檢視 Deployment 上線狀態。

$kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out

這就是deployment資源建立物件的關係圖:

image-20210918111755912

現在我們主要來看一下建立的這個nginx-deployment宣告。

image-20210918154910640

我們把yml檔案分為兩個大部分(紅色):

  • 屬性。

    • apiVersion - 建立該物件所使用的 Kubernetes API 的版本
    • kind - 想要建立的物件的類別
    • metadata - 幫助唯一性標識物件的一些資料,包括一個 name 字串、UID 和可選的 namespace
  • 規格 spec(specification)

    • replicas - 期望的pod副本數量
    • selector - pod標籤選擇器
    • template - pod模板

    我們在selector中匹配包含app=nginx標籤的pod,pod模板中又為新建立的pod打上app=nginx的標籤,這樣就形成了控制閉環。

我們通過可以show-labels檢視pod的標籤

$ kubectl get pod  --show-labels
NAME                                READY   STATUS    RESTARTS   AGE   LABELS
nginx-deployment-767cf44bff-9fj8q   1/1     Running   0          81m   app=nginx,pod-template-hash=767cf44bff
nginx-deployment-767cf44bff-f746l   1/1     Running   0          81m   app=nginx,pod-template-hash=767cf44bff
nginx-deployment-767cf44bff-ktbzl   1/1     Running   0          81m   app=nginx,pod-template-hash=767cf44bff

為什麼pod中又有一個pod-template-hash標籤?

eployment 控制器將 pod-template-hash 標籤新增到 Deployment 所建立的每一個 ReplicaSet 中。我們來看一下rs的selector描述:

$ kubectl describe rs
Name:           nginx-deployment-767cf44bff
Namespace:      default
Selector:       app=nginx,pod-template-hash=767cf44bff

pod-template-hash 標籤是通過對 ReplicaSet 的 PodTemplate 進行雜湊處理,此標籤可確保 Deployment 的子 ReplicaSets 不衝突,所生成的雜湊值被新增到 ReplicaSet的selector、Pod 模板labels、以及 ReplicaSet 旗下的任何 Pod 中。這樣deployment下的replicaset只能控制自己的pod。恩,妙哉。

不同工作負載資源所建立的物件,spec是不同的。比如在Deployment中spec可以包含如下欄位,這個可以在Kubernetes API中找到。

image-20210918144005483

大多數字段都包含了一個預設值,除非有特殊需求,大多數時候很難被用到。如果需要的時候你再谷歌一下也不遲。到這裡deployment工作負載的第一個用例已經成了。


deployment更新

僅當 Deployment Pod 模板(即 .spec.template欄位)發生改變時,例如模板的標籤或容器映象被更新, 才會觸發 Deployment 上線。

其他更新(如對 Deployment 執行擴縮容的操作)不會觸發上線動作。

image-20210920204824833

  1. 我們可以通過kubectl set 命令更新現有工作負責資源
$ kubectl set image deployment/nginx-deployment nginx-web=nginx:1.17 --record
deployment.apps/nginx-deployment image updated

--record 用於記錄kubectl對資源的操作。便於後期需要時回滾。下面會說到。

kubectl set -h 查詢set支援更新的內容。

Available Commands:

  • env Update environment variables on a pod template
  • image Update image of a pod template
    resources Update resource requests/limits on objects with pod templates
  • selector Set the selector on a resource
  • serviceaccount Update ServiceAccount of a resource
  • subject Update User, Group or ServiceAccount in a RoleBinding/ClusterRoleBinding
  1. 使用kubectl edit編輯deployment後自動更新
$ kubectl edit deployment/nginx-deployment --record
deployment.apps/nginx-deployment edited
  1. 直接更新deployment yml檔案

個人覺得最好的方式是更新yml宣告檔案,通過kubectl apply 應用即可,這樣你只要管理好你的的nginx-deployment.yml做到心中有數

當我們更新後檢視rs狀態,此時deployment 建立了一個新的nginx-deployment replicaset並投入使用。

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-64f9765d86   4         4         4       4h11m
nginx-deployment-6cf9cc9c9d   0         0         0       5h6m

這裡順便看一下deployment中pod滾動更新策略

我們可以通過kubectl describe deployment 檢視RollingUpdateStrategy欄位,即在滾動更新時最大不可用pod數為1/4,最大可用pod數為期望副本數1.25倍(多25%)。

RollingUpdateStrategy: 25% max unavailable, 25% max surge

假如我們將 deployment_A 中4個副本(pod)更新到deployment_B(也是4副本),其中的某個資料pod狀態如下

$ kubectl get pod 
NAME                                READY   STATUS              RESTARTS   AGE
nginx-deployment-64f9765d86-c9rlj   0/1     ContainerCreating   0          2s
nginx-deployment-64f9765d86-wngmx   0/1     ContainerCreating   0          2s
nginx-deployment-7fcdcb4b75-lmsmm   1/1     Running             0          4h6m
nginx-deployment-7fcdcb4b75-m99tx   1/1     Terminating         0          4h5m
nginx-deployment-7fcdcb4b75-tghb2   1/1     Running             0          4h5m
nginx-deployment-7fcdcb4b75-xfs2m   1/1     Running             0          4h6m

即只有1個在停止,正在建立2個新pod(即將有5個可用),詳細滾動過程可通過kubectl descibe deployment中events檢視。

儘量不要更新模板中labels,會造成pod孤立。在某些API版本已經被禁止了。


deployment回滾

deployment回滾和更新一樣,Pod 模板部分會被回滾。

我們通過 rollout history 來檢視某個deployment的歷史版本。即之前通過--record所記錄的。

$ kubectl  rollout history   deployment/nginx-deployment 
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         kubectl apply --filename=nginx-deployment.yml --record=true
4         kubectl apply --filename=nginx-deployment.yml --record=true
5         kubectl set image deployment/nginx-deployment nginx-web=nginx:1.17 --record=true
9         kubectl edit deployment/nginx-deployment --record=true
10        kubectl edit deployment/nginx-deployment --record=true

回滾到第5個版本。

$ kubectl rollout undo deployment/nginx-deployment --to-revision=5
deployment.apps/nginx-deployment rolled back

或者直接回滾到上一個版本。

$ kubectl rollout undo deployment/nginx-deployment

還是如前面所說,回滾只一種更工程化的說法,其實回滾也是一種更新,yml宣告依然是核心。所以我們更應該關注的對deployment的yml檔案的版本控制。


deployment縮放

縮放控制的是.spec.replicas,也可通過scale命令操作。

$ kubectl scale deployment/nginx-deployment --replicas=6
deployment.apps/nginx-deployment scaled

水平自動縮放本為暫不涉及,後面文章會詳細討論。可以參考:Horizontal Pod Autoscaler


deployment暫停與恢復

我們可以在觸發更新之前暫停 Deployment,然後做多個修改之後再恢復,進行一次性上線。

還是我們之前的deployment

$ kubectl get deploy
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   4/4     4            4           30m

$ kubectl get rs
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-64f9765d86   4         4         4       30m

暫停deployment

$ kubectl rollout pause deployment/nginx-deployment
error: deployments.apps "nginx-deployment" is already paused

對nginx-deployment做一些更新

  1. 直接修改yml檔案,更新映象為nginx:1.17,並通過kubectl apply應用更改。
  2. 通過set做資源限制。
$ kubectl set resources deployment/nginx-deployment -c=nginx-web --limits=cpu=50m,memory=100Mi
deployment.apps/nginx-deployment resource requirements updated

此時我們檢視rs副本狀態,檢視deployment版本資訊

$ kubectl get rs 
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-64f9765d86   4         4         4       40m

$ kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment 
REVISION  CHANGE-CAUSE
1         <none>

可以看到還是之前的rs,deployment並沒有將我們的修改應用到物件中。

現在我們將deployment通過Resume恢復

$ kubectl rollout resume deployment/nginx-deployment
deployment.apps/nginx-deployment resumed

檢視rs狀態

$ kubectl get rs 
NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-64f9765d86   3         3         3       41m
nginx-deployment-7f4447656b   2         2         0       4s

這會deployment已恢復,並應用了對資源物件的更新。


參考:

k8s官方文件Deployment

相關文章