概述
如何在騰訊雲 Kubernetes 集羣實現藍綠髮布和灰度發佈?一般要向集羣額外部署其它開源工具來實現,好比 Nginx Ingress,Traefik 等,或者讓業務上 Service Mesh(服務網格),利用服務網格的能力來實現。這些方案多多少少都是須要一點點門檻的,若是藍綠髮布或灰度發佈的需求不復雜,同時不但願讓集羣引入更多的組件或複雜的用法,能夠考慮使用本文的簡單方案,利用 Kubernetes 原生的特性以及騰訊雲 TKE/EKS 集羣自帶的 LB 插件實現簡單的藍綠髮布和灰度發佈。nginx
注: 本文適用產品範圍: TKE 集羣、EKS 集羣 (彈性集羣)後端
原理介紹
咱們一般使用 Deployment、StatefulSet 等 Kubernetes 自帶的工做負載來部署業務,每一個工做負載都管理一組 Pod,以 Deployment 爲例:centos
一般還會爲每一個工做負載建立對應的 Service,Service 經過 selector 來匹配後端 Pod,其它服務或者外部經過訪問 Service 便可訪問到後端 Pod 提供的服務。要對外暴露能夠直接將 Service 類型設置爲 LoadBalancer,LB 插件會自動爲其建立 CLB (騰訊雲負載均衡器) 做爲流量入口。api
如何實現藍綠髮布?以 Deployment 爲例,集羣中部署兩個不一樣版本的 Deployment,它們的 Pod 擁有共同的 label,但有一個 label 的值不一樣,用於區分不一樣的版本,Service 使用 selector 選中了其中一個版本的 Deployment 的 Pod,經過修改 Service 的 selector 中決定 服務版本的 label 的值來改變 Service 後端對應的 Deployment,實現讓服務從一個版本直接切換到另外一個版本,即藍綠髮布:app
如何實現灰度發佈?雖然咱們一般會爲每一個工做負載都建立一個 Service,但 Kubernetes 並無限制 Service 必定要與工做負載一一對應,由於 Service 是經過 selector 來匹配後端 Pod 的,只要不一樣工做負載的 Pod 都能被相同 selector 選中,就能夠實現一個 Service 對應多個版本的工做負載的效果,調整不一樣版本工做負載的副本數就至關於調整不一樣版本服務的權重,實現灰度發佈:負載均衡
使用 YAML 建立資源
本文的示例將使用 yaml 的方式部署工做負載和建立 Service,有兩種操做方式。curl
方式一:在 TKE 或 EKS 控制檯右上角點擊 YAML 建立資源
,而後將本文示例的 yaml 粘貼進去:工具
方式二:將示例的 yaml 保存成文件,而後使用 kubectl 指定 yaml 文件來建立,如: kubectl apply -f xx.yaml
。測試
部署多版本工做負載
要實現藍綠髮布或灰度發佈,首先咱們須要在集羣中部署多個版本的工做負載,這裏以簡單的 nginx 爲例,部署第一個版本:lua
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-v1 spec: replicas: 3 selector: matchLabels: app: nginx version: v1 template: metadata: labels: app: nginx version: v1 spec: containers: - name: nginx image: "openresty/openresty:centos" ports: - name: http protocol: TCP containerPort: 80 volumeMounts: - mountPath: /usr/local/openresty/nginx/conf/nginx.conf name: config subPath: nginx.conf volumes: - name: config configMap: name: nginx-v1 --- apiVersion: v1 kind: ConfigMap metadata: labels: app: nginx version: v1 name: nginx-v1 data: nginx.conf: |- worker_processes 1; events { accept_mutex on; multi_accept on; use epoll; worker_connections 1024; } http { ignore_invalid_headers off; server { listen 80; location / { access_by_lua ' local header_str = ngx.say("nginx-v1") '; } } }
再部署第二個版本:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-v2 spec: replicas: 3 selector: matchLabels: app: nginx version: v2 template: metadata: labels: app: nginx version: v2 spec: containers: - name: nginx image: "openresty/openresty:centos" ports: - name: http protocol: TCP containerPort: 80 volumeMounts: - mountPath: /usr/local/openresty/nginx/conf/nginx.conf name: config subPath: nginx.conf volumes: - name: config configMap: name: nginx-v2 --- apiVersion: v1 kind: ConfigMap metadata: labels: app: nginx version: v2 name: nginx-v2 data: nginx.conf: |- worker_processes 1; events { accept_mutex on; multi_accept on; use epoll; worker_connections 1024; } http { ignore_invalid_headers off; server { listen 80; location / { access_by_lua ' local header_str = ngx.say("nginx-v2") '; } } }
能夠在控制檯看到部署的狀況:
實現藍綠髮布
爲咱們部署的 Deployment 建立 LoadBalancer 類型的 Service 對外暴露服務,指定使用 v1 版本的服務:
apiVersion: v1 kind: Service metadata: name: nginx spec: type: LoadBalancer ports: - port: 80 protocol: TCP name: http selector: app: nginx version: v1
測試訪問:
$ for i in {1..10}; do curl EXTERNAL-IP; done; # 替換 EXTERNAL-IP 爲 Service 的 CLB IP 地址 nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1 nginx-v1
全是 v1 版本的響應,如今咱們切到 v2 版本,修改 Service 的 selector,讓它選中 v2 版本的服務,若是在控制檯改,先找到對應 Service,點擊 編輯YAML
:
修改 selector 部分:
selector: app: nginx version: v2
或者也能夠直接用 kubectl 修改:
kubectl patch service nginx -p '{"spec":{"selector":{"version":"v2"}}}'
再次測試訪問:
$ for i in {1..10}; do curl EXTERNAL-IP; done; # 替換 EXTERNAL-IP 爲 Service 的 CLB IP 地址 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v2
全是 v2 版本的響應,成功實現了藍綠髮布。
實現灰度發佈
相比藍綠髮布,咱們爲不給 Service 指定使用 v1 版本的服務,從 selector 中刪除 version
標籤,讓 Service 同時選中兩個版本的 Deployment 的 Pod:
apiVersion: v1 kind: Service metadata: name: nginx spec: type: LoadBalancer ports: - port: 80 protocol: TCP name: http selector: app: nginx
測試訪問:
$ for i in {1..10}; do curl EXTERNAL-IP; done; # 替換 EXTERNAL-IP 爲 Service 的 CLB IP 地址 nginx-v1 nginx-v1 nginx-v2 nginx-v2 nginx-v2 nginx-v1 nginx-v1 nginx-v1 nginx-v2 nginx-v2
能夠看到,一半是 v1 版本的響應,另外一半是 v2 版本的響應。如今咱們來調節 v1 和 v2 版本的 Deployment 的副本,將 v1 版本調至 1 個副本,v2 版本調至 4 個副本。
能夠經過控制檯操做:
也能夠經過 kubectl 操做:
kubectl scale deployment/nginx-v1 --replicas=1 kubectl scale deployment/nginx-v2 --replicas=4
而後再次進行訪問測試:
$ for i in {1..10}; do curl EXTERNAL-IP; done; # 替換 EXTERNAL-IP 爲 Service 的 CLB IP 地址nginx-v2nginx-v1nginx-v2nginx-v2nginx-v2nginx-v2nginx-v1nginx-v2nginx-v2nginx-v2$ for i in {1..10}; do curl EXTERNAL-IP; done; # 替換 EXTERNAL-IP 爲 Service 的 CLB IP 地址 nginx-v2 nginx-v1 nginx-v2 nginx-v2 nginx-v2 nginx-v2 nginx-v1 nginx-v2 nginx-v2 nginx-v2
能夠看到,10 次訪問中只有 2 次返回了 v1 版本,v1 與 v2 的響應比例與其副本數比例一致,爲 1:4,經過控制不一樣版本服務的副本數就實現了灰度發佈。
總結
本文咱們介紹瞭如何在有限的條件下在 Kubernetes 集羣中實現簡單的藍綠髮布與灰度發佈,對於一些簡單的發佈需求場景能夠考慮使用這種方案。
【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公衆號,及時獲取更多幹貨!!