iT邦幫忙

2022 iThome 鐵人賽

DAY 14
2
DevOps

從異世界歸來發現只剩自己不會 Kubernetes系列 第 14

從異世界歸來的第十四天 - Kubernetes Deployment Strategies - Blue/Green Deployment 藍綠部署 (三)

  • 分享至 

  • xImage
  •  

概述

昨天介紹完了 Deployment 兩種最基本的部署策略後,我們接下將要以其為基礎實現的相對進階的部署觀念,在 Kubernetes 中指揮調度各種服務是非常容易,這裡也再次呼應只要實現了該策略的精隨就可以算是實現了該策略,並沒有侷限於特定作法,所以在 Kubernetes 中我們可以使用像是 Service 或是 Ingress 等可以管理外部訪問或進行負載均衡的資源對象實作部署策略,今天就讓我們簡單的使用 Service 來玩玩最簡單的藍綠部署吧。

藍綠部署策略(Blue / Green Deployment)

藍綠部署是最常見的一種 Zero Downtime 部署的方式,是相對簡單穩定且不會有多版本同時存在線上的問題,需要注意的是會有一段系統承受兩倍的資源負載的時間,如果資源不吃緊的話的確是值得使用該策略以換取穩定性與時間成本。

以下為藍綠部署新舊版本更新過程中接收流量的示意圖:

https://ithelp.ithome.com.tw/upload/images/20220914/201495624BMRN8KDEf.png

使用藍綠部署策略更新服務

Kubernetes 中,我們可以用 ServiceIngress 來實現該策略,而以下使用的 Service 操作關鍵都在於使用 label 標籤去控制流量指向。

大致實現方法可以簡單分為以下步驟:

  1. 啟動一個原有的 v1 版本服務並且用 Servicelabel selector 指向該 v1 版本服務管理對外端口。
  2. 啟動並且等待我們的 v2 版本完全就緒,此時新舊兩個版本處於同時存在的狀態。
  3. Servicelabel selectorv1 版本指向到 v2 版本。
  4. 確保終止了舊的 v1 版本。

大致了解後就馬上來實現吧!

實戰練習

# app-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: foo-deployment
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: v1
  template:
    metadata:
      labels:
        app: my-app
        version: v1
    spec:
      containers:
        - name: foo
          image: mikehsu0618/foo
          ports:
            - containerPort: 8080
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: blue-green-service
spec:
  selector:
    app: my-app
    version: v1
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

這裡可以注意到我們將 blue-green-servicelabel selectorv1 版本互相綁定,使得其可以當作我們對外流量的唯一管理者。

  1. 首先把我們的 v1 版本及 service 都運行起來:
kubectl apply -f app-v1.yaml -f service.yaml
----------
deployment.apps/foo-deployment created
service/blue-green-service created

檢查運行狀態:

kubectl get all
-------
NAME                                  READY   STATUS    RESTARTS   AGE
pod/foo-deployment-68df868866-c99w6   1/1     Running   0          31s
pod/foo-deployment-68df868866-frgkt   1/1     Running   0          31s
pod/foo-deployment-68df868866-npskk   1/1     Running   0          31s

NAME                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/blue-green-service   LoadBalancer   10.100.116.42   localhost     8080:30138/TCP   20h
service/kubernetes           ClusterIP      10.96.0.1       <none>        443/TCP          30d

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/foo-deployment   3/3     3            3           31s

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/foo-deployment-68df868866   3         3         3       31s

實際請求 foo 容器所開放的 API 來確認是是否為 v1 版本 :

curl localhost:8080
--------
{"data":"Hello foo"}%

非常的順利,一切如我們所視 v1 版本服務已經順利開啟且被 blue-green-service 管理外部端口。

  1. 接下來預先把要更新的 v2 版本也完整啟動起來:
# app-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar-deployment
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: v2
  template:
    metadata:
      labels:
        app: my-app
        version: v2
    spec:
      containers:
        - name: bar
          image: mikehsu0618/bar
          ports:
            - containerPort: 8080

預先建立 v2 版本服務:

kubectl apply -f app-v2.yaml
--------
deployment.apps/bar-deployment created

這時再次查看所有服務運作情況:

kubectl get all
---------
NAME                                  READY   STATUS    RESTARTS   AGE
pod/bar-deployment-7bbbff5c97-9nq6w   1/1     Running   0          16s
pod/bar-deployment-7bbbff5c97-jp6t2   1/1     Running   0          16s
pod/bar-deployment-7bbbff5c97-qdzl6   1/1     Running   0          16s
pod/foo-deployment-68df868866-c99w6   1/1     Running   0          2m34s
pod/foo-deployment-68df868866-frgkt   1/1     Running   0          2m34s
pod/foo-deployment-68df868866-npskk   1/1     Running   0          2m34s

NAME                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/blue-green-service   LoadBalancer   10.100.116.42   localhost     8080:30138/TCP   20h
service/kubernetes           ClusterIP      10.96.0.1       <none>        443/TCP          30d

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/bar-deployment   3/3     3            3           16s
deployment.apps/foo-deployment   3/3     3            3           2m34s

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/bar-deployment-7bbbff5c97   3         3         3       16s
replicaset.apps/foo-deployment-68df868866   3         3         3       2m34s

沒錯, v1 版本以及 v2 版本都已經如我們預期中的同時存在於環境之中。

再打幾次 API 確認環境中依然只開放 v1 版本對外:

