9 months ago

Blue/Green Deployments 也是不用停機,升級過程中用戶無感。

跟滾動部屬最大的差別就是滾動式逐一將 Service 替換成新的版本。
藍綠部屬是準備好另外一個完整的系統,在前端 Service 或是附載平衡那段做一個流量切換的動作。

示意圖大概如下
1.準備一個完整的服務,這個也可以提供測試做一個線上測試

2.當測試完成後以 Kubernetes 來說,只要修改 Service.yaml 檔,去 apply 變更就可以達成了

這中間不會讓服務斷掉,基本上用戶是無感的,
切換也只是毫秒的時間即可完成。

雖說不是什麼新的部屬方式,但方便性跟簡易性大大提升。
想想你以前為了要不斷線要做多少準備個設定工作 nginx 各服務IP port

下面說明一下操作過程 指令忘了就從這邊找http://samchu.logdown.com/posts/2462697-learn-how-to-use-kubernetes-deployment-to-rolling-update-in-thirty-second

先來看一下我們佈署的資訊

[root@master1 ~]# kubectl get deployment 
NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
test-rest-deployment   2         2         2            2           3d

[root@master1 ~]# kubectl describe deployment test-rest-deployment
Name:           test-rest-deployment
Namespace:      default
CreationTimestamp:  Fri, 15 Sep 2017 14:19:58 +0800
Labels:         app=test-rest
Annotations:        deployment.kubernetes.io/revision=2
            kubernetes.io/change-cause=kubectl replace --filename=test-rest.yaml --record=true
Selector:        app=test-rest
Replicas:       2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType:       RollingUpdate
MinReadySeconds:    30
RollingUpdateStrategy:  1 max unavailable, 1 max surge
Pod Template:
  Labels:   app=test-rest
  Containers:
   test-rest:
    Image:  spike234/test-rest:0.1.8
    Port:   8080/TCP
    Requests:
      cpu:      100m
    Environment:    <none>
    Mounts:     <none>
  Volumes:      <none>
Conditions:
  Type      Status  Reason
  ----      ------  ------
  Available     True    MinimumReplicasAvailable
OldReplicaSets: <none>
NewReplicaSet:  test-rest-deployment-1587270817 (2/2 replicas created)
Events:     <none>

我們的 Labels 只有 app=test-rest ,並沒有包含版本資訊,在綁定上 會比較難操作
(Labels 在找服務時非常好用,這點講師有特別講過,盡量使用 Labels 來定義服務)

我們把舊的先都刪掉

[root@master1 ~]# kubectl get service
NAME         CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   10.233.0.1      <none>        443/TCP          3d
test-rest    10.233.15.134   <nodes>       8080:30080/TCP   3d

[root@master1 ~]# kubectl delete service test-rest
service "test-rest" deleted

[root@master1 ~]# kubectl get pods
NAME                                    READY     STATUS    RESTARTS   AGE
test-rest-deployment-1587270817-7d2vl   1/1       Running   2          2d
test-rest-deployment-1587270817-lg104   1/1       Running   2          2d

[root@master1 ~]# kubectl get deployment
NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
test-rest-deployment   2         2         2            2           3d

[root@master1 ~]# kubectl delete deployment test-rest-deployment
deployment "test-rest-deployment" deleted

[root@master1 ~]# kubectl get pods
No resources found.

再把版本標記打上 yaml 中,重新佈版

[root@master1 ~]# cat << EOF > blue.yaml
> apiVersion: extensions/v1beta1
> kind: Deployment
> metadata:
>   name: test-blue-deployment
> spec:
>   replicas: 2
>   template:
>     metadata:
>       labels:
>         app: test-rest
>         version: "1.0"
>     spec:
>       containers:
>       - name: test-rest
>         image: spike234/test-rest:0.1.8
>         ports:
>         - containerPort: 8080
>         resources:
>           requests:
>             cpu: 100m
> EOF

