Deployment是一種高階控制器資源,在部署時,Deployment創建並管理ReplicaSet,由ReplicaSet創建管理pod。目的方便應用升級時,Deployment便於通過ReplicaSet管理一組pod進行應用升級。
1、Deployment的創建
與pod、replicaset一樣,deployment在k8s中也是一種資源,可以通過yaml的聲明方式聲明一套deployment的定義,然後通過kubectl create創建出deployment。下面以demo_deployment.yaml爲例
apiVersion: apps/v1beta1 #版本
kind: Deployment #資源類型
metadata: #deployment的元數據
name: mydeployment #Deployment的資源名字
spec: #Deployment描述信息
minReadySeconds: 10 #pod創建延遲至少10s然後才ready狀態
replicas: 3 #創建pod的副本數
template: #pod的模板信息
metadata: #pod的元數據
labels: #定義pod標籤
app: mynginx-pod #pod的標籤
spec: #pod中容器描述信息
containers: #定義容器
- name: mynginx #容器的名字
image: mynginx:v0.2 #容器中鏡像
ports: #定義容器暴露的端口
- containerPort: 80
根據yaml創建deployment
[root@k8s-master01 deployment_work]# ls
demo_deployment.yaml
#創建deployment
[root@k8s-master01 deployment_work]# kubectl create -f demo_deployment.yaml --record
deployment.apps/mydeployment created
#查詢deployment
[root@k8s-master01 deployment_work]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
mydeployment 3/3 3 3 10s
#查詢replicaset
[root@k8s-master01 deployment_work]# kubectl get rs
NAME DESIRED CURRENT READY AGE
mydeployment-7fd7865495 3 3 3 17s
#查詢pod
[root@k8s-master01 deployment_work]# kubectl get pod
NAME READY STATUS RESTARTS AGE
mydeployment-7fd7865495-57jnx 1/1 Running 0 29s
mydeployment-7fd7865495-8vfdl 1/1 Running 0 29s
mydeployment-7fd7865495-c7j7c 1/1 Running 0 29s
由此可見,deployment顯示創建了一個名字爲mydeployment-7fd7865495的replicaset,由replicaset創建了3個pod。–record能顯示變更歷史原因,方便查看每個版本變更的原因。
2、deployment管理應用升級
當應用需要升級時,只需要修改deployment中的pod模板就可以控制pod中應用從舊版本升級到新版本中。deployment升級時,通過新建一個ReplicaSet,然後通過ReplicaSet重建新版本應用的pod,然後刪除舊版本的pod,但是管理舊版本pod的ReplicaSet保留着,以防後續回滾用 deployment在升級pod應用過程 中採用兩種升級策略:
- Recreate : 刪除舊版本的pod後纔會創建新版本的pod,會導致應用出現短暫的停機狀態,如果應用不支持多版本,可以選擇該策略。
- RollingUpdate : 刪除舊版本的pod時,同時創建新版本的pod,應用平滑的升級,使應用在升級過程中也保持可用,但需要支持應用多版本,否則會導致數據錯亂。Deployment的默認升級策略。
下面通過示例演示滾動升級,首先通過deployment部署mynginx:v0.2版本的應用,然後滾動升級成mynginx:v0.3版本,首先查看v0.2版本應用
#查看部署的pod
[root@k8s-master01 deployment_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-6c5cf4c646-8knrf 1/1 Running 0 4m49s 10.244.2.75 k8s-node02 <none> <none>
mydeployment-6c5cf4c646-jp84k 1/1 Running 0 4m49s 10.244.1.73 k8s-node01 <none> <none>
mydeployment-6c5cf4c646-mwt2d 1/1 Running 0 4m49s 10.244.2.76 k8s-node02 <none> <none>
#訪問pod中的應用,輸出當前版本爲2
[root@k8s-master01 deployment_work]# curl 10.244.2.75
hello lzj, this is version 2
下面升級鏡像
kubectl set image deployment mydeployment mynginx=mynginx:v0.3
監控pod滾動更新狀態如下:
[root@k8s-master01 deployment_work]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
mydeployment-6c5cf4c646-8knrf 1/1 Running 0 18m
mydeployment-6c5cf4c646-jp84k 1/1 Running 0 18m
mydeployment-6c5cf4c646-mwt2d 1/1 Running 0 18m
mydeployment-797fcb456f-6x9xm 1/1 Running 0 16s
mydeployment-6c5cf4c646-8knrf 1/1 Terminating 0 18m
mydeployment-797fcb456f-dd26l 0/1 Pending 0 0s
mydeployment-797fcb456f-dd26l 0/1 Pending 0 0s
mydeployment-797fcb456f-dd26l 0/1 ContainerCreating 0 0s
mydeployment-6c5cf4c646-8knrf 0/1 Terminating 0 18m
mydeployment-797fcb456f-dd26l 1/1 Running 0 1s
mydeployment-6c5cf4c646-8knrf 0/1 Terminating 0 18m
mydeployment-6c5cf4c646-8knrf 0/1 Terminating 0 18m
mydeployment-6c5cf4c646-mwt2d 1/1 Terminating 0 18m
mydeployment-797fcb456f-kl2m4 0/1 Pending 0 0s
mydeployment-797fcb456f-kl2m4 0/1 Pending 0 0s
mydeployment-797fcb456f-kl2m4 0/1 ContainerCreating 0 0s
mydeployment-6c5cf4c646-mwt2d 0/1 Terminating 0 18m
mydeployment-797fcb456f-kl2m4 1/1 Running 0 2s
mydeployment-6c5cf4c646-mwt2d 0/1 Terminating 0 18m
mydeployment-6c5cf4c646-mwt2d 0/1 Terminating 0 18m
mydeployment-6c5cf4c646-jp84k 1/1 Terminating 0 18m
mydeployment-6c5cf4c646-jp84k 0/1 Terminating 0 18m
mydeployment-6c5cf4c646-jp84k 0/1 Terminating 0 19m
mydeployment-6c5cf4c646-jp84k 0/1 Terminating 0 19m
[root@k8s-master01 deployment_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-797fcb456f-6x9xm 1/1 Running 0 5m14s 10.244.1.74 k8s-node01 <none> <none>
mydeployment-797fcb456f-dd26l 1/1 Running 0 4m52s 10.244.2.77 k8s-node02 <none> <none>
mydeployment-797fcb456f-kl2m4 1/1 Running 0 4m31s 10.244.1.75 k8s-node01 <none> <none>
#請求pod,發現pod返回內容當前版本爲3
[root@k8s-master01 deployment_work]# curl 10.244.1.74
hello lzj, this is version 3
發現pod是先創建一個v0.3版本的pod,然後停止一個v0.2版本的pod,直至滾動結束。從更新的狀態中可以看出,deployment滾動更新時,是通過創建了另外一個ReplicaSet,然後通過ReplicaSet創建了3個v0.3版本的pod。最後把原來的ReplicaSet下的3個v0.2版本的pod刪除掉。
注意:如果修改了deployment中的pod模板,會立即觸發滾動更新,如果沒修改pod模板,只是修改了deployment的一些屬性,不會觸發滾動更新的。
3、deployment管理應用回滾
當deployment部署應用升級後,如果發現當前版本有bug,需要回滾到上一版本,則可以通過deployment的rollout undo進行回滾。回滾的原理就是根據舊版本的ReplicaSet重新建舊版本的Pod應用,然後刪除新版本的pod。如下所示,當前應用鏡像版本爲mynginx:v0.3,需要回滾到上一應用版本
[root@k8s-master01 dockerfile_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-797fcb456f-2xj82 1/1 Running 0 82s 10.244.1.80 k8s-node01 <none> <none>
mydeployment-797fcb456f-8kczn 1/1 Running 0 60s 10.244.2.81 k8s-node02 <none> <none>
mydeployment-797fcb456f-c7z25 1/1 Running 0 39s 10.244.1.81 k8s-node01 <none> <none>
#訪問pod中的當前應用,輸出內容爲v0.3版本的應用
[root@k8s-master01 dockerfile_work]# curl 10.244.1.80
hello lzj, this is version 3
#回滾到上一版本應用
[root@k8s-master01 dockerfile_work]# kubectl rollout undo deployment mydeployment
deployment.extensions/mydeployment rolled back
[root@k8s-master01 dockerfile_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-6c5cf4c646-4nbfv 1/1 Running 0 77s 10.244.1.82 k8s-node01 <none> <none>
mydeployment-6c5cf4c646-5nj5j 1/1 Running 0 55s 10.244.2.83 k8s-node02 <none> <none>
mydeployment-6c5cf4c646-88sjf 1/1 Running 0 99s 10.244.2.82 k8s-node02 <none> <none>
#回滾結束後,重新訪問pod中的應用,發現版本已經回退到v0.2版本
[root@k8s-master01 dockerfile_work]# curl 10.244.1.82
hello lzj, this is version 2
注意:執行上述操作後,應用已經回滾到了v0.2版本,如果按上述步驟再次執行就又會回到v0.3版本,可以通過指定回滾到的版本進行回滾。
#查詢deployment的滾動歷史,創建deployment時添加了--record,所以下面CHANGE-CAUSE纔會有變更步驟的記錄原因
[root@k8s-master01 dockerfile_work]# kubectl rollout history deployment mydeployment
deployment.extensions/mydeployment
REVISION CHANGE-CAUSE
1 kubectl create --filename=demo_deployment.yaml --record=true
3 kubectl create --filename=demo_deployment.yaml --record=true
4 kubectl create --filename=demo_deployment.yaml --record=true
#其中REVISION代表每次滾動時的版本編號,回滾時可以指定版本編號回滾到指定的版本。下面回滾到最初的應用版本。
[root@k8s-master01 dockerfile_work]# kubectl rollout undo deployment mydeployment --to-revision=1
deployment.extensions/mydeployment rolled back
[root@k8s-master01 dockerfile_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-7fd7865495-7kdjl 1/1 Running 0 2m37s 10.244.1.83 k8s-node01 <none> <none>
mydeployment-7fd7865495-m77pm 1/1 Running 0 2m15s 10.244.2.84 k8s-node02 <none> <none>
mydeployment-7fd7865495-tr2mm 1/1 Running 0 114s 10.244.1.84 k8s-node01 <none> <none>
#回滾到最初的版本後,訪問pod中的應用,發現輸出了最初的NGINX內容
[root@k8s-master01 dockerfile_work]# curl 10.244.1.83
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
4、滾動失敗,deployment自動回滾
在應用版本升級時,如果版本有bug,應控制deployment自動回滾到前一個版本。實現該功能需藉助minReadySeconds和探針實現。
minReadySeconds用來指定沒有任何容器crash的Pod並被認爲是可用狀態的最小秒數。默認是0(Pod在ready後就會被認爲是可用狀態)。如果minReadySeconds設置10s,可以使用minReadySeconds可以讓deployment在第一個pod就緒之後繼續等待10s,如pod沒有問題,繼續升級下一個pod繼續等待10s,如此類推。一般設置minReadySeconds時間等於應用啓動後可以正常接受流量的長度。在pod中設置就緒探針,如果在minReadySeconds時間內,探針失敗了,deployment進行自動回滾。下面通過demo_deployment.yaml實例演示
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mydeployment
spec:
minReadySeconds: 10
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
name: myreplicaset
labels:
app: myreplicaset
spec:
containers:
- name: mynginx
image: mynginx:v0.3
ports:
- containerPort: 80
其中可以通過定義deployment的屬性maxSurge與maxUnavailable控制滾動升級速率。
maxSurge:決定了deployment配置的副本數之外,最多允許超出的pod實例數量,比如副本數設置3,maxSurge設置的1,在deployment的滾動升級之間,最多允許存在4個 pod實例數量;
maxUnavailable:決定了deployment滾動升級之間,相對於期望副本數量最多有多少個pod實例數量處於不可用狀態。比如副本設置爲3,maxUnavailable設置爲1,滾動升級時最多有2個pod實例處於可用狀態。
#創建mydeployment
[root@k8s-master01 deployment_work]# kubectl apply -f demo_deployment.yaml --record
deployment.apps/mydeployment created
#查詢創建出來的pod
[root@k8s-master01 dockerfile_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-768bc94c96-gtf9w 1/1 Running 0 15s 10.244.1.92 k8s-node01 <none> <none>
mydeployment-768bc94c96-mphqp 1/1 Running 0 15s 10.244.2.93 k8s-node02 <none> <none>
mydeployment-768bc94c96-s8npx 1/1 Running 0 15s 10.244.1.93 k8s-node01 <none> <none>
#訪問pod中應用,版本爲2
[root@k8s-master01 dockerfile_work]# curl 10.244.1.92
hello lzj, this is version 2
下面修改yaml中鏡像併爲pod添加探針
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: mydeployment
spec:
minReadySeconds: 10
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
name: myreplicaset
labels:
app: myreplicaset
spec:
containers:
- name: mynginx
image: mynginx:v0.3 #鏡像修改爲v0.3版本
readinessProbe: #增加就緒探針
periodSeconds: 1
httpGet:
path: /test.html
port: 8080
ports:
- containerPort: 80
容器中暴漏的是80端口,而探針探測的時8080端口,探針必定時失敗的,下面執行deployment的滾動升級
#滾動升級mydeployment
[root@k8s-master01 deployment_work]# kubectl apply -f demo_deployment.yaml --record
deployment.apps/mydeployment configured
#查看升級後的pod,發現滾動失敗,創建第一個pod時,狀態爲就緒,因此deployment自動回滾,回到v0.2版本
[root@k8s-master01 dockerfile_work]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mydeployment-5bcf884b6d-4ldjx 0/1 Running 0 11m 10.244.2.94 k8s-node02 <none> <none>
mydeployment-768bc94c96-gtf9w 1/1 Running 0 13m 10.244.1.92 k8s-node01 <none> <none>
mydeployment-768bc94c96-mphqp 1/1 Running 0 13m 10.244.2.93 k8s-node02 <none> <none>
mydeployment-768bc94c96-s8npx 1/1 Running 0 13m 10.244.1.93 k8s-node01 <none> <none>
#訪問pod中應用,發現應用沒有升級到v0.3版本,依然是v0.2版本
[root@k8s-master01 dockerfile_work]# curl 10.244.1.92
hello lzj, this is version 2
注意
1. kubectl create 與 kubectl apply區別
kubectl create只能執行一次,不能重複執行;
kubectl apply可以重複執行,是增量的執行,yaml中增加了什麼東西,apply執行時只會創建增加的資源。
2. deployment相關操作命令
kubectl rollout status deployment mydeployment #查看deployment部署狀態
kubectl set image deployment mydeployment mynginx=mynginx:v0.2 #版本升級爲v0.2
kubectl rollout undo deployment mydeployment #回滾到上一級
kubectl rollout undo deployment mydeployment --to-revision=2 #回滾到指定的步驟
kubectl rollout pause deployment mydeployment #暫停升級,可以多次修改deployment後再恢復執行
kubectl rollout resume deployment mydeployment #恢復升級
參考《kubenetes in Action》