【2021鐵人賽】建立自管的Azure DevOps Agent(Linux Container agent)

前一篇文章建立了Azure DevOps Agent的Windows Container Image,已經知道了基本的概念就是:

  1. 選擇基底映像檔
  2. 安裝所需要的額外套件與程式
  3. 將Azure DevOps Agent的開始程式start.ps/start.sh複製進去

既然已經知道了上面的概念,前一篇也有做過一次,那麼這篇就少浪費一些篇幅,直接把Code端上來看吧!

start.sh的內容如下,記得要改成Unix格式的結束符號(LF)喔!(或是透過dos2unix轉換)

#!/bin/bash
set -e

if [ -z "$AZP_URL" ]; then
  echo 1>&2 "error: missing AZP_URL environment variable"
  exit 1
fi

if [ -z "$AZP_TOKEN_FILE" ]; then
  if [ -z "$AZP_TOKEN" ]; then
    echo 1>&2 "error: missing AZP_TOKEN environment variable"
    exit 1
  fi

  AZP_TOKEN_FILE=/azp/.token
  echo -n $AZP_TOKEN > "$AZP_TOKEN_FILE"
fi

unset AZP_TOKEN

if [ -n "$AZP_WORK" ]; then
  mkdir -p "$AZP_WORK"
fi

export AGENT_ALLOW_RUNASROOT="1"

cleanup() {
  if [ -e config.sh ]; then
    print_header "Cleanup. Removing Azure Pipelines agent..."

    # If the agent has some running jobs, the configuration removal process will fail.
    # So, give it some time to finish the job.
    while true; do
      ./config.sh remove --unattended --auth PAT --token $(cat "$AZP_TOKEN_FILE") && break

      echo "Retrying in 30 seconds..."
      sleep 30
    done
  fi
}

print_header() {
  lightcyan='3[1;36m'
  nocolor='3[0m'
  echo -e "${lightcyan}$1${nocolor}"
}

# Let the agent ignore the token env variables
export VSO_AGENT_IGNORE=AZP_TOKEN,AZP_TOKEN_FILE

source ./env.sh

print_header "1. Configuring Azure Pipelines agent..."

./config.sh --unattended \
  --agent "${AZP_AGENT_NAME:-$(hostname)}" \
  --url "$AZP_URL" \
  --auth PAT \
  --token $(cat "$AZP_TOKEN_FILE") \
  --pool "${AZP_POOL:-Default}" \
  --work "${AZP_WORK:-_work}" \
  --replace \
  --acceptTeeEula & wait $!

print_header "2. Running Azure Pipelines agent..."

trap 'cleanup; exit 0' EXIT
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM

# To be aware of TERM and INT signals call run.sh
# Running it with the --once flag at the end will shut down the agent after the build is executed
./run.sh "$@"

官方的Dockerfile內容如下:

FROM ubuntu:18.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 \
    libcurl4 \
    libicu60 \
    libunwind8 \
    netcat \
    libssl1.0 \
  && rm -rf /var/lib/apt/lists/*

RUN curl -LsS https://aka.ms/InstallAzureCLIDeb | bash \
  && rm -rf /var/lib/apt/lists/*

ARG TARGETARCH=amd64
ARG AGENT_VERSION=2.185.1

WORKDIR /azp
RUN if [ "$TARGETARCH" = "amd64" ]; then \
      AZP_AGENTPACKAGE_URL=https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz; \
    else \
      AZP_AGENTPACKAGE_URL=https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-${TARGETARCH}-${AGENT_VERSION}.tar.gz; \
    fi; \
    curl -LsS "$AZP_AGENTPACKAGE_URL" | tar -xz

COPY ./start.sh .
RUN chmod +x start.sh

ENTRYPOINT [ "./start.sh" ]

同樣的,上面的Dockerfile並不包含dotnet sdk,所以仍然需要自行安裝進去。

也和上一篇提到的一樣,我們可以透過在Docker hub上找到官方的dotnet sdk映像檔,找到我們要的OS版本,然後取代Dockerfile第一行的FROM後面使用的image repository:

上圖的表格來自於微軟在Docker Hub上的dotnet sdk頁面,dotnet sdk的image repository是mcr.microsoft.com/dotnet/sdk:5.0,我們只需要將冒號後面的5.0改成需要的就行了,以上面紅框內容為例,就把5.0改為5.0-focal,這樣就是以Ubuntu 20.04為版本安裝了dotnet sdk 5.0製作的Docker image,再加上安裝PowerShell、Docker的話,最終的Dockerfile內容如下:

FROM mcr.microsoft.com/dotnet/sdk:5.0-focal

# 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

#在這底下加入要額外裝在Docker Image內的程式

RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    jq \
    git \
    iputils-ping \
    libcurl4 \
    libicu66 \
    libunwind8 \
    netcat \
    libssl1.0 \
	wget \
  && rm -rf /var/lib/apt/lists/*

# 新增 Microsoft 存放庫金鑰和摘要
RUN wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb && \
         dpkg -i packages-microsoft-prod.deb

# 安裝PowerShell
# Enable the "universe" repositories & Install PowerShell
RUN apt-get update && apt-get install -y powershell

# 安裝Docker
RUN apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add
RUN add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
RUN apt-get update && apt-get install docker-ce docker-ce-cli containerd.io

#===========================================

RUN curl -LsS https://aka.ms/InstallAzureCLIDeb | bash \
  && rm -rf /var/lib/apt/lists/*

ARG TARGETARCH=amd64
ARG AGENT_VERSION=2.185.1

WORKDIR /azp
RUN if [ "$TARGETARCH" = "amd64" ]; then \
      AZP_AGENTPACKAGE_URL=https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-x64-${AGENT_VERSION}.tar.gz; \
    else \
      AZP_AGENTPACKAGE_URL=https://vstsagentpackage.azureedge.net/agent/${AGENT_VERSION}/vsts-agent-linux-${TARGETARCH}-${AGENT_VERSION}.tar.gz; \
    fi; \
    curl -LsS "$AZP_AGENTPACKAGE_URL" | tar -xz

COPY ./start.sh .
RUN chmod +x start.sh

ENTRYPOINT [ "./start.sh" ]

上面的Dockerfile內容中要特別提一下在官方的範例中安裝的libicu60 package只適用在Ubuntu 18.04(參考這篇),因為我是選Ubuntu 20.04,所以改成libicu66(參考這篇)。

準備好Dockerfile和start.sh這兩個檔案之後,執行下面的指令建立映像檔:

docker build -t devopsagent .

完成Build Image的動作之後,透過下面的指令建立一個名為azure-agent的Container:

docker run --name azure-agent -d -v /var/run/docker.sock:/var/run/docker.sock -e AZP_URL=[AzureDevOpsURL] -e AZP_TOKEN=[AzureDevOpsPAT] -e AZP_AGENT_NAME=[AzureDevOpsAgentName] IMAGE:TAG

docker run的指令和前一篇的大同小異,主要差別在於如何繫結host的docker給container使用。

同樣的環境變數表再貼一次:

Azure DevOps Agent所使用的環境變數

同樣貼一下執行的結果:

還有Agent Pools裡的列表和Agent的Capabilities:

其它和前一篇的內容沒什麼太大的差別,至於Linux VM的部份意思差不多,所以就不再另外弄一篇安裝在Linux VM裡的文章了

發佈留言