1. 程式人生 > >微軟容器周邊玩具之 Brigade 篇

微軟容器周邊玩具之 Brigade 篇

        今兒咱們撩一撩 Brigade,AZURE 的童鞋出去講容器總會把 Helm,Draft,Brigade 掛在嘴邊,這 Brigade 到底能做什麼今天我們就來說一說。K8s 中有一種排程模式叫 Job,Job 不名思意就是任務,以達到某一目標定義的一系列執行,Job 其實非常適合在 K8s 中執行,容器呼之即來揮之即去的特點,可以非常方便的做任務的編排,任務執行中申請資源,任務結束返回結果釋放資源。簡單的一些的任務可能由一個事務構成,複雜的任務可能由一系列事務構成。當需要執行一系列事務時可以把所有事務放在一個容器中執行,也可以通過把事務放入流水線(workflow)來執行。流水線作業顯然在靈活性和效率上更勝一籌,流水線通過將複雜任務拆分為獨立的事務單元,然後每個事務單元分別由專門的處理單元來進行出來,然後將結果傳遞給下一個處理單元,通過這種方法,一個複雜的任務可以拆解為多個標準的事務,後續當有新的複雜事務時,這些標準事務單元可以進行重組來實現新的事務邏輯。在 K8s 中 Job 更像簡單事務的處理邏輯,在單個容器中將事務進行處理,缺乏通用性和靈活性,那麼有沒有這樣一個工具或平臺可以實現複雜事物內任務的的編排,並在任務間實現訊息的傳遞以及事件驅動邏輯,Brigade 就是我們要找的答案。下面我們就以一個 CI (Continue Intergrated)的例子來為大家介紹一下 Brigade。

       在 CI 過程中我們想實現一個從程式碼更新 -> 映象Build -> 通知開發人員新版本釋出 ,我們今天把整個過程通過 Brigade + AKS + ACR 的方式來實現,下面我們先來看一下 CI Workflow 的流程圖:

        在開始之前我們先來完成一些基本元件的安裝,假設我們在環境中已經擁有 AKS,ACR,以及現成的 Slack 賬戶,下面我們先來進行 Brigade Gateway的安裝,Brigade Gateway 是 Brigade 的事件監聽閘道器,上述我們在預定義的流水線的事件驅動監聽器都是由 Brigade Gateway 來實現,當 Brigade Gateway 聽到事件請求後會觸發相關聯的任務(比如上述的容器映象 Build,Slack Notification)。安裝很簡單我們可以直接通過 helm 來進行快速安裝:

helm repo add brigade https://azure.github.io/brigade
helm install brigade/brigade --set cr.enabled=true,cr.service.type=LoadBalancer