[root@master1 ~]# kubectl apply -f blue.yaml
deployment "test-blue-deployment" created

[root@master1 ~]# kubectl get pods
NAME                                    READY     STATUS    RESTARTS   AGE
test-blue-deployment-1958241402-2x42v   1/1       Running   0          1m
test-blue-deployment-1958241402-6q7l5   1/1       Running   0          1m

發佈服務

[root@master1 ~]# cat << EOF > service.yaml
> apiVersion: v1
> kind: Service
> metadata:
>   name: test-rest
>   labels:
>     app: test-rest
> spec:
>   type: NodePort
>   selector:
>     app: test-rest
>     version: "1.0"
>   ports:
>   - port: 8080
>     targetPort: 8080
>     nodePort: 30080
> EOF

[root@master1 ~]# kubectl apply -f service.yaml
service "test-rest" created

測試一下我們服務跟版本都正確執行

[root@master1 ~]# curl "http://192.168.31.147:30080/api/v1/test"
{"rc":"1","version":"1.0"}

再來修改我們的程式 version = 1.1 push 之後等 circleci 幫我們打包成 Docker 後來發布新版的程式

[root@master1 ~]# cat << EOF > green.yaml
> apiVersion: extensions/v1beta1
> kind: Deployment
> metadata:
>   name: test-green-deployment
> spec:
>   replicas: 2
>   template:
>     metadata:
>       labels:
>         app: test-rest
>         version: "1.1"
>     spec:
>       containers:
>       - name: test-rest
>         image: spike234/test-rest:0.1.9
>         ports:
>         - containerPort: 8080
>         resources:
>           requests:
>             cpu: 100m
> EOF

[root@master1 ~]# kubectl apply -f green.yaml
deployment "test-green-deployment" created

佈署完後觀察一下 Deployment 跟 Pod ,然後我們的程式版本還是在 1.0

[root@master1 ~]# kubectl get deployment 
NAME                    DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
test-blue-deployment    2         2         2            2           17m
test-green-deployment   2         2         2            2           1m

[root@master1 ~]# kubectl get pods
NAME                                     READY     STATUS    RESTARTS   AGE
test-blue-deployment-1958241402-2x42v    1/1       Running   0          17m
test-blue-deployment-1958241402-6q7l5    1/1       Running   0          17m
test-green-deployment-4242213378-69q2j   1/1       Running   0          1m
test-green-deployment-4242213378-9f0jl   1/1       Running   0          1m

[root@master1 ~]# curl "http://192.168.31.147:30080/api/v1/test"
{"rc":"1","version":"1.0"}

這個時候如果測試有需要可以開個不同 port 的 Service 來讓測試人員在線上做測試,測完後再把測試用的 Service 砍掉就好了。

接下來我們要幫 Service 更換後端服務成 version: "1.1" 的版本也就是這個 Switch 動作啦,同時也會一直測試 api 是否一直可以正常提供服務並同時更新。

[root@master1 ~]# cat << EOF > service.yaml
> apiVersion: v1
> kind: Service
> metadata:
>   name: test-rest
>   labels:
>     app: test-rest
> spec:
>   type: NodePort
>   selector:
>     app: test-rest
>     version: "1.1"
>   ports:
>   - port: 8080
>     targetPort: 8080
>     nodePort: 30080
> EOF

[root@master1 ~]# kubectl apply -f service.yaml
service "test-rest" configured

測試結果

比滾動部屬來要簡單,也不會有 API 版本同時存在問題

更爽的是幾行指令,改改 yaml 就可以達成了,佈署錯了,也別忘了退版也是改改 yaml 就完成了喔。

完全超越以往的維運水準

Reference:
Blue/Green Deployments on Kubernetes - Ian Lewis

← Learn how to use Kubernetes Deployment to rolling update in thirty second Kubernetes Horizontal Pod Autoscaling →
 
comments powered by Disqus