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 就完成了喔。
完全超越以往的維運水準