1. 程式人生 > 實用技巧 >Nginx+keepalived配置檔案+指令碼檔案

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的靈活控制,很方便水平擴充套件/收縮還有滾動更新以及回滾操作。