引言
k8s部署無狀態應用后,若需要更新應用時,可以通過使用ReplicationController或ReplicaSet實現升級,主要有兩種方式:
- 直接刪除所有現有的pod,然后創建新的pod;
- 先創建新的pod,再刪除舊pod。這里面也有兩種方式,一種是先等所有新pod都運行成功后,應用切換到新pod訪問,一次性刪除所有舊pod;另一種是滾動升級方式逐步新建pod代替舊pod。
下面我們將先看一下常用的相關術語,然后看一下升級pod的演進方式。
其他相關術語
Pod:每個Pod是一個或一組緊密相關的容器,每個Pod就像是一個獨立的邏輯機器,擁有自己的IP、主機名、進程等,運行一個獨立的應用程序,是K8S調度的基本單位。
ReplicationController:簡稱RC,旨在創建和管理一個Pod的多個副本(replicas)。當Pod副本數少於指定數目,RC就會啟動運行新的Pod副本;多於指定數目,RC就會殺死多余的Pod副本。
ReplicaSet:是新一代的RC,其相比於RC,Pod選擇器的表達能力更強,其選擇器可匹配缺少某個標簽或特定標簽名的Pod。
刪舊pod,建新pod
假設ReplicationController管理一組v1版本的pod,直接通過將pod模板修改為v2版本的鏡像,刪除舊的pod實例,RC檢測到當前沒有pod匹配標簽選擇器,就會創建新的實例。
- 階段1:原v1版本的RC有3個副本pod-v1。
- 階段2:pod模板發生修改,由初始的v1版本修改為v2版本。
- 階段3:pod-v1被手動刪除。
- 階段4:RC檢測到當前沒有pod匹配標簽選擇器,根據模板創建新的pod-v2。在階段3過渡到階段4期間,服務會出現短暫的不可用。
建新pod,刪舊pod
如果客戶不能接受升級更新期間出現短暫的不可用的服務,那就需要先創建新的pod,再刪除舊pod,這需要更多的硬件資源來支撐新舊pod同時存在的場景。
創建所有新pod,刪除所有舊pod
pod一般是通過Service來暴露服務的,在運行新版本pod前,Service都是訪問的舊版本pod,當新版本pod創建且正常運行后,修改服務標簽選擇器切換Service流量至新pod,切換完畢后,刪除舊RC,就可以刪除所有舊pod。這種方式就是所謂的藍綠部署
。
- 階段1:原v1版本的RC有3個副本pod-v1。
- 階段2:新建v2版本的RC,並且RC-v2自動創建了新的v2版本的pod。
- 階段3:Service的流量切換到pod-v2,正常運行起來。
- 階段4:刪除RC-v1,從而自動刪除pod-v1。
滾動新建和刪除pod
除了一次性創建新pod再一次性刪除舊pod,我們還可以逐步遞進的對舊版本pod進行刪除,對新版本pod進行創建。這個可以通過對舊版本RC逐步縮容,同時對新版本RC進行擴容來實現。
- 階段1:v1版本的RC副本數為3,有3個pod-v1。
- 階段2:RC-v1副本數降為2,自動刪除一個pod-v1,此時,創建一個v2版本的RC,且pod副本數為1,會自動新建一個v2版本的pod。
- 階段3:RC-v1副本數降為1,自動再刪除一個pod-v1,RC-v2的副本數為2,再自動新建一個pod-v2。
- 階段4:RC-v1副本數降為0,並且刪掉RC-v1,RC-v2副本數升為3,從而創建第3個pod-v2,至此完成滾動升級。
引入Deployment
ReplicationController和ReplicaSet這兩種資源對象需要其他控制器進行配合才可以實現滾動升級,並且難度大,因此k8s提供了一種基於ReplicaSet的資源對象Deployment可以支持聲明式
地更新應用。
Deployment介紹
Deployment概述
Deployment是K8s在1.2版本引入的,是一種更高階的資源,用於部署應用程序並以聲明的方式升級應用,從而更好地解決pod編排問題。
Deployment使用機制
Deployment在內部使用了ReplicaSet實現編排pod功能,當創建一個Deployment時,ReplicaSet資源會隨之創建,ReplicaSet是新一代的ReplicationController,並推薦使用它替代ReplicationController來復制和管理Pod,在使用Deployment時,實際的Pod是由Deployment的ReplicaSet創建和管理的。
Deployment使用場景
- 創建Deployment對象生成對應的ReplicaSet並完成pod副本創建;
- 通過檢查Deployment狀態(查看pod副本數量是否達到預期值)檢驗應用部署是否完成;
- 更新Deployment從而創建新的pod;
- 當前Deployment不穩定或故障,回滾到之前某個版本的Deployment(歷史版本revision)
- 暫停Deployment並修改多個pod的template spec配置項,再恢復Deployment進行新的發布部署;
- 擴展Deployment從而應對高負載場景;
- 清理不再需要使用的舊版本ReplicaSet;
Deployment使用
Deployment基本命令
假設Deployment的服務名稱為test-tomcat-deploy,yaml模板文件名為test-tomcat.yaml。使用命令時,deploy等價於deployment等價於deployments。若需要指定命名空間ns_name時,需要加上-n ns_name
。
創建deployment
- 基於模板創建
$ kubectl create -f test-tomcat.yaml
刪除deployment
- 基於模板刪除
$ kubectl delete -f test-tomcat.yaml
- 基於名稱刪除
$ kubectl delete deployment test-tomcat-deploy
更新deployment
- 基於模板更新
$ kubectl apply -f test-tomcat.yaml
- 基於名稱更新
$ kubectl edit deploy/test-tomcat-deploy
查看deployment
- 基於模板查看
$ kubectl get deploy test-tomcat-deploy -o yaml
- 基於名稱查看
$ kubectl describe deployments test-tomcat-deploy
- 查看列表
$ kubectl get deploy
資源對象信息
Deployment信息
[root@localhost ~]# kubectl get deploy -n kube-system
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
st-ui-wnunzeyg 1 1 1 1 1d
st-ui-x3w4xumy 1 1 1 1 1d
DESIRED
:pod副本數量的期望值(Deployment中定義的Replica數)CURRENT
:當前Replica值(Deployment實際創建的ReplicaSet中Replica值),該值會一直增加到DESIRED值為止才算整個應用實例創建完畢,部署才算完成。UP-TO-DATE
:最新版本的pod副本數量,用於指示在滾動升級過程中,有多少pod副本已成功升級。(Deployment滾動升級過程中ReplicaSet的Replica成功數)AVAILABLE
:當前集群中可用pod副本數。(Deployment創建的ReplicaSet中Replica存活數)AGE
:表示距離最后一次操作的時長。
ReplicaSet信息
[root@localhost ~]# kubectl get rs -n kube-system
NAME DESIRED CURRENT READY AGE
st-ui-wnunzeyg-391614280 1 1 1 1d
st-ui-x3w4xumy-1656786196 1 1 1 1d
我們可以看到ReplicaSet的命名和Deployment是相關的,ReplicaSet命名是以Deployment名為前綴,在Deployment名字基礎上又加了一串隨機數。
Pods信息
[root@localhost ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
st-ui-wnunzeyg-391614280-3brk8 1/1 Running 0 1d
st-ui-x3w4xumy-1656786196-f4w8z 1/1 Running 0 1d
pod名稱以Deployment中的ReplicaSet名稱為前綴,在此基礎上又加了隨機字符串。
Deployment更新
更新策略
在Deployment中,可以通過spec.strategy指定Pod更新的策略,目前支持:Recreate(重建)
和RollingUpdate(滾動更新)
,默認是RollingUpdate。
Recreate:設置spec.strategy.type=Recreate
,更新方式為:Deployment在更新Pod時,會先殺掉所有正在運行的Pod,然后創建新的Pod。
RollingUpdate:設置spec.strategy.type=RollingUpdate
,更新方式為:Deployment會以滾動的方式來漸變性的更新Pod,即Pod新版本的遞增,舊版本的遞減的一個過程。
滾動更新
概念
“滾動”,給人的是一種“圓”的印象,持續,不中斷的意思,類似於“持續交付”的理念。RollingUpdate策略指一次僅更新一個Pod
,並且逐個更新,而不是一次性將所有的服務都關閉,避免業務中斷。
原理
- 初始創建Deployment,系統創建了一個ReplicaSet,並按照用戶的需求創建了3個Pod副本;
- 當更新Deployment時,系統創建一個新的ReplicaSet,並將其副本數量擴展到1,然后將舊的ReplicaSet縮減為2;
- 系統繼續按照相同的更新策略對新舊兩個ReplicaSet進行逐個調整。
- 最后,新的ReplicaSet運行了3個新版本的Pod副本,舊的ReplicaSet副本數量則縮減為0。
Deployment回滾
概念
回滾:通過滾動升級的策略可以平滑的升級Deployment,若升級出現問題,需要最快且最好的方式回退到上一次能夠提供正常工作的版本。為此K8S提供了回滾機制。
revision:更新應用時,K8S都會記錄當前的版次,即為revision,當升級出現問題時,可通過回滾到某個特定的revision,默認配置下,K8S只會保留最近的幾個revision,可以通過Deployment配置文件中的spec.revisionHistoryLimit屬性增加revision數量。
更新或回滾:每次更新或回滾時,revision都會自增1,回滾可以看作是一次更新,是一次更新為原版本的操作。
kubectl命令使用
查看修訂版本記錄
$ kubectl rollout history deployment deployment_name
查看某個歷史記錄的詳細信息
$ kubectl rollout history deployment deployment_name --revision=2
其中--revision
表示指定修訂版本;
回滾到上一個版本
$ kubectl rollout undo deployment deployment_name
回滾到指定版本
$ kubectl rollout undo deployment deployment_name --to-revision=2
其中,--to-revision
表示回滾到指定的修訂版本。
API接口使用
POST
/apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/rollback
如:
curl -k -H 'Authorization: Bearer token_xxxx' -H 'Content-Type:application/json' -X POST -d '{
"kind": "DeploymentRollback",
"apiVersion": "extensions/v1beta1",
"name": "deployment_name",
"rollbackTo": {
"revision": 2
}
}' https://localhost:6443/apis/extensions/v1beta1/namespaces/default/deployments/deployment_name/rollback
其中:name和rollbackTo.revision為必須字段,name為資源名稱,rollbackTo.revision為回退的版本,若要回退上一個版本,即為0。
Q&A
什么是聲明式?和其他方式有什么區別?
除了聲明式,我們一般還有指令式,也就是命令式。我們看看這兩者定義和區別。
指令式:
定義
:使用計算機某種語言的指令(命令)來完成程序的運行,比如我們通過編寫shell腳本、python腳本運行程序應用。編寫
:編寫復雜,強依賴開發人員的經驗,需要考慮目標環境以及流程細節,處理各種異常情況和邊緣情況等。事務性
:較難保持事務性,強依賴腳本流程,若腳本在執行過程中出現異常,程序應用會處於一個中間狀態,所以多次運行,可能會達到不同的狀態和結果。維護性
:開發后,需要有對應的運維文檔來協助運維人員維護同一個腳本,不便於維護。
聲明式:
定義
:使用配置文件直接描述最終狀態,比如k8s中的yaml文件,描述最終要啟動多少副本,要多少cpu之類的狀態和結果。編寫
:易於編寫,只要會寫配置文件,告訴應用達到什么樣的結果和狀態即可,不需要考慮流程和目標環境的細節,事務性
:天然的事務性,要么執行成功,要么失敗,不會出現多種中間狀態,重復執行保持一致的狀態和結果。維護性
:配置文件中直接描述了最終狀態和結果,無需過多的運維文檔來描述信息。
參考
《Kubernetes in Action》
《Kubernetes權威指南》
k8s官網