首先我們要理解:一個應用跑在k8s叢集上了,那麼這個應用就是一個工作負載(workloads)。
在k8s中會用pod的來承載這個應用,那麼負責管理這個pod的東西就叫工作負載資源(workload resources)。
我們可以簡單理解為是這樣的:
工作負載資源又支援jj自定義或使用第三方資源,這裡我們先認識內建的,k8s內建工作負載資源包含如下:
- deployment
- replicaset
- statefulset
- daemonset
- jobs
- cronjob
- TTL Controller for Finished Resources
- ReplicationController (逐步被ReplicaSet替代)
那讓我們從最常用的deployment開始吧。
一個 Deployment 為 Pods和 ReplicaSets提供宣告式的更新能力,我們從下面幾個方面開始上手:
- 建立 Deployment 將 ReplicaSet 上線。 ReplicaSet 在後臺建立 Pods。 檢查 ReplicaSet 的上線狀態,檢視其是否成功。
- **通過更新 Deployment 的 Pod模板(TemplateSpec),宣告 Pod 的新狀態 。 **新的 ReplicaSet 會被建立,Deployment 以受控速率將 Pod 從舊 ReplicaSet 遷移到新 ReplicaSet。 每個新的 ReplicaSet 都會更新到 Deployment 的修訂版本。
- 如果 Deployment 與你的預期不符,可以回滾到較早的 Deployment 版本。 每次回滾都會更新到 Deployment 修訂的新版本。
- 通過Deployment 擴大應用規模承擔更多負載。
- 暫停 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資源建立物件的關係圖:
現在我們主要來看一下建立的這個nginx-deployment宣告。
我們把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中找到。
大多數字段都包含了一個預設值,除非有特殊需求,大多數時候很難被用到。如果需要的時候你再谷歌一下也不遲。到這裡deployment工作負載的第一個用例已經成了。
deployment更新
僅當 Deployment Pod 模板(即 .spec.template
欄位)發生改變時,例如模板的標籤或容器映象被更新, 才會觸發 Deployment 上線。
其他更新(如對 Deployment 執行擴縮容的操作)不會觸發上線動作。
- 我們可以通過
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
- 使用
kubectl edit
編輯deployment後自動更新
$ kubectl edit deployment/nginx-deployment --record
deployment.apps/nginx-deployment edited
- 直接更新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做一些更新
- 直接修改yml檔案,更新映象為nginx:1.17,並通過kubectl apply應用更改。
- 通過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