做者:王煒,CODING DevOps 後端開發工程師,擁有多年研發經驗,雲原生、DevOps、Kubernetes 資深愛好者,Servicemesher 服務網格中文社區成員。得到 Kubernetes CKA、CKAD 認證。
在 Kubernetes 上的應用實現灰度發佈,最簡單的方案是引入官方的 Nginx-ingress
來實現。 html
咱們經過部署兩套 deployment 和 services,分別表明灰度環境和生產環境,經過負載均衡算法,實現對兩套環境的按照灰度比例進行分流,進而實現灰度發佈。nginx
一般的作法是當項目打包新鏡像後,經過修改 yaml
文件的鏡像版本,執行 kubectl apply
的方式來更新服務。若是發佈流程還須要進行灰度發佈,那麼能夠經過調整兩套服務的配置文件權重來控制灰度發佈,這種方式離不開人工執行。若是項目數量多,灰度的時間跨度過長,人爲誤操做的機率將大大增長,過於依賴於人工執行,這對於 DevOps
工程實踐是不能忍受的。git
那麼,有沒有一種方式可以實現無需人工干預的自動化灰度呢?例如在代碼更新後,自動發佈到預發佈和灰度環境,並在一天的時間內自動將灰度比例從 10% 權重提升到 100%,且可以隨時終止,灰度經過後自動發佈到生產環境?web
答案是確定的,利用 CODING DevOps
就可以知足此類需求。算法
迅速回顧一下 Nginx-ingress
的架構和實現原理:docker
Nginx-ingress
經過前置的 Loadbalancer
類型的 Service
接收集羣流量,將流量轉發至 Nginx-ingress
Pod 內並對配置的策略進行檢查,再轉發至目標 Service
,最終將流量轉發至業務容器。json
傳統的 Nginx
須要咱們配置 conf
文件策略。但 Nginx-ingress
經過實現 Nginx-ingress-Controller
將原生 conf
配置文件和 yaml
配置文件進行了轉化,當咱們配置 yaml
文件的策略後,Nginx-ingress-Controller
將對其進行轉化,而且動態更新策略,動態 Reload Nginx Pod
,實現自動管理。後端
那麼 Nginx-ingress-Controller
如何可以動態感知集羣的策略變化呢?方法有不少種,能夠經過 webhook admission 攔截器,也能夠經過 ServiceAccount 與 Kubernetes Api 進行交互,動態獲取。Nginx-ingress-Controller
使用後者來實現。因此在部署 Nginx-ingress
咱們會發現 Deployment
內指定了 Pod 的 ServiceAccount,以及實現了 RoleBinding ,最終達到 Pod 可以與 Kubernetes Api 交互的目的。api
爲了實現以上目標,咱們設計瞭如下持續部署流水線。微信
此持續部署流水線主要實現瞭如下幾個步驟:
一、自動部署到預發佈環境
二、是否進行 A/B 測試
三、自動灰度發佈(自動進行3次逐漸提高灰度比例)
四、發佈到生產環境
同時,本文案例還演示了從 Git 提交代碼到自動觸發持續集成的步驟:
一、提交代碼後觸發持續集成,自動構建鏡像
二、鏡像構建完成後,自動推送鏡像到製品庫
三、觸發持續部署
一、提交代碼後觸發持續集成,自動構建鏡像並推送到製品庫
二、觸發持續部署,併發布到預發佈環境
三、人工確認:進行 A/B 測試(或跳過直接進入自動灰度)
進行 A/B 測試時,只有 Header 包含 location=shenzhen 能夠訪問新版本,其餘用戶訪問生產環境仍然爲舊版本。
四、人工確認:是否自動灰度發佈(自動進行 3 輪逐漸提高灰度比例,每輪間隔 30s)
第一次灰度:新版本 30% 的灰度比例,此時訪問生產環境大約有 30% 的流量進入新版本灰度環境:
30s 後自動進行第二輪灰度:新版本 60% 的灰度比例:
60s 後自動進行第三輪灰度:新版本 90% 的灰度比例:
本案例中,咱們配置了自動化灰度發佈將會以 3 次漸進式進行,每次提升 30% 的比例,每次持續 30s 後自動進入下一個灰度階段。在不一樣的灰度階段,會發現請求新版本出現的機率愈來愈高。漸進式的灰度可根據業務須要進行任意配置,例如持續 1 天時間分 10 次自動進行灰度,直至發佈到生產環境而無需人工值守。
五、灰度完成,30s 後發佈到生產環境
項目源碼地址:https://wangweicoding.coding....
├── Jenkinsfile # 持續集成腳本 ├── deployment │ ├── canary │ │ └── deploy.yaml # 灰度發佈部署文件 │ ├── dev │ │ └── deploy.yaml # 預發佈部署文件 │ └── pro │ └── deploy.yaml # 生產部署文件 ├── docker │ ├── Dockerfile │ └── html │ └── index.html ├── nginx-ingress-init │ ├── nginx-ingress-deployment # nginx-ingress 部署文件 │ │ ├── ClusterRoleBinding.yaml │ │ ├── RoleBinding.yaml │ │ ├── clusterRole.yaml │ │ ├── defaultBackendService.yaml │ │ ├── defaultBackendServiceaccount.yaml │ │ ├── deployment.yaml │ │ ├── nginxDefaultBackendDeploy.yaml │ │ ├── roles.yaml │ │ ├── service.yaml │ │ └── serviceAccount.yaml │ └── nginx-ingress-helm # nginx-ingress Helm 包 │ └── nginx-ingress-1.36.3.tgz └── pipeline # 持續部署流水線模板 ├── gray-deploy.json # 灰度發佈流水線 ├── gray-init.json # 灰度發佈初始化(首次運行) └── nginx-ingress-init.json # nginx-ingress 初始化(首次運行)
灰度環境和生產環境主要由 deployment/canary/deploy.yaml
和 deployment/pro/deploy.yaml
來實現,主要是實現了兩套環境的:
A/B 測試和灰度由配置的 Ingress
進行控制:
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx # nginx=nginx-ingress| qcloud=CLB ingress nginx.ingress.kubernetes.io/canary: "true" # 開啓灰度 nginx.ingress.kubernetes.io/canary-by-header: "location" # A/B 測試用例 Header key nginx.ingress.kubernetes.io/canary-by-header-value: "shenzhen" # A/B 測試用例 Header value name: my-ingress namespace: pro spec: rules: - host: nginx-ingress.coding.pro http: paths: - backend: serviceName: nginx-canary servicePort: 80 path: /
A/B 測試主要由註解 nginx.ingress.kubernetes.io/canary-by-header
和 nginx.ingress.kubernetes.io/canary-by-header-value
進行控制,來匹配請求 Header 的 Key 和 Value。
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx # nginx=nginx-ingress| qcloud=CLB ingress nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-weight: 30 name: my-ingress namespace: pro spec: rules: - host: nginx-ingress.coding.pro http: paths: - backend: serviceName: nginx-canary servicePort: 80 path: /
而灰度則由註解 nginx.ingress.kubernetes.io/canary-weight
控制,值範圍能夠是 0-100
,對應灰度權重比例。在 Nginx-ingress
,負載均衡算法主要由加權輪詢
的算法來實現分流。
總體架構圖如所示:
一、K8S 集羣,推薦使用騰訊雲容器服務;
二、開通 CODING DevOps,提供鏡像構建和流水線的部署能力。
一、克隆源碼並推送至本身的 CODING Git 倉庫
$ git clone https://e.coding.net/wangweicoding/nginx-ingress-gray/nginx-ingress-gray.git $ git remote set-url origin https://you coding git $ git add . $ git commit -a -m 'first commit' $ git push -u origin master
注意,推送前請將 deployment/dev
、deployment/canary
、deployment/pro
文件夾的 deploy.yaml
image 修改成本身的製品庫鏡像地址。
二、建立持續集成流水線
使用「自定義構建過程」建立構建計劃,並選擇使用代碼倉庫的 Jenkinsfile
三、新增雲帳號並建立持續部署流水線,複製項目的 pipeline Json 模板到建立的流水線內(3 個)
爲了便於使用模板,建立持續部署流水線應用名爲:nginx-ingress
建立繼續建立空白部署流程,複製 Json 模板到持續部署流水線中,一共建立三條流水線:
注意:請將以上流水線的雲帳號選擇爲本身的雲帳號,另外 gray-deploy 流水線中,請從新配置「啓動所需製品」和「觸發器」。
四、初始化 nginx-ingress(首次運行)
首次運行 nginx-ingress
流水線將自動爲您部署nginx-ingress
。部署成功後,運行 kubectl get svc | grep nginx-ingress-controller
獲取 Ningx-ingress
的 EXTERNAL-IP
,此 IP 爲集羣請求入口 IP 。併爲本機配置 Host
,便於訪問。
五、初始化灰度發佈(首次運行)
首次運行 gray-init
流水線將自動部署一套完整的環境,不然自動化灰度流水線將會失敗。
六、自動觸發灰度發佈
如今,您能夠嘗試修改項目 docker/html/index.html
文件,推送後將自動觸發構建和持續部署,觸發後,進入「持續部署」頁面,查看部署詳情和流程。
咱們主要利用了 CODING 持續部署
的等待
階段,經過對不一樣灰度比例的階段設定等待時間,自動化逐一運行灰度階段,最終實現無人工值守的自動化灰度發佈。
利用等待
階段,能夠實現平滑的發佈流程,只有當發佈出現問題,才須要人工介入。配合持續部署通知功能,能夠很方便的將當前發佈狀態推送到企業微信、釘釘等協做工具。
爲了方便展現,案例中對灰度比例和等待時間進行了硬編碼,你也可使用階段的「自定義參數」來實現對灰度比例和等待實現進行動態控制,針對當前的發佈等級動態輸入灰度比例和流程控制,使得發佈更加靈活。
本文的 Nginx-ingress
採用 deployment
的部署方式來實現。Nginx-ingress
做爲 Kubernetes
集羣的邊緣網關,承擔着全部入口流量,其高可用性直接決定了 Kubernetes
集羣的高可用性。
在生產環境,部署 Nginx-ingress
建議遵循如下幾點:
Nginx-ingress-controller
部署在獨立的 Node 節點(如高主頻、高網絡、高 IO 節點)或者低負載的節點。Deployment
的方式部署,能夠爲 Nginx-ingress
配置 HPA 水平伸縮。關於 CODING,瞭解更多