1 滾動更新的定義和目標
滾動更新的含義
一次只更新一小部分副本,成功后,再更新更多的副本,最終完成所有副本的更新。
滾動更新的好處
最大好處是零停機,整個更新過程始終有副本在運行,從而保證了業務的連續性。
根據 yaml 創建資源, apply 可以重復執行,create 不行
kubectl create -f deploy.yml
kubectl apply -f deploy.yml --record
注意 當deploy.yml 是上次發布的內容沒有更改時,使用kubectl apply無法進行更新發布。比如鏡像使用的是latest標簽時。
我們在發布deployment時,如果使用了如下的發布方式 或者 參數配置不正確時,會發現 服務會掛掉一會兒,用戶會訪問不了。
kubectl delete --ignore-not-found=true -f deploy.yml kubectl create -f deploy.yml
原因是
pod被刪除或者 容器啟動后,到服務真正工作起來,中間會有一段時間無法正常訪問,但 k8s 卻認為服務是正常就緒狀態。
本篇文章主要解決這個問題,實現 平滑的發布,發布更新服務過程中保證服務一直可用,用戶零感知。
2 設置滾動更新
2.1 服務准備
我們有一個api服務deploy.yaml如下:
apiVersion: apps/v1 kind: Deployment metadata: name: familytree-api namespace: default spec: selector: matchLabels: app: familytree-api replicas: 3 template: metadata: labels: app: familytree-api spec: containers: - name: familytree-api image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:1.0.0 imagePullPolicy: Always resources: requests: cpu: 1 memory: 1Gi limits: cpu: 4 memory: 4Gi env: - name: VERSION value: 1.0.0 ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: name: familytree-api-service namespace: default spec: selector: app: familytree-api ports: - protocol: TCP port: 8080 targetPort: 8080 --- apiVersion: extensions/v1beta1 kind: Ingress metadata: name: familytree-api-ingress namespace: default annotations: kubernetes.io/ingress.class: traefik traefik.frontend.rule.type: PathPrefix spec: rules: - host: api.test.com http: paths: - path: /api/nowater backend: serviceName: familytree-api-service servicePort: 8080 ---
服務中包含url路由接口可返回版本號和當前hostname
訪問路由
app.router.add_get('/api/nowater/version', service.version_print)
實現代碼如下:
async def version_print(request): version = config["version"] hostname = socket.gethostname() try: print("打印版本 "+version+" hostname " + hostname) return web.json_response({'version': version, "hostname": hostname}) except Exception as e: return web.json_response({'msg': e.value}, status=500)
使用命令發布服務
kubectl create -f deploy.yml
查看部署列表
kubectl get deployments | grep familytree-api
查看正在運行的pod
kubectl get pods | grep familytree-api
查看正在運行的pod使用的鏡像
kubectl get deployment -o wide | grep familytree-api
輸出如下:
[zzq@host3 ~]$ kubectl get deployment -o wide | grep familytree-api familytree-api 3 3 3 0 4m familytree-api 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:1.0.0 app=familytree-api
通過pod描述,查看服務的當前映像版本
kubectl describe pods familytree-api-7c6fd4bb75-5qtr5
訪問服務url
[zzq@host3 ~]$ curl http://api.test.com/api/nowater/version {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"}
2.2 進行滾動升級
方式一 將yaml中的鏡像版本修改為升級版本–推薦
image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0
環境變量也修改為2.0.0
env: - name: VERSION value: 2.0.0
然后使用apply命令重新發布服務
kubectl apply -f deploy.yml --record
記得一定需要帶有 --record,否則沒有版本的信息記錄,不利於回滾定位。
方式二 使用命令
kubectl set image deployments/familytree-api familytree-api=123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0
2.3 查看是否升級成功
查看狀態:
kubectl rollout status deployment/familytree-api Waiting for rollout to finish: 1 out of 3 new replicas have been updated.. deployment "familytree-api" successfully rolled out
暫停升級
kubectl rollout pause deployment <deployment>
繼續升級
kubectl rollout resume deployment <deployment>
升級結束后,繼續查看rs的狀態:
kubectl get rs
根據AGE我們可以看到離我們最近的當前狀態是:3,和我們的yaml文件是一致的,證明升級成功了。用describe命令可以查看升級的全部信息:
kubectl describe deployment familytree-api
輸出為
[zzq@host3 ~]$ kubectl describe deployment familytree-api Name: familytree-api Namespace: default CreationTimestamp: Mon, 23 Sep 2019 18:12:43 +0800 Labels: <none> Annotations: deployment.kubernetes.io/revision=2 kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"kubernetes.io/change-cause":"kubectl apply --filename=./deploy/deploy-prod.yml ... kubernetes.io/change-cause=kubectl apply --filename=./deploy/deploy-prod.yml --record=true Selector: app=familytree-api Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=familytree-api Containers: familytree-api: Image: 123.dkr.ecr.cn-sourthwest-1.amazonaws.com.cn/module/familytree-api-module:2.0.0 Port: 8080/TCP Host Port: 0/TCP Limits: cpu: 4 memory: 4Gi Requests: cpu: 1 memory: 1Gi Environment: VERSION: 2.0.0 Mounts: <none> Volumes: <none> Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: <none> NewReplicaSet: familytree-api-c6fbb4499 (3/3 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 20m deployment-controller Scaled up replica set familytree-api-66f79b747c to 3 Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set familytree-api-c6fbb4499 to 1 Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set familytree-api-66f79b747c to 2 Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set familytree-api-c6fbb4499 to 2 Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set familytree-api-66f79b747c to 1 Normal ScalingReplicaSet 3m deployment-controller Scaled up replica set familytree-api-c6fbb4499 to 3 Normal ScalingReplicaSet 3m deployment-controller Scaled down replica set familytree-api-66f79b747c to 0
訪問服務url
[zzq@host3 ~]$ curl http://api.test.com/api/nowater/version {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"}
3 設置服務存活探針和服務健康檢查探針以及相應參數
使用上面的發布步驟並不能保證 服務完全平滑。
因為k8s不能判斷 一個的服務是否已經可用,只要pod正常啟動就會判斷成 可用。
但是pod啟動后並不代表服務可用,比如java的程序 可能還需要啟動spring boot框架,去連接數據庫等待。
這樣就會導致 短暫的 服務不可用。
3.1 服務不可用的示例
比如我們一直訪問准備好的version版本查詢接口如下:
while :; do curl http://api.test.com/api/nowater/version; sleep 1; done
然后進行版本更新發布
kubectl apply -f deploy.yml --record
輸出如下:
[zzq@host3 ~]$ while :; do curl http://api.test.com/api/nowater/version; sleep 1; done ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused curl: (7) Failed to connect to http://api.test.com/api/nowater/version: Connection refused ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ----------
我們可以發現鏡像版本已經更新到2.0.0
我們可以在2.0.0鏡像中加入延遲啟動服務,也就是說,會先sleep 20s,然后才去啟動app服務。
這就模擬了在服務啟動過程中,雖然pod已經是存在的狀態,但是並沒有真正提供服務。
可以看到,由於延遲啟動,api並沒有真正做好准備提供服務,此時流量已經發到后端,導致服務不可用的狀態
3.2 解決方案–探針檢測
在實際生產環境中會遇到這樣那樣的問題,比如:容器里面應用掛了或者說新啟動的容器里面應用還沒有就緒等等,所以說就需要進行探測來檢驗容器是否滿足需求。
那么一般的檢測分為幾種,比如:進程檢測、業務檢測。
進程檢測呢很好理解,也就是說通過檢測容器進程來驗證容器內應用是否存活。
Kubelet會定期通過Docker Daemon獲取所有Docker進程的運行情況,如果發現某個Docker容器未正常運行,則重新啟動該容器進程。目前,進程級的健康檢查都是默認啟用的。
業務檢測呢也好理解,有些人會問,有了進程檢測不就挺好的么,為什么要進行業務檢測?
因為在很多實際場景下,僅僅使用進程級健康檢查還遠遠不夠。有時,從Docker的角度來看,容器進程依舊在運行;但是如果從應用程序的角度來看,假設應用代碼處於死鎖狀態的話,那每次調度到這個容器的時候永遠都無法正常響應用戶的業務。比如對於使用java web服務的應用來說,並不是簡單地說tomcat啟動成功就可以對外提供服務的,還需要等待spring容器初始化,數據庫連接連接上等等。
為了解決以上問題,Kubernetes引人了一個在容器內執行的活性探針(liveness probe)的概念,以支持用戶自己實現應用業務級的健康檢查。這些檢查項由Kubelet代為執行,以確保用戶的應用程序正確運轉,至於什么樣的狀態才算“正確”,則由用戶自己定義。
Kubernetes支持3種類型的應用健康檢查動作,分別為HTTP Get、Container Exec和TCP Socket。exec的方式比較通用的,因為不是每個服務都有http服務,但每個服務都可以在自己內部定義健康檢查的job,定期執行,然后將檢查結果保存到一個特定的文件中,外部探針就不斷的查看這個健康文件就OK了。
介紹完存活性探針(liveness probe)之后我們來看看就緒探針(readiness probe),就緒探針是來確定容器是否已經就緒可以接受訪問,只有當Pod中的容器都處於就緒狀態時kubelet才會認定該Pod處於就緒狀態,至於什么樣的狀態才算 ”就緒”,還是由用戶自己定義。該狀態的作用就是控制哪些Pod可以作為service的后端,如果Pod處於非就緒狀態,那么它們將會被從service的load balancer中移除,防止 流量分發到 異常的pod中。
4 存活性探針(liveness probe)和就緒探針(readiness probe)的區別
readinessProbe檢查成功與否,決定這個pod是否會被加入到Service的load balancer列表中,即是否給它分配訪問的流量,並不影響Pod本身的生命周期
如果容器中的進程能夠在遇到問題或不健康的情況下自行崩潰,則不一定需要存活探針; kubelet 將根據Pod的restartPolicy自動執行正確的操作。
如果您希望容器在探測失敗時被殺死並重新啟動,那么請指定一個存活探針,並指定restartPolicy為Always或OnFailure。
如果要僅在探測成功時才開始向 Pod 發送流量,請指定就緒探針。在這種情況下,就緒探針可能與存活探針相同,但是spec中的就緒探針的存在意味着Pod將在沒有接收到任何流量的情況下啟動,並且只有在探針探測成功后才開始接收流量。
兩種探測的配置方法完全一樣,支持的配置參數也一樣,既可單獨探測又可結合者一起執行。
LivenessProbe:用於判斷容器是否存活(running狀態),如果LivenessProbe探針探測到容器不健康,則kubelet殺掉該容器,並根據容器的重啟策略做相應的處理。如果一個容器不包含LivenessProbe探針,則kubelet認為該容器的LivenessProbe探針返回的值永遠是“Success”。
ReadinessProbe:用於判斷容器是否啟動完成(ready狀態),可以接收請求。如果ReadinessProbe探針檢測到失敗,則Pod的狀態被修改。Endpoint Controller將從Service的Endpoint中刪除包含該容器所在Pod的Endpoint。
4.1 存活性探測
livenessProbe:存活性探測,最主要是用來探測pod是否需要重啟–決定把pod刪除重新創建
在spec的containers中增加
與image同級
exec探針:
livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 2 failureThreshold: 3
http探針:
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
tcp探針:
livenessProbe: tcpSocket: port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
參數說明
說法1:
initialDelaySeconds:容器啟動后第一次執行探測是需要等待多少秒。
periodSeconds:執行探測的頻率。默認是10秒,最小1秒。
timeoutSeconds:探測超時時間。默認1秒,最小1秒。
successThreshold:探測失敗后,最少連續探測成功多少次才被認定為成功。默認是1。對於liveness必須是1。最小值是1。
failureThreshold:探測成功后,最少連續探測失敗多少次才被認定為失敗。默認是3。最小值是1。
說法2:
initialDelaySeconds: 表示容器啟動之后延遲多久進行liveness探測
timeoutSeconds:每次執行探測的超時時間
periodSeconds:探測的周期時間
successThreshold:最少連續幾次探測成功的次數,滿足該次數則認為success。
failureThreshold:最少連續幾次探測失敗的次數,滿足該次數則認為fail作
舉例:
initialDelaySeconds: 5 #告訴kubelet在第一次執行probe之前要的等待5秒鍾
periodSeconds: 10 #kubelet要每隔10秒執行一次liveness probe 檢查
timeoutSeconds: 2 #超長時長,默認為1s,最小值也為1s
failureThreshold: 3 #處於成功狀態時,探測操作至少連續多少次的失敗才被視為檢測不通過,默認為3,最小為1
探針檢測命令是在容器中執行 cat /tmp/healthy 命令。
如果命令執行成功,將返回0,kubelet就會認為該容器是活着的並且很健康。如果返回非0值,kubelet就會殺掉這個容器並重啟它。
4.2 就緒性探測
readinessProbe:就緒性探測,用來探測pod是否已經能夠提供服務–決定是否參與分配流量
在spec的containers中增加
與image同級
readinessProbe: tcpSocket: port: 80 initialDelaySeconds: 5 periodSeconds: 10
或者
readinessProbe: httpGet: path: /api/nowater/version port: 8080 httpHeaders: - name : X-Custom-Header value: Awesome initialDelaySeconds: 5 periodSeconds: 10
periodSeconds 規定kubelet要每隔10秒執行一次readinessProbe 檢查。
initialDelaySeconds 告訴kubelet在第一次執行probe之前要的等待5秒鍾。
探針檢測命令是檢查tcp連接 端口80 是否暢通。
也可以檢查某個http 請求是否返回成功碼。
如果返回一個成功的返回碼,kubelet就會認定該容器服務是可用的。
如果返回失敗的返回碼,kubelet將該pod改為not ready,將會被從service的load balancer中移除。
注意:任何大於200小於400的返回碼都會認定是成功的返回碼。其他返回碼都會被認為是失敗的返回碼。
由於設置了readinessProbe,雖然pod已經啟動起來了,但是並不會立即投入使用,會出現了 READY: 0/1 的情況
並且有pod出現了一直持續Terminating狀態,因為滾動更新的限制,至少要保證有pod可用
再查看curl的狀態,image的版本平滑更新到2.0.0,沒有出現報錯的狀況
[zzq@host3 ~]$ while :; do curl http://api.test.com/api/nowater/version; sleep 1; done ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "1.0.0", "hostname": "familytree-api-66f79b747c-rv69s"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ---------- {"version": "2.0.0", "hostname": "familytree-api-c6fbb4499-vcbt7"} ----------
4.3 調整參數設置
在spec下面添加滾動升級策略:
與template同級
minReadySeconds: 5 strategy: # indicate which strategy we want for rolling update type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 1
minReadySeconds:
這個值默認是0,Kubernetes會假設該容器啟動起來后就可以提供服務了,會導致用戶訪問異常
這里需要估一個比較合理的值,從容器啟動到應用正常提供服務
如果沒有設置該值,Kubernetes會假設該容器啟動起來后就提供服務了
如果沒有設置該值,在某些極端情況下可能會造成服務不正常運行
maxSurge:
升級過程中最多可以比原先設置多出的POD數量
例如:maxSurage=1,replicas=5,則表示Kubernetes會先啟動1一個新的Pod后才刪掉一個舊的POD,整個升級過程中最多會有5+1個POD。
maxUnavaible:
升級過程中最多有多少個POD處於無法提供服務的狀態
當maxSurge不為0時,該值也不能為0
例如:maxUnavaible=1,則表示Kubernetes整個升級過程中最多會有1個POD處於無法服務的狀態。
4.4 格式如下
4.5 回滾
查看Deployment的升級歷史:
kubectl rollout history deployment nginx-deploy
查看指定版本的升級歷史
kubectl rollout history deployment nginx-deploy --revision=3
假如現在要直接回退到當前版本的前一個版本:
kubectl rollout undo deployment nginx-deploy deployment "nginx-deploy" rolled back
當然也可以用revision回退到指定的版本:
kubectl rollout undo deployment nginx-deploy --to-revision=2 deployment "nginx-deploy" rolled back
現在可以用命令查看Deployment現在的狀態了。
5 k8s滾動更新的原理
部署(Deployment)自動創建副本集(ReplicaSet),副本集根據參數策略可以精確地控制每次替換的Pod數量,從而可以很好的實現滾動更新。具體來說,k8s每次使用一個新的副本控制器(replication controller)來替換已存在的副本控制器,從而始終使用一個新的Pod模板來替換舊的pod模板。
大致步驟如下:
1、創建一個新的replication controller。
2、增加或減少pod副本數量,直到滿足當前批次期望的數量。
3、刪除舊的replication controller。
5.1 部署概況
使用命令查看部署概況
kubectl get deployment
上圖包含的幾個滾動發布過程標量,說明如下:
DESIRED 最終期望處於READY狀態的副本數
CURRENT 當前的副本總數
UP-TO-DATE 當前完成更新的副本數
AVAILABLE 當前可用的副本數
5.2 部署詳情
使用命令查看部署詳情
kubectl describe deployment familytree-api
從上圖可以看到,k8s精確地控制着整個發布過程,滾動進行,直到所有副本全部更新。其實,k8s提供了兩個參數maxSurge和maxUnavailable來精確地控制每次滾動的pod數量,如下:
maxSurge 滾動更新過程中運行操作期望副本數的最大pod數,可以為絕對數值(eg:5),但不能為0;也可以為百分數(eg:10%)。默認為25%。
maxUnavailable 滾動更新過程中不可用的最大pod數,可以為絕對數值(eg:5),但不能為0;也可以為百分數(eg:10%)。默認為25%。
如果未指定這兩個可選參數,則k8s使用默認配置,如下:
kubectl get deployment familytree-api -o yaml
剖析部署helloworldapi的標准輸出:
當前的副本總數 = 3 + 3 * 25% = 4,所以CURRENT為4。
當前可用的副本數 = 3 - 3 * 25% = 2,所以AVAILABLE為2。
整個滾動過程是通過控制兩個副本集來完成的,新的副本集:familytree-api-c6fbb4499;舊的副本集: familytree-api-66f79b747c 。
理想狀態下的滾動過程:
創建了一個新的副本集,並為其分配1個新版本的pod,使副本總數達到4,一切正常。
通知舊副本集,銷毀1個舊版本的pod,使可用副本總數保持到2,一起正常。
當1個副本銷毀成功后,通知新副本集,再新增1個新版本的pod,使副本總數達到4,一切正常。
只要銷毀成功,新副本集,就會創造新的pod,一直循環,直到舊的副本集pod數量為0。
有時整個滾動過程也是不理想的,不符合上述的規律,會有一些混亂。
但
k8s最終都會使服務全部更新到期望狀態,始終保持最大的副本總數和可用副本總數的不變性
6 deployment的常用命令和參數說明
查看部署狀態
kubectl rollout status deployment/review-demo --namespace=scm
kubectl describe deployment/review-demo --namespace=scm
或者這種寫法
kubectl rollout status deployments review-demo --namespace=scm
kubectl describe deployments review-demo --namespace=scm
升級
kubectl set image deployment/review-demo review-demo=library/review-demo:0.0.1 --namespace=scm
或者
kubectl edit deployment/review-demo --namespace=scm
編輯.spec.template.spec.containers[0].image的值
終止升級
kubectl rollout pause deployment/review-demo --namespace=scm
繼續升級
kubectl rollout resume deployment/review-demo --namespace=scm
回滾
kubectl rollout undo deployment/review-demo --namespace=scm
查看deployments版本
kubectl rollout history deployments --namespace=scm
回滾到指定版本
kubectl rollout undo deployment/review-demo --to-revision=2 --namespace=scm
升級歷史
kubectl describe deployment/review-demo --namespace=scm Name: review-demo Namespace: scm CreationTimestamp: Tue, 31 Jan 2017 16:42:01 +0800 Labels: app=review-demo Selector: app=review-demo Replicas: 3 updated | 3 total | 3 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 1 max unavailable, 1 max surge OldReplicaSets: <none> NewReplicaSet: review-demo-2741031620 (3/3 replicas created) Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 1 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 2 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 2 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 1 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set review-demo-2741031620 to 3 1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set review-demo-1914295649 to 0
deployment文件
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: review-demo namespace: scm labels: app: review-demo spec: replicas: 3 # minReadySeconds: 60 #滾動升級時60s后認為該pod就緒 strategy: rollingUpdate: ##由於replicas為3,則整個升級,pod個數在2-4個之間 maxSurge: 1 #滾動升級時會先啟動1個pod maxUnavailable: 1 #滾動升級時允許的最大Unavailable的pod個數 template: metadata: labels: app: review-demo spec: terminationGracePeriodSeconds: 60 ##k8s將會給應用發送SIGTERM信號,可以用來正確、優雅地關閉應用,默認為30秒 containers: - name: review-demo image: library/review-demo:0.0.1-SNAPSHOT imagePullPolicy: IfNotPresent livenessProbe: #kubernetes認為該pod是存活的,不存活則需要重啟 httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 60 ## equals to the maximum startup time of the application + couple of seconds timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 readinessProbe: #kubernetes認為該pod是啟動成功的 httpGet: path: /health port: 8080 scheme: HTTP initialDelaySeconds: 30 ## equals to minimum startup time of the application timeoutSeconds: 5 successThreshold: 1 failureThreshold: 5 resources: # keep request = limit to keep this container in guaranteed class requests: cpu: 50m memory: 200Mi limits: cpu: 500m memory: 500Mi env: - name: PROFILE value: "test" ports: - name: http containerPort: 8080
幾個重要參數說明
maxSurge與maxUnavailable
maxSurge: 1 表示滾動升級時會先啟動1個pod
maxUnavailable: 1 表示滾動升級時允許的最大Unavailable的pod個數
由於replicas為3,則整個升級,pod個數在2-4個之間
terminationGracePeriodSeconds
k8s將會給應用發送SIGTERM信號,可以用來正確、優雅地關閉應用,默認為30秒。
如果需要更優雅地關閉,則可以使用k8s提供的pre-stop lifecycle hook 的配置聲明,將會在發送SIGTERM之前執行。
livenessProbe與readinessProbe
livenessProbe是kubernetes認為該pod是存活的,不存在則需要kill掉,然后再新啟動一個,以達到replicas指定的個數。
readinessProbe是kubernetes認為該pod是啟動成功的,這里根據每個應用的特性,自己去判斷,可以執行command,也可以進行httpGet。比如對於使用java web服務的應用來說,並不是簡單地說tomcat啟動成功就可以對外提供服務的,還需要等待spring容器初始化,數據庫連接連接上等等。對於spring boot應用,默認的actuator帶有/health接口,可以用來進行啟動成功的判斷。
其中readinessProbe.initialDelaySeconds可以設置為系統完全啟動起來所需的最少時間,livenessProbe.initialDelaySeconds可以設置為系統完全啟動起來所需的最大時間+若干秒。
這幾個參數配置好了之后,基本就可以實現近乎無縫地平滑升級了。對於使用服務發現的應用來說,readinessProbe可以去執行命令,去查看是否在服務發現里頭應該注冊成功了,才算成功。
參考:
原文鏈接:https://blog.csdn.net/zzq900503/article/details/101221899