3.3 Deployments(部署)
Deployments控制器(Deployment controller,Deployment應該也是控制器的一種吧)提供了Pod和ReplicaSets的聲明式更新。在Deployment對象中,可以描述對應的desired state,Deployments controller將會已可控的頻率去改變實際狀態變成desired state,可以定義Deployments創建新的ReplicaSets,或者移除已有的Deployments並讓新的Deployment接管已有的Pod。類似的,不推薦直接管理ReplicaSets,而應該通過操縱Deployment對象去管理。
【使用場景】
- 創建Deployment,用於推出副本集:副本集子在幕後創建,檢查推出的狀態是否成功;
- 聲明Pod的新狀態:更新Deployment的Pod模板規約PodTemplateSpec,一個新的ReplicationSet將會被創建,Deployment管理將Pod以一個可控的速度移到新的副本集中,每個新的副本集都會更新Deployment的修改。
- 回滾Deployment的早期版本:如果當前的Deployment的狀態不穩定,每個回滾更新Deployment;
- 擴大Deployment以方便更多的負載;
- 暫停Deployments以對其podTemplatespec應用多個修復程序,然後恢復Deployments以啓動新的滾動;
- 使用Deployment的狀態作爲滾動卡住的標識;
- 清理不再需要的老的ReplicaSets;
【創建Deployment】
Deployment需要一個apiVersion
、kind
、metadata
字段,當然也需要.spec
的東西了,其中.spec.template
和.spec.selector
是必需的,.spec.strategy
表示替換舊Pod的策略,.spec.strategy.type
可以設置爲Recreate
(在新Pod創建之前殺死所有已有的Pod)或RollingUpdate
(默認值,可以指定maxUnavailable
和maxSurge
控制升級進程)。
下面是創建一個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
的格式,其實就是舊版的CURRENT
和DESIRED
參數,前者表示當前正在運行副本的數量(即.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 -w
和kubectl get rs
。
【Deployment status】
Deployment有各種狀態,可以通過kubectl rollout status deployments.v1.apps/my-nginx
查看,主要有如下的幾種:
- Progressing Deployment:即正在運行狀態,Deployment此時應該出現某些行爲:創建新的副本集ReplicaSet、擴大最新的副本集、縮減舊的副本集、新Pod變爲ready或avaliable狀態;
- Complete Deployment:即完成狀態,Deployment應該是:所有和Deployment相關的副本集都已經更新至最新、且這些副本都處於available狀態、沒有Deployment的舊副本在運行;
- Failed Deployment:即失敗狀態,Deployment發生這種情況的因素可能是:配額不足、準備就緒探測器(即就緒探針)故障、鏡像拉取錯誤、權限不足、配置錯誤;
【清理策略】
可以指定通過設置.spec.revisionHistoryLimit
字段指定Deployment要維護多少舊的副本集ReplicaSet,重置後臺將會進行垃圾清理,默認爲10,這個其實就是在Deployment的更新歷史記錄的數量,如果將它設置爲0,那就不能進行回滾了。