curl localhost:8080
{"data":"Hello foo"}% 
--------                                                                                                                                   
curl localhost:8080
{"data":"Hello foo"}%
--------                                                                                                                                                                                                                                                                       
curl localhost:8080
{"data":"Hello foo"}%    
  1. 接下來把 servicespec.selector 指向我們的 v2 版本:
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: blue-green-service
spec:
  selector:
    app: my-app
    version: v2  // 將 version 從 v1 更新成 v2
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

再次執行更新過的 service 設定檔並且查看詳細資訊

kubectl apply -f service.yaml
--------
service/blue-green-service configured

kubectl describe service blue-green-service
------
Name:                     blue-green-servicee
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=my-app,version=v2
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.100.116.42
IPs:                      10.100.116.42
LoadBalancer Ingress:     localhost
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  30138/TCP
Endpoints:                10.1.0.136:8080,10.1.0.137:8080,10.1.0.138:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

成功將 selector 更新成 v2 版本~

現在我們可以預期線上環境中只有 v2 版本的 bar 容器在運行,所以我們將再次發送 API 確認:

curl localhost:8080
{"data":"Hello bar"}%
curl localhost:8080
{"data":"Hello bar"}%
curl localhost:8080
{"data":"Hello bar"}%

到這裡 v2 版本已經確定成功上線囉~

  1. 關閉舊的 v1 版本 :
kubectl delete -f app-v1.yaml
--------
deployment.apps "foo-deployment" deleted

接下來查看一下線上環境的運作情形:

kubectl get all
--------
NAME                                  READY   STATUS    RESTARTS   AGE
pod/bar-deployment-7bbbff5c97-9nq6w   1/1     Running   0          92m
pod/bar-deployment-7bbbff5c97-jp6t2   1/1     Running   0          92m
pod/bar-deployment-7bbbff5c97-qdzl6   1/1     Running   0          92m

NAME                         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/blue-green-service   LoadBalancer   10.100.116.42   localhost     8080:30138/TCP   21h
service/kubernetes           ClusterIP      10.96.0.1       <none>        443/TCP          30d

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/bar-deployment   3/3     3            3           92m

NAME                                        DESIRED   CURRENT   READY   AGE
replicaset.apps/bar-deployment-7bbbff5c97   3         3         3       92m

成功的將舊的 v1 版本資源都刪除了,到此我們也完成了一次簡單的藍綠部署。

結論

終於我們又利用了進階部署策略再一次拯救了我們的線上環境,感謝各位的努力,由上面的簡單範例中我們可以再次印證,只要有心我們可以用各種方法各種工具來實現各種高大尚的技術,最重要的是我們需要將它的觀念內化為自己的語言做到隨心所欲不逾舉的地步。我知道那是你的夢想,也是我的夢想。


狂賀₍₍ ◝( ゚∀ ゚ )◟ ⁾⁾♪

千呼萬喚始出來!鐵人賽系列「從異世界歸來發現只剩自己不會 Kubernetes」同名改編作品出版了!
感謝所有交流指教的各路英雄,也感謝願意點閱文章的各位,如果能幫助到任何人都將會是我的榮幸。

本書內容改編自第 14 屆 iThome 鐵人賽 DevOps 組的優選系列文章《從異世界歸來發現只剩自己不會 Kubernetes》。此書是一本綜合性的指南,針對想要探索認識 Kubernetes 的技術人員而生。無論是初涉此領域的新手,還是已有深厚經驗的資深工程師,本書都能提供你所需的知識和技能。

「這本書不僅提供了豐富的範例程式碼和操作指南,讓身為工程師的我們能實際操作來加深認知;更重要的是,它教會我如何從後端工程師的角度去思考和應用 Kubernetes。從容器的生命週期、資源管理到部署管理,每一章都與我們的日常開發工作息息相關。」
──── 雷N │ 後端工程師 / iThome 鐵人賽戰友

天瓏連結: 從異世界歸來發現只剩自己不會 Kubernetes:初心者進入雲端世界的實戰攻略!
https://ithelp.ithome.com.tw/upload/images/20231030/201495629BWPC1wajW.png


相關文章:

相關程式碼同時收錄在:

https://github.com/MikeHsu0618/2022-ithelp/tree/master/Day14


上一篇
從異世界歸來的第十三天 - Kubernetes Deployment Strategies - Rolling Update & Recreate (二)
下一篇
從異世界歸來的第十五天 - Kubernetes Deployment Strategies - Canary Deployment 金絲雀部署 (四)
系列文
從異世界歸來發現只剩自己不會 Kubernetes30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
fatmylin
iT邦新手 5 級 ‧ 2022-10-06 16:28:48

Hi 版大,
我發現了一個小問題, 在 app-v2.yaml 可能要把 appbar 改成 my-app
還要把 version 改成 v2.

# app-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bar-deployment
  labels:
    app: my-app # bar -> my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app # bar -> my-app
      version: v2 # v1 -> v2
  template:
    metadata:
      labels:
        app: my-app # bar -> my-app
        version: v2 # v1 -> v2
    spec:
      containers:
        - name: bar
          image: mikehsu0618/bar
          ports:
            - containerPort: 8080

如此才能透過更改 service.yamlversion=v2 去做 blue green deployment 不然 service 好像沒辦法順利指到
https://ithelp.ithome.com.tw/upload/images/20221006/20153500L9RfM77Xmm.png

已更正~趕稿疏忽了感謝~
github 的是正確版但沒有複製正確
但很高興能看到你獨自找到解答的回覆/images/emoticon/emoticon02.gif

我要留言

立即登入留言