Kubernetes--k8s---滾動更新--零停機不停服發布服務


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM