天天看點

CODING DevOps + Nginx-ingress 實作自動化灰階釋出

作者:王炜,CODING DevOps 後端開發工程師,擁有多年研發經驗,雲原生、DevOps、Kubernetes 資深愛好者,Servicemesher 服務網格中文社群成員。獲得 Kubernetes CKA、CKAD 認證。

前言

在 Kubernetes 上的應用實作灰階釋出,最簡單的方案是引入官方的

Nginx-ingress

來實作。

我們通過部署兩套 deployment 和 services,分别代表灰階環境和生産環境,通過負載均衡算法,實作對兩套環境的按照灰階比例進行分流,進而實作灰階釋出。

通常的做法是當項目打包新鏡像後,通過修改

yaml

檔案的鏡像版本,執行

kubectl apply

的方式來更新服務。如果釋出流程還需要進行灰階釋出,那麼可以通過調整兩套服務的配置檔案權重來控制灰階釋出,這種方式離不開人工執行。如果項目數量多,灰階的時間跨度過長,人為誤操作的機率将大大增加,過于依賴于人工執行,這對于

DevOps

工程實踐是不能忍受的。

那麼,有沒有一種方式能夠實作無需人工幹預的自動化灰階呢?例如在代碼更新後,自動釋出到預釋出和灰階環境,并在一天的時間内自動将灰階比例從 10% 權重提高到 100%,且能夠随時終止,灰階通過後自動釋出到生産環境?

答案是肯定的,利用

CODING DevOps

就能夠滿足此類需求。

Nginx-ingress 架構和原理

迅速回顧一下

Nginx-ingress

的架構和實作原理:

CODING DevOps + Nginx-ingress 實作自動化灰階釋出

Nginx-ingress

通過前置的

Loadbalancer

類型的

Service

接收叢集流量,将流量轉發至

Nginx-ingress

Pod 内并對配置的政策進行檢查,再轉發至目标

Service

,最終将流量轉發至業務容器。

傳統的

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 互動的目的。

實作方案預覽

為了實作以上目标,我們設計了以下持續部署流水線。

CODING DevOps + Nginx-ingress 實作自動化灰階釋出

此持續部署流水線主要實作了以下幾個步驟:

1、自動部署到預釋出環境

2、是否進行 A/B 測試

3、自動灰階釋出(自動進行3次逐漸提升灰階比例)

4、釋出到生産環境

同時,本文案例還示範了從 Git 送出代碼到自動觸發持續內建的步驟:

1、送出代碼後觸發持續內建,自動建構鏡像

2、鏡像建構完成後,自動推送鏡像到制品庫

3、觸發持續部署

1、送出代碼後觸發持續內建,自動建構鏡像并推送到制品庫

2、觸發持續部署,并釋出到預釋出環境

CODING DevOps + Nginx-ingress 實作自動化灰階釋出

3、人工确認:進行 A/B 測試(或跳過直接進入自動灰階)

進行 A/B 測試時,隻有 Header 包含 location=shenzhen 可以通路新版本,其他使用者通路生産環境仍然為舊版本。

4、人工确認:是否自動灰階釋出(自動進行 3 輪逐漸提升灰階比例,每輪間隔 30s)

第一次灰階:新版本 30% 的灰階比例,此時通路生産環境大約有 30% 的流量進入新版本灰階環境:

30s 後自動進行第二輪灰階:新版本 60% 的灰階比例:

60s 後自動進行第三輪灰階:新版本 90% 的灰階比例:

本案例中,我們配置了自動化灰階釋出将會以 3 次漸進式進行,每次提高 30% 的比例,每次持續 30s 後自動進入下一個灰階階段。在不同的灰階階段,會發現請求新版本出現的機率越來越高。漸進式的灰階可根據業務需要進行任意配置,例如持續 1 天時間分 10 次自動進行灰階,直至釋出到生産環境而無需人工值守。

5、灰階完成,30s 後釋出到生産環境

項目源碼和原理分析

項目源碼位址:https://wangweicoding.coding.net/public/nginx-ingress-gray/nginx-ingress-gray/git

├── 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

來實作,主要是實作了兩套環境的:

  • Deployment
  • Service
  • Ingress

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

,負載均衡算法主要由

權重輪詢

的算法來實作分流。

整體架構圖如所示:

CODING DevOps + Nginx-ingress 實作自動化灰階釋出

環境準備

1、K8S 叢集,推薦使用騰訊雲容器服務;

2、開通 CODING DevOps,提供鏡像建構和流水線的部署能力。

實踐步驟

1、克隆源碼并推送至自己的 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 修改為自己的制品庫鏡像位址。

2、建立持續內建流水線

使用“自定義建構過程”建立建構計劃,并選擇使用代碼倉庫的

Jenkinsfile

3、新增雲賬号并建立持續部署流水線,複制項目的 pipeline Json 模闆到建立的流水線内(3 個)

為了便于使用模闆,建立持續部署流水線應用名為:nginx-ingress

建立繼續建立空白部署流程,複制 Json 模闆到持續部署流水線中,一共建立三條流水線:

  • nginx-ingress-init - 用于初始化 nginx-ingress
  • gray-init - 用于首次初始化環境
  • gray-deploy - 用于示範灰階釋出

    注意:請将以上流水線的雲賬号選擇為自己的雲賬号,另外 gray-deploy 流水線中,請重新配置“啟動所需制品”和“觸發器”。

4、初始化 nginx-ingress(首次運作)

首次運作

nginx-ingress

流水線将自動為您部署

nginx-ingress

。部署成功後,運作

kubectl get svc | grep nginx-ingress-controller

擷取

Ningx-ingress

EXTERNAL-IP

,此 IP 為叢集請求入口 IP 。并為本機配置

Host

,便于通路。

5、初始化灰階釋出(首次運作)

gray-init

流水線将自動部署一套完整的環境,否則自動化灰階流水線将會失敗。

6、自動觸發灰階釋出

現在,您可以嘗試修改項目

docker/html/index.html

檔案,推送後将自動觸發建構和持續部署,觸發後,進入“持續部署”頁面,檢視部署詳情和流程。

總結

我們主要利用了

CODING 持續部署

等待

階段,通過對不同灰階比例的階段設定等待時間,自動化逐一運作灰階階段,最終實作無人工值守的自動化灰階釋出。

利用

等待

階段,可以實作平滑的釋出流程,隻有當釋出出現問題,才需要人工介入。配合持續部署通知功能,可以很友善的将目前釋出狀态推送到企業微信、釘釘等協作工具。

為了友善展示,案例中對灰階比例和等待時間進行了寫死,你也可以使用階段的“自定義參數”來實作對灰階比例和等待實作進行動态控制,針對目前的釋出等級動态輸入灰階比例和流程控制,使得釋出更加靈活。

生産建議

本文的

Nginx-ingress

采用

deployment

的部署方式來實作。

Nginx-ingress

作為

Kubernetes

叢集的邊緣網關,承擔着所有入口流量,其高可用性直接決定了

Kubernetes

叢集的高可用性。

在生産環境,部署

Nginx-ingress

建議遵循以下幾點:

  • 推薦使用 DaemonSet 的方式部署,避免節點故障。
  • 通過标簽選擇器,将

    Nginx-ingress-controller

    部署在獨立的 Node 節點(如高主頻、高網絡、高 IO 節點)或者低負載的節點。
  • 如果采用

    Deployment

    的方式部署,可以為

    Nginx-ingress

    配置 HPA 水準伸縮。
關于 CODING,了解更多

繼續閱讀