Nginx+keepalived配置檔案+指令碼檔案
一、簡介
Deployment實現了Kubernetes專案中非常重要的功能:
(1)、水平擴充套件
(2)、水平收縮
比如更新了Deployment的Pod模板,比如修改了映象版本,那麼Deployment就會遵循滾動更新(rolling update)的方式來升級現有的容器 。這個操作依賴Kubernetes中一個非常重要的API物件:ReplicaSet(詳情見3.2)。不過Deployment又在ReplicaSet之上又做了新的封裝,其新特性有如下幾點:
(1)、Deployment具有ReplicaSet的全部功能;
(2)、可以檢視Deployment升級詳細狀態和事件;
(3)、當升級出現問題時,可以使用回滾操作回滾到之前的任一版本;
(4)、新增版本記錄,每一次操作Deployment都會記錄下來,這也是版本回滾的基礎;
(5)、對每一次升級,都能進行暫停和啟動;
從上面可以知道,Deployment已經具體ReplicaSet的全部功能,並且還有許多新的功能,所以推薦使用Deployment來管理Pod。
從上圖可以看到Deployment、ReplicaSet、Pod它們以層層控制關係,Deployment可以擁有多個ReplicaSet,一個ReplicaSet可以擁有多個Pod。一個Deployment擁有多個ReplicaSet主要是為了支援回滾操作,每當操作Deployment的時候,就會生成一個新的ReplicaSet,然後逐步更新新的Pod,而老的ReplicaSet會逐步減少Pod直到新的ReplicaSet全部接管。這時候並不會刪除老的ReplicaSet,系統會將其儲存下來,以備回滾使用。
ReplicaSet還負責通過"控制器模式",保證系統的Pod數永遠等於期望數,這也是Deployment只允許restartPolicy=Always的原因:只有在容器能保證自己始終處於running狀態,通過ReplicaSet調整Pod的數量才有意義。
而在此基礎上,Deployment同樣通過"控制器模式",來操作ReplicaSet的個數和屬性,進而實現水平擴充套件/收縮和滾動更新這兩個動作。其中水平擴充套件和收縮非常容易實現,Deployment Controller只需要修改它的ReplicaSet的Pod副本數就可以了。
二、水平擴充套件/收縮
我們看下面一個Deployment例子:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
然後我們建立這個Deployment。
補充欄位說明:
(1)、READY:使用者期望的Pod個數;
(2)、UP-TO-DATE:當前處於最新版本的Pod個數;
(3)、AVAILABLE:當前已經可用的Pod數,也就是處於running狀態並且是最新的版本;
從上我們看到Deployment和Pod都正常啟動並且數量和期望的一致,現在我們使用kubectl scale來做水平擴充套件收縮。
(1)、擴充套件
(2)、收縮
當然,除了使用命令的方式來做水平擴充套件/收縮以外,還可以直接編輯其配置檔案,使用kubectl edit命令,如下:
然後儲存退出,就可以看到如下擴充套件已經OK了,收縮是一樣的操作:
除了上面兩種方法,還可以直接編輯我們原始的YAML檔案,然後使用kubectl apply -f nginx-deployment.yaml來做擴充套件和收縮,甚至可以用kubectl patch來打補丁,其內容用JSON語法。
三、滾動更新/回滾
3.1、滾動更新
上面介紹了水平擴充套件和收縮,下面來介紹一下滾動更新和回滾操作。
我們還是以上面的YAML檔案為例,首先,我們建立這個YAML檔案,這一次我們在建立的命令上加一個--record,它的作用是記錄每次我們操作所執行的命令,方便後面操作。
[root@master deployment]# kubectl apply -f nginx-deployment.yaml --record
deployment.apps/nginx-deployment configured
然後我們來檢視叢集狀態:
[root@master deployment]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 3/3 3 3 6h6m
我們可以通過kubectl rollout status 來檢視Deployment物件的狀態變化,如下:
[root@master deployment]# kubectl rollout status deployment/nginx-deployment deployment "nginx-deployment" successfully rolled out [root@master deployment]#
我們可以檢視Deployment的ReplicaSet:
[root@master deployment]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5754944d6c 3 3 3 54m
然後我們修改Pod的模板做滾動更新,修改Pod模板的方式也有很多,可以直接kubectl edit 修改配置檔案,也可以修改原始檔,然後使用kubectl apply -f 來使配置生效,我們這裡採用kubectl edit來直接用來配置檔案,這種修改儲存退出就會立即生效,如下:
我們把映象版本更新為1.8然後儲存退出。然後使用kubectl rollout status來檢視Deployment的變化情況:
[root@master ~]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
然後我們可以看到會啟動一個新的ReplicaSet,來使用這個新的Pod模板來建立新的副本,然後會從老的ReplicaSet刪除老的副本,如此進行直到版本更新完成。像這樣將一個叢集中正在執行的多個Pod版本,交替進行升級的過程叫做滾動更新。
我們可以通過kubectl get rs檢視新舊兩個ReplicaSet的狀態:
[root@master ~]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5754944d6c 0 0 0 67m nginx-deployment-6f655f5d99 3 3 3 7h2m
這種滾動更新的好處是:如果在更新過程中,新版本Pod有問題,那麼滾動更新就會停止,這時候運維和開發就可以介入檢視其原因,由於應用本身還有兩個舊版本的Pod線上,所以並不會對服務造成太大的影響;當然,這時候應在Pod中加上health check檢查應用的健康狀態,而不是簡單的依賴容器的running狀態。為了進一步保證服務的延續性,Deployment Controller還會確保在任何時間視窗內,只有指定比例的Pod處於離線狀態,同時它也會確保在任何時間視窗內,只有指定比例的Pod被建立,這個比例預設是DESIRED的25%。
當然可以通過修改Deployment物件的一個欄位RollingUpdateStrategy來自定義,比如:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: ... strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 1
說明:
(1)、maxSurge:定義除了DESIRED數量之外,在一次滾動更新過程中,Deployment還可以建立多少Pod;
(2)、maxUnavailable:定義在一次滾動更新過程中,Deployment最多可以刪除多少Pod;
另外,這兩個配置還可以通過設定百分值來表示。
如此,我們可以得到如下關係圖:
Deployment實際控制的是ReplicaSet的數目以及每個ReplicaSet的屬性。而一個應用版本,對應的就是一個ReplicaSet,而這個版本應有的Pod數量,是通過ReplicaSet自己的控制器來管理。
3.2、回滾
從上面我們明白了應用版本和ReplicaSet的對應關係,下面就來介紹一下它是如何回滾的。
現在我們來更改Pod模板中的映象版本資訊,上面介紹了直接修改配置檔案的方法來修改,這次用kubectl set image命令來修改。
如下,我們修改一個不存在的nginx版本,故意製造故障。
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.999 deployment.extensions/nginx-deployment image updated
然後我們來檢視ReplicaSet的狀態:
[root@master ~]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5754944d6c 0 0 0 103m nginx-deployment-6f655f5d99 3 3 3 7h37m nginx-deployment-79c5b65fdb 1 1 0 41s
我們可以看到新建立了一個ReplicaSet,其中READY狀態為0,這是因為我們這個映象並不存在,所以就無法更新。
我們可以通過一下方法進行回滾:
(1)、直接回滾到上一個版本,我們執行kubectl rollout undo命令,如下:
[root@master ~]# kubectl rollout undo deployment/nginx-deployment deployment.extensions/nginx-deployment rolled back [root@master ~]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5754944d6c 0 0 0 106m nginx-deployment-6f655f5d99 3 3 3 7h41m nginx-deployment-79c5b65fdb 0 0 0 3m59s
這時候通過檢視ReplicaSet的狀態,可以看到剛新建立的ReplicaSet的Pod數收縮為0了。
(2)、我們通過檢視歷史版本,恢復到任意版本,我們通過kubectl rollout history命令,如下:
[root@master ~]# kubectl rollout history deployment/nginx-deployment deployment.extensions/nginx-deployment REVISION CHANGE-CAUSE 2 kubectl apply --filename=nginx-deployment.yaml --record=true 4 kubectl apply --filename=nginx-deployment.yaml --record=true 5 kubectl apply --filename=nginx-deployment.yaml --record=true
然後選擇我們可以檢視對應版本的詳細資訊:
kubectl rollout history deployment/nginx-deployment --revision=2
確定是我們需要的版本後就可以執行如下命令進行回滾操作:
[root@master ~]# kubectl rollout undo deployment/nginx-deployment --to-revision=2 deployment.extensions/nginx-deployment rolled back
這時我們可以看到ReplicaSet已經回滾到上一個版本了:
[root@master ~]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5754944d6c 3 3 3 115m nginx-deployment-6f655f5d99 0 0 0 7h50m nginx-deployment-79c5b65fdb 0 0 0 13m
顯然,從上面整個過程,我們知道只要我們對這個Deployment做一次更新操作,就會生成一個ReplicaSet,如果更新很頻繁,這顯然是有點浪費資源了,Kubernetes為了處理這類需求提供了一個指令kubectl rollout pause,它會讓我們對Deployment的多次操作只生成一個ReplicaSe。具體用法如下:
[root@master ~]# kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused
然後可以用kubectl set image 或者kubectl edit隨意修改這個Deployment的內容,等到我們修改完成後,再執行kubectl rollout resume命令來做恢復操作,比如我們修改image映象和新增一個新的容器,然後儲存退出:
然後執行恢復命令:
[root@master ~]# kubectl rollout resume deployment/nginx-deployment
deployment.extensions/nginx-deployment resumed
我們上面最了兩次修改,然後我們檢視ReplicaSet:
[root@master ~]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-5754944d6c 0 0 0 132m nginx-deployment-5b9b565595 1 1 0 11s nginx-deployment-6f655f5d99 2 2 2 8h
然後我們發現只生成了一個ReplicaSet,由於我本地沒有這個映象,所以拉取映象過程中READY狀態為0。
這種辦法會隨著應用版本的不斷增加,也會建立很多的ReplicaSet版本,所以Deployment物件還定義了一個欄位revisionHistoryLimit,就是定義Kubernetes為Deployment保留的歷史版本個數。
我們可以通過kubectl edit 進去檢視預設保留的個數:
四、總結
從全文可知,Deployment實際是一個兩層控制器:
(1)、它通過ReplicaSet的個數來描述應用版本個數;
(2)、它通過ReplicaSet的屬性來保證Pod的副本數;
而且Deployment的靈活控制,很方便水平擴充套件/收縮還有滾動更新以及回滾操作。