本文不對 helm 做深入介紹,感興趣的童鞋可以等我下一篇文章。這裡上述兩條命令是快速安裝了 Brigade Gateway,其中指定的引數 cr.enable=true, cr.service.type=LoadBalancer 是用來在 Brigade Gateway 上開啟 ACR(Azure Container Registry)事件監聽器,並且由於 ACR 是個公網服務,所以 Brigade Gatway 需要暴露公網訪問節點來供 ACR 的 Webhook 訪問。好奇的童鞋可能問,為什麼沒有關於 Github 的引數,預設 Brigade Gateway 就支援監聽 Github Webhook 的事件訊息。除此之外,Brigade 專案還支援一些其它閘道器型別(如 EventGrid,Kubernetes Event 等, 可以訪問:

https://github.com/Azure/brigade 瞭解更多所支援閘道器的內容)。安裝成功後通過 kubectl get pods 可以看到在 kubernetes cluster 內多了兩個 Pod。

kubectl get pods
NAME                                         READY   STATUS      RESTARTS   AGE
brigade-brigade-api-6bf4cbdccd-5p7br         1/1     Running     0          6d
brigade-brigade-cr-gw-77d965d846-pkbmk       1/1     Running     0          6d
brigade-brigade-ctrl-8544c45b68-2tb5k        1/1     Running     0          6d
brigade-brigade-github-gw-5ff9c674cf-xtt4f   1/1     Running     0          6d

其中 brigade-brigade-github-gw 和 brigade-brigade-cr-gw 就是 Brigade 用來監聽 Github 和 ACR 的事件閘道器。萬事俱備,我們可以開始進入主題,通過 Brigade 如何來編排整個上述 CI 的水線。

        Brigade 整個任務編排的邏輯通過  brigade.js 檔案來進行描述,Brigade 對任務編排邏輯進行了程式碼的抽象,使用者客戶方便的通過二次封裝的類庫來編寫流水線邏輯,以本文的示例為例,我們來進行一些解讀,幫助大家理解。大家在進行自己的專案時,可以參考 https://azure.github.io/brigade/topics/scripting.html 和 https://azure.github.io/brigade/topics/javascript.html 來編寫自己的流水線。

 1 const { events, Job } = require("brigadier");
 2 
 3 events.on("push", function(e, project) {
 4   var driver = project.secrets.DOCKER_DRIVER || "overlay"
 5 
 6 // Build and push a Docker image.
 7   const docker = new Job("dind", "docker:stable-dind")
 8   docker.privileged = true;
 9   docker.env = {
10     DOCKER_DRIVER: driver
11   }
12   docker.tasks = [
13     "dockerd-entrypoint.sh &",
14     "sleep 20",
15     "cd /src",
16     "docker build -t $DOCKER_REGISTRY/flask ."
17   ];
18 
19 // If a Docker user is specified, we push.
20   if (project.secrets.DOCKER_USER) {
21     docker.env.DOCKER_USER = project.secrets.DOCKER_USER
22     docker.env.DOCKER_PASS = project.secrets.DOCKER_PASS
23     docker.env.DOCKER_REGISTRY = project.secrets.DOCKER_REGISTRY
24     docker.tasks.push("docker login -u $DOCKER_USER -p $DOCKER_PASS $DOCKER_REGISTRY")
25     docker.tasks.push("docker push $DOCKER_REGISTRY/flask")
26   } else {
27     console.log("skipping push. DOCKER_USER is not set.");
28   }
29  
30   docker.run()
31 })
32 
33 events.on("image_push", (e, project) => {
34   var docker = JSON.parse(e.payload)
35   console.log(docker)
36   var message = "New Build " + docker.target.repository + ":"+ docker.target.tag + " available!"
37   var slack = new Job("slack-notify", "technosophos/slack-notify:latest", ["/slack-notify"])
38   slack.storage.enabled = false
39   slack.env = {
40       SLACK_WEBHOOK: project.secrets.SLACK_WEBHOOK, 
41       SLACK_USERNAME: "BrigadeBot",
42       SLACK_TITLE: "Brigade Build Demo",
43       SLACK_MESSAGE: message,
44       SLACK_COLOR: "#0000ff"
45   }
46   slack.run()
47 })

程式碼中基本組成框架為 event.on 和 job,event.on 來定義觸發事件,job 來定義事件的響應。job 中通過呼叫容器來實現任務的執行。以上述 events.on("push", function(e, project) 為例,定義了當收到 Github push 事件後,將事件訊息 e 和 專案 project 資訊傳參至 context 內,然後建立 job 對該事件進行處理,job 以 new Job("dind", "docker:stable-dind") 進行建立,通過 docker:stable-dind 映象建立一個任務處理環境來執行映象 build 和 映象 push 的工作。第二部分 events.on("image_push", (e, project) 定義了當 ACR 發出 push 事件通過後進行 Slack 訊息推送的任務。這部分也出現了 e 和 project,e 很容易理解,就是上游事件通告方傳入的事件訊息的內容,那 project 是什麼呢?

        Brigade 中定義 project 為一個 Code Version Control System。即你有很多的程式碼專案,你可以通過定義多個 project 來描述不同的專案,從而實現在不同專案下定義不同引數、不同 context 的目標。project 在 Brigade 中通過 yaml 檔案的方式進行描述,以上述示例為例,我們來看一下如何通過它定義引數和 context。

 1 cloneURL: "https://github.com/nonokangwei/brigadedemo.git"
 2 namespace: "default"
 3 project: "nonokangwei/brigadedemo"
 4 repository: "github.com/nonokangwei/brigadedemo"
 5 sharedSecret: "09879879879879879879879871"
 6 secrets: {
 7   DOCKER_USER: "k8sdemoacr",
 8   DOCKER_PASS: "xxyJ5ON6M4/ur11yl1ta0X6P5g9vZP19",
 9   DOCKER_REGISTRY: "k8sdemoacr.azurecr.io",
10   SLACK_WEBHOOK: "https://hooks.slack.com/services/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"
11 }

其中 project 關鍵字定義了專案名稱,repogistory 定義了程式碼倉庫資訊,secrets 是針對這個專案的引數資訊,在 brigade.js 中可以引用這些引數來進行任務的定製化。yaml 檔案建立好後,需要在 Brigade 中進行註冊來讓 Gateway 開始監聽相關專案的事件訊息。註冊方法如下:

helm install brigade/brigade-project -f {project-name}.yaml

執行後你會發現在 kubernetes cluster 它會建立一個 kubernetes secrets 物件,將上述資訊存入其中,後續可以被 Job 中建立的容器來載入使用。

        通過上面的定義我們示例中的 CI 流水線已經定義好了,下面我們來配置一下 Github 和 ACR 中的 Webhook,然後再在 Slack 中配置一下訊息接收。

        Github Webhook 配置方法如下,進入到自己的 Github 專案中,選擇 Setting -> Webhooks,然後選擇 add webhook,Content Type 選擇 application/json,Payload URL 填入通過 kubectl get svc 中獲取的 brigade-brigade-github-gw 的公網地址按照 “http://YOUR_HOSTNAME:7744/events/github” 格式填寫。

        ACR 的 Webhook 配置方法如下,在 Azure Portal 選擇建立的 ACR,選擇 Webhook -> Add, Service URI 按照 http://YOUR_HOSTNAME:80/events/webhook/nonokangwei/brigadedemo?commit=master 格式進行輸入,其中 nonokangwei/brigadedemo 替換為你們自己的專案名稱,這裡的名稱需要與在上述 project yaml 檔案中定義的 project 名稱一致,這樣當事件訊息進入 Gateway 後,Gateway 才可以知道該訊息歸屬哪一個專案該如何進行處理。

        Slack 可以登入 https://api.slack.com/incoming-webhooks 來定義偵聽器。

        下面我們來對整個流水線進行模擬,在該專案中定義了一個簡單的 python flask 框架的 Web 程式,在 github 中對 Web 程式進行更新併發布,然後來觀察整個流水線的執行情況。編輯 github 中的 app.py 檔案,將 Hey 替換為 Hello 並 commit 提交。kubectl get pods 會看到一個名為 dind-01cx5x48c5cmnbtsmry84pwxz9 的 Pods 被建立開始執行,該 Pods 對 Github 的 Push 事件訊息進行處理,開始 Docker Build 的操作,操作成功後將 Build 好的映象釋出至 ACR,ACR 收到映象後,觸發 Webhook 發出事件訊息,此時在 kubernetes cluster 中看到一個名為 slack-notify-01cx5xb79t3z6fc3552d28h869 的 Pods 被該事件觸發,然後發出 Slack 的通知訊息,最後在 Slack 中我們收到有新映象可用的通知訊息。

        通過上面一個 CI 流水線的示例,相信大家已經對 Brigade 有所瞭解,Brigade 是一個開源的藉助 Kubernetes 來實現事件驅動事務處理編排的工具,並且其原生提供了很多常見事件閘道器和任務容器映象,方便大家做流水線化的事務編排。最後給再分享給大家一些學習資料,方便大家快速上手。

閱讀資料:

1. Brigade 手冊列表: https://azure.github.io/brigade/topics/

2. brigrade.js 開發說明:  https://azure.github.io/brigade/topics/scripting.html  必讀,可以幫助你快速掌握 brigade 的開發方法

3. brigade SDK 類庫字典:https://azure.github.io/brigade/topics/javascript.html 不懂的地方就查查字典