Azure DevOps Server CI – 自搭跨平台容器代理Agents

前言
最近在地端(On-premises)幫團隊搭一套CI/CD流程,也順帶整理了一下從無到有的搭建過程,這次使用了docker技術來解決現有團隊使用CI/CD時讓現有CI/CD hosting環境過於複雜的問題。
在開始之前,我先預備一下搭建的環境,如下:

Windows Server 2012 R2( Traditional Chinese) VM虛擬機
Azure DevOps Server 2019 RC1.0
Docker version 18.03.0-ce
沒用上最新的Docker 版本是因為Win Server 2012 R2不支援容器化,需要安裝

Docker Toolbox( https://docs.docker.com/toolbox/toolbox_install_windows/
)

在使用docker image之前,先來簡單解釋一下代理Agent。MSDN的說法是是一套可被安裝的軟件(installable software),用來處理序列的工作(jobs)/任務(Tasks),比方說你出行時可以打車,而你可以選擇Taxi,Uber,或Didi..等等,出行就是你的job,而Taxi或Didi這邊來說就是Agent。

Agent可以處理在building或release這些活動,一旦有大量的building,或release活動產生的時候一個agent肯定負擔不小,這時多個agent是一個不錯的方案
我先從單一agent開始建立,這邊微軟的教程已經非常簡單了,我照其步驟快速過一遍,以便讀者能有基本認識,在搭建多個agent也能快速上手,也能進一步搭建容器化的agent
單agent建立:

  • 下載Agent

  1. 在DefaultCollection portal 頁面找到 集合設置

2.選擇 代理池,
可知在此可以設置多個代理

3.在默認下有個名稱 Default
的代理池,目前尚未創建任何的代理所以這邊顯示未註冊代理

4.選擇下載代理,你將會看到下列信息,選擇相應的OS下載代理,我安裝Azure Devops Server是在Windows Server下,所以這邊選擇Windows,由此可以得知Agent 可依附在不同的平台下如macOS,Linux

  • 安裝Agent

下載完後可以知道這是一個zip壓縮包微軟已經寫好了配置過程與啟用腳本

  1. 將壓縮包解壓到指定的位置,如 C:\agent

  2. 用admin 身分執行Powershell,切換到解壓directory

  3. 貼上微軟提供的命令, 注意不要包含空白

  4. 執行config.cmd 進行配置

5.配置過程如下,


這邊來說明一下各個配置

  • 服務器URL: 這邊如果沒有指定的明確的域名,可以輸入安裝Azure Devops Server 的服務器名

  • 驗證類型:這邊可先用默認的 Integrated

  • 代理名:可自定義名稱,如上圖指定了 Build-Agent

  • 用於服務的 賬戶
    名: 這邊可以 依照工作的需求與運維的要求看是否需要建立新的賬戶或用默認的
    ,我建立新的賬戶 adobuild,

    建立服務,服務啟動時會用這個 賬戶
    來啟動

  • 如無錯誤訊息,成功結束配置

6.
最後在代理池裡可以看到配置並成功聯機狀態的Agent


到此已經完成的最簡單的配置,也是微軟教程內的範疇,我們還差如何驗證Agent的功能?最簡單的方法就是將代碼分支enqueue到這個Default來進行編譯

最後可以在代理池看到編譯的狀態,也能從log看出編譯失敗的原因


以上就是一個簡易的搭建過程,但這邊衍伸了幾個問題?

回顧文章開頭所述,我在一個乾淨的VM進行配置,編譯之所以出錯是因為這是一個 .Net Core
的項目,VM壓根沒裝 .Net Core
SDK


裝上了當然編譯就沒問題,但想像一情境:


Azure Devops Server會同時有好多團隊來使用,如寫Python的,Node.js的,如果都在這台服務器下裝項目的依賴軟件

這樣真的好嗎?
如果使用在線Azure Devops Service 這可能會幫助您省去這個問題。
在地端(On-premises)搭建時,為了涵蓋以上情境,我使用了

Running a self-hosted agent in Docker

https://docs.microsoft.com/zh-tw/azure/devops/pipelines/agents/docker?view=azure-devops

這是需要Docker支持的技術
,如果agent可以在各個容器裡隔離開來,並且各自擁有可依賴的環境docker image後,如需要對.Net Core項目進行CI 可以準備一個docker file裏頭預先裝好.net sdk,Python項目也能用另一個 docker file
預先裝好 Python
,多個
docker file對應到不同的Agent,

這樣就可以保持 Azure Devops Server
的環境單純。

  • 準備

    docker file

上述的思維已經很多前輩都想到了,本文的案例在地端的Azure Devops Server使用Running a self-hosted agent in Docker

簡化現有團隊間的技術債,在一位歐洲的開發者

RobertoPrevato 的博客中我也看到相同做法。( https://robertoprevato.github.io/Self-hosted-Azure-DevOps-agents-running-in-Docker/
)。按微軟文檔的教程,只須執行
docker build出image並

docker


run

命令即可完成agent配置。

前面提到
agent

可以hosting在不同的操作系統下,在此我將agent 配置在linux下並裝好.net core sdk/runtimes等(為什麼是linux?因為可以免去大量授權的麻煩)

  • 項目可用的dockerfile如何建立?

    熟悉dockerfile應該可以跳過這一段。
    先來看看微軟在Running a self-hosted agent in Docker中範例

https://docs.microsoft.com/zh-tw/azure/devops/pipelines/agents/docker?view=azure-devops

FROM ubuntu:16.04


# To make it easier for build and release pipelines to run apt-get, # configure apt to not require confirmation (assume the -y argument by default) ENV DEBIAN_FRONTEND=noninteractive RUN echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes
RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ jq \ git \ iputils-ping \ libcurl3 \ libicu55 \ libunwind8 \ netcat
WORKDIR /azp
COPY ./start.sh . RUN chmod +x start.sh
CMD ["./start.sh"]

依樣畫葫蘆,從範例看到 apt-get install,
這邊就可以 自定義來安裝.net core 項目所需的依賴

(或其它如python項目)安裝片段如下:

apt-get install dotnet-sdk-2.1=2.1.301-1

apt-get install dotnet-sdk-2.2

通過範例還可得知,這dockerfile最後寫:

RUN chmod +x start.sh

透過start.sh腳本來進行agent配置(服務器URL/驗證類型…),

透過dockerfile可以建立(build)一個image,接著啟動(run) image

docker build -t dockeragent:latest .
docker run -e AZP_URL=<Azure DevOps instance> \

-e AZP_TOKEN=<PAT token> \

-e AZP_AGENT_NAME=mydockeragent \

dockeragent:latest

完成後便可在代理池看到一個名為 mydockeragent
基於 ubuntu 16.04
並帶有.net core 項目依賴環境的代理了。

以下我們實際來走訪一次Running a self-hosted agent in Docker流程,
很幸運的我已經看到預先搭好.net core sdk環境的dokerfile了


https://github.com/RobertoPrevato/AzureDevOps-agents/blob/master/ubuntu18.04-dotnet/Dockerfile
步驟分為二

  1. Build docker images

  2. Run Image

Let’s Go

  • Build docker images

    我簡化了 RobertoPrevato
    提供的dockerfile,因為image太多了build用時太長。

    您可以在 https://github.com/yuessir/AzureDevOps-agents/tree/Customized-master

    下載簡化過腳本到本地進行,如需其它語言dockerfile可找到原作fork源頭

    1.使用bash執行 build.sh


    2.腳本自動安裝所需依賴


如無錯誤則成功完成building images

  • Run Image

使用下列命令我們建立一個名為 Self-hosted Ubuntu 18.04
的代理池,代理名稱為 ubuntu18.04-dotnet
,使用image為 devopsubuntu18.04-dotnet:latest

  docker run -e AZP_URL=http://win-pmovrk1des/DefaultCollection \

     -e AZP_POOL='Self-hosted Ubuntu 18.04' \

     -e AZP_TOKEN=azusie3sn5so6i6nzfytgp2fkfelwr5itnzcf6pylfnwiyviha \

     -e AZP_AGENT_NAME='ubuntu18.04-dotnet' \

     devopsubuntu18.04-dotnet:latest

這邊需要注意由於
使用PAT驗證而非Integrated驗證,

在驗證過程中會發生缺少SSL的錯誤信息

這邊解決方案就是把Azure Devops Server加上SSL

更改命令如下

docker run -e AZP_URL=https://az.***.com/DefaultCollection \

--add-host az.***.com:192.168.239.128 \

   -e AZP_POOL='Self-hosted Ubuntu 18.04' \

   -e AZP_TOKEN=usie3sn5sokf6gdfkgp2fgrkfelwr5it \

   -e AZP_AGENT_NAME='ubuntu18.04-dotnet' \

   devopsubuntu18.04-dotnet:latest

執行命令:


配置成功將出現下面信息:


回到代理池頁面就可看到配置後的Ubuntu Agent了


在re-enqueue .net core項目分支後也可以看到順利被代理編譯成功。
這就是使用docker 作為Azure Devops Agent 的過程,過程礙於篇幅只先呈現ubuntu with .Net Agent的部分,您可以自行嘗試帶有python/nodejs的agent並實行CI。

最後簡單總結:

缺點:

  1. 項目成員要有能力知道如何提供dockerfile的內容

好處:

  1. 可以依照不同團隊的開發性質進行快速的替換不同的agent
  2. 安裝依賴組件時不會讓服務器變得擁腫,避免不必要的安全風險
  3. Builing image可以快速更新與重建,適合快速迭代的團隊

以上就是在地端搭建的過程,有任何的問題歡迎與我聯繫~
下一篇將會針對CD的部分來著墨