在 Docker 中執行自我裝載式代理程式
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
本文提供在 Docker 中執行 Azure Pipelines 代理程式的指示。 您可以在 Azure Pipelines 中設定自我裝載代理程式,以在 Windows Server Core 內執行(適用於 Windows 主機),或使用 Docker 在 Ubuntu 容器中執行。 當您想要執行具有外部協調流程的代理程式,例如 Azure 容器執行個體 時,這會很有用。 在本文中,您將逐步解說完整的容器範例,包括處理代理程式自我更新。
Windows 和 Linux 都支援作為容器主機。 Windows 容器應在 Windows vmImage
上執行。
若要在 Docker 中執行代理程式,您會將幾個 環境變數 傳遞至 docker run
,其會將代理程式設定為連線到 Azure Pipelines 或 Azure DevOps Server。 最後,您可以 自定義容器 以符合您的需求。 工作和腳本可能取決於容器 PATH
上可用的特定工具,而且您必須負責確保這些工具可供使用。
此功能需要代理程式 2.149 版或更新版本。 Azure DevOps 2019 未隨附相容的代理程式版本。 不過,如果您想要執行 Docker 代理程式,您可以將 正確的代理程式套件上傳至應用層 。
Windows
啟用 Hyper-V
根據預設,Windows 上不會啟用 Hyper-V。 如果您想要在容器之間提供隔離,您必須啟用 Hyper-V。 否則,適用於 Windows 的 Docker 將不會啟動。
注意
您必須在電腦上啟用虛擬化。 它通常預設為啟用。 不過,如果 Hyper-V 安裝失敗,請參閱您的系統檔,以瞭解如何啟用虛擬化。
安裝適用於 Windows 的 Docker (英文)
如果您使用 Windows 10,您可以安裝 Docker Community Edition。 若為 Windows Server 2016,請安裝 Docker Enterprise Edition。
將 Docker 切換為使用 Windows 容器
根據預設,適用於 Windows 的 Docker 會設定為使用 Linux 容器。 若要允許執行 Windows 容器,請確認適用於 Windows 的 Docker 正在執行 Windows 精靈。
建立並建置 Dockerfile
接下來,建立 Dockerfile。
開啟命令提示字元。
建立新的目錄:
mkdir "C:\azp-agent-in-docker\"
移至這個新目錄:
cd "C:\azp-agent-in-docker\"
將下列內容儲存至名為
C:\azp-agent-in-docker\azp-agent-windows.dockerfile
的檔案:FROM mcr.microsoft.com/windows/servercore:ltsc2022 WORKDIR /azp/ COPY ./start.ps1 ./ CMD powershell .\start.ps1
將下列內容儲存至
C:\azp-agent-in-docker\start.ps1
:function Print-Header ($header) { Write-Host "`n${header}`n" -ForegroundColor Cyan } if (-not (Test-Path Env:AZP_URL)) { Write-Error "error: missing AZP_URL environment variable" exit 1 } if (-not (Test-Path Env:AZP_TOKEN_FILE)) { if (-not (Test-Path Env:AZP_TOKEN)) { Write-Error "error: missing AZP_TOKEN environment variable" exit 1 } $Env:AZP_TOKEN_FILE = "\azp\.token" $Env:AZP_TOKEN | Out-File -FilePath $Env:AZP_TOKEN_FILE } Remove-Item Env:AZP_TOKEN if ((Test-Path Env:AZP_WORK) -and -not (Test-Path $Env:AZP_WORK)) { New-Item $Env:AZP_WORK -ItemType directory | Out-Null } New-Item "\azp\agent" -ItemType directory | Out-Null # Let the agent ignore the token env variables $Env:VSO_AGENT_IGNORE = "AZP_TOKEN,AZP_TOKEN_FILE" Set-Location agent Print-Header "1. Determining matching Azure Pipelines agent..." $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$(Get-Content ${Env:AZP_TOKEN_FILE})")) $package = Invoke-RestMethod -Headers @{Authorization=("Basic $base64AuthInfo")} "$(${Env:AZP_URL})/_apis/distributedtask/packages/agent?platform=win-x64&`$top=1" $packageUrl = $package[0].Value.downloadUrl Write-Host $packageUrl Print-Header "2. Downloading and installing Azure Pipelines agent..." $wc = New-Object System.Net.WebClient $wc.DownloadFile($packageUrl, "$(Get-Location)\agent.zip") Expand-Archive -Path "agent.zip" -DestinationPath "\azp\agent" try { Print-Header "3. Configuring Azure Pipelines agent..." .\config.cmd --unattended ` --agent "$(if (Test-Path Env:AZP_AGENT_NAME) { ${Env:AZP_AGENT_NAME} } else { hostname })" ` --url "$(${Env:AZP_URL})" ` --auth PAT ` --token "$(Get-Content ${Env:AZP_TOKEN_FILE})" ` --pool "$(if (Test-Path Env:AZP_POOL) { ${Env:AZP_POOL} } else { 'Default' })" ` --work "$(if (Test-Path Env:AZP_WORK) { ${Env:AZP_WORK} } else { '_work' })" ` --replace Print-Header "4. Running Azure Pipelines agent..." .\run.cmd } finally { Print-Header "Cleanup. Removing Azure Pipelines agent..." .\config.cmd remove --unattended ` --auth PAT ` --token "$(Get-Content ${Env:AZP_TOKEN_FILE})" }
在該目錄中執行下列命令:
docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
最後一個影像會標記
azp-agent:windows
。
啟動映像
現在您已建立映像,您可以執行容器。 這會安裝最新版的代理程序、設定並執行代理程式。 它會以您選擇的指定 Azure DevOps 或 Azure DevOps Server 實例的指定代理程式集區(預設代理 Default
程式集區)為目標:
docker run -e AZP_URL="<Azure DevOps instance>" -e AZP_TOKEN="<Personal Access Token>" -e AZP_POOL="<Agent Pool Name>" -e AZP_AGENT_NAME="Docker Agent - Windows" --name "azp-agent-windows" azp-agent:windows
如果您遇到網路問題,您可能需要指定 --network
參數。
docker run --network "Default Switch" < . . . >
如果您要停止容器,並使用 移除代理程式C
+ Ctrl
,您可能需要指定 --interactive
和 --tty
旗標(或只是 )。-it
docker run --interactive --tty < . . . >
如果您想要每個管線作業的全新代理程式容器,請將 --once
旗標傳遞至 run
命令。
docker run < . . . > --once
--once
使用 旗標,您可能會想要使用 Kubernetes 或 Azure 容器執行個體 等容器協調流程系統,在作業完成時啟動容器的新複本。
您可以使用選擇性 環境變數來控制代理程式名稱、代理程式集區和代理程式工作目錄。
Linux
安裝 Docker
根據您的 Linux 散發套件,您可以安裝 Docker Community Edition 或 Docker Enterprise Edition。
建立並建置 Dockerfile
接下來,建立 Dockerfile。
開啟終端機。
建立新的目錄 (建議):
mkdir ~/azp-agent-in-docker/
移至這個新目錄:
cd ~/azp-agent-in-docker/
將下列內容儲存至
~/azp-agent-in-docker/azp-agent-linux.dockerfile
:針對 Alpine:
FROM alpine ENV TARGETARCH="linux-musl-x64" # Another option: # FROM arm64v8/alpine # ENV TARGETARCH="linux-musl-arm64" RUN apk update RUN apk upgrade RUN apk add bash curl git icu-libs jq WORKDIR /azp/ COPY ./start.sh ./ RUN chmod +x ./start.sh RUN adduser -D agent RUN chown agent ./ USER agent # Another option is to run the agent as root. # ENV AGENT_ALLOW_RUNASROOT="true" ENTRYPOINT [ "./start.sh" ]
針對 Ubuntu 22.04:
FROM ubuntu:22.04 ENV TARGETARCH="linux-x64" # Also can be "linux-arm", "linux-arm64". RUN apt update RUN apt upgrade -y RUN apt install -y curl git jq libicu70 WORKDIR /azp/ COPY ./start.sh ./ RUN chmod +x ./start.sh # Create agent user and set up home directory RUN useradd -m -d /home/agent agent RUN chown -R agent:agent /azp /home/agent USER agent # Another option is to run the agent as root. # ENV AGENT_ALLOW_RUNASROOT="true" ENTRYPOINT [ "./start.sh" ]
如果您想要以 root 身分執行代理程式,
agent
請ENV AGENT_ALLOW_RUNASROOT="true"
取消批注該行,並移除在此行之前新增使用者。注意
工作可能取決於容器預期提供的可執行檔。 例如,您必須將和
unzip
套件新增zip
至RUN apt install -y
命令,才能執行ArchiveFiles
和ExtractFiles
工作。 此外,由於這是Linux Ubuntu映像供代理程式使用,因此您可以視需要自定義映像。 例如:如果您需要建置 .NET 應用程式,您可以遵循在Ubuntu上安裝 .NET SDK 或 .NET 執行時間檔,並將該檔新增至映像。將下列內容儲存至
~/azp-agent-in-docker/start.sh
,請務必使用 Unix 樣式 (LF) 行尾結束詞:#!/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 cleanup() { trap "" EXIT 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="\033[1;36m" nocolor="\033[0m" echo -e "\n${lightcyan}$1${nocolor}\n" } # Let the agent ignore the token env variables export VSO_AGENT_IGNORE="AZP_TOKEN,AZP_TOKEN_FILE" print_header "1. Determining matching Azure Pipelines agent..." AZP_AGENT_PACKAGES=$(curl -LsS \ -u user:$(cat "${AZP_TOKEN_FILE}") \ -H "Accept:application/json" \ "${AZP_URL}/_apis/distributedtask/packages/agent?platform=${TARGETARCH}&top=1") AZP_AGENT_PACKAGE_LATEST_URL=$(echo "${AZP_AGENT_PACKAGES}" | jq -r ".value[0].downloadUrl") if [ -z "${AZP_AGENT_PACKAGE_LATEST_URL}" -o "${AZP_AGENT_PACKAGE_LATEST_URL}" == "null" ]; then echo 1>&2 "error: could not determine a matching Azure Pipelines agent" echo 1>&2 "check that account "${AZP_URL}" is correct and the token is valid for that account" exit 1 fi print_header "2. Downloading and extracting Azure Pipelines agent..." curl -LsS "${AZP_AGENT_PACKAGE_LATEST_URL}" | tar -xz & wait $! source ./env.sh trap "cleanup; exit 0" EXIT trap "cleanup; exit 130" INT trap "cleanup; exit 143" TERM print_header "3. 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 "4. Running Azure Pipelines agent..." chmod +x ./run.sh # 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 "$@" & wait $!
注意
您也必須使用容器協調流程系統,例如 Kubernetes 或 Azure 容器執行個體,在工作完成時啟動容器的新複本。
在該目錄中執行下列命令:
docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
最後一個影像會標記
azp-agent:linux
。
啟動映像
現在您已建立映像,您可以執行容器。 這會安裝最新版的代理程序、設定並執行代理程式。 它會以您選擇的指定 Azure DevOps 或 Azure DevOps Server 實例的指定代理程式集區(預設代理 Default
程式集區)為目標:
docker run -e AZP_URL="<Azure DevOps instance>" -e AZP_TOKEN="<Personal Access Token>" -e AZP_POOL="<Agent Pool Name>" -e AZP_AGENT_NAME="Docker Agent - Linux" --name "azp-agent-linux" azp-agent:linux
如果您要停止容器,並使用 移除代理程式C
+ Ctrl
,您可能需要指定 --interactive
和 --tty
旗標(或只是 )。-it
docker run --interactive --tty < . . . >
如果您想要每個管線作業的全新代理程式容器,請將 --once
旗標傳遞至 run
命令。
docker run < . . . > --once
--once
使用 旗標,您可能會想要使用容器協調流程系統,例如 Kubernetes 或 Azure 容器執行個體,在作業完成時啟動容器的新複本。
您可以使用選擇性 環境變數來控制代理程式名稱、代理程式集區和代理程式工作目錄。
環境變數
環境變數 | 描述 |
---|---|
AZP_URL | Azure DevOps 或 Azure DevOps Server 實例的 URL。 |
AZP_TOKEN | 具有代理程式集區的個人存取令牌(PAT)範圍(讀取、管理)範圍,由有權在 AZP_URL 上設定代理程式的使用者所建立。 |
AZP_AGENT_NAME | 代理程式名稱(預設值:容器主機名)。 |
AZP_POOL | 代理程式集區名稱(預設值: Default )。 |
AZP_WORK | 工作目錄(預設值: _work )。 |
新增工具和自定義容器
您已建立基本組建代理程式。 您可以擴充 Dockerfile 以包含其他工具和其相依性,或使用此容器作為基底層來建置您自己的容器。 請確定下列專案保持不變:
- 腳本
start.sh
是由 Dockerfile 呼叫。 - 腳本
start.sh
是 Dockerfile 中的最後一個命令。 - 確定衍生容器不會移除 Dockerfile 所陳述的任何相依性。
在 Docker 容器內使用 Docker
若要從 Docker 容器內使用 Docker,您可以繫結掛接 Docker 套接字。
警告
這樣做具有嚴重的安全性影響。 容器內的程式代碼現在可以在 Docker 主機上以根目錄執行。
如果您確定要這樣做,請參閱 Docker.com 上的系結掛接 檔。
使用 Azure Kubernetes Service 叢集
警告
請考慮任何 Docker 型工作都無法在 AKS 1.19 或更新版本上運作,因為 Docker 限制中的 Docker。 Docker 已取代為 Kubernetes 1.19 中的容器 ,而 Docker-in-Docker 變得無法使用。
部署和設定 Azure Kubernetes Service
請遵循快速入門:使用 Azure 入口網站 部署 Azure Kubernetes Service (AKS) 叢集中的步驟。 之後,您的 PowerShell 或 Shell 控制台可以使用 kubectl
命令行。
部署及設定 Azure Container Registry
請遵循快速入門:使用 Azure 入口網站建立 Azure 容器登錄中的步驟。 之後,您可以從 Azure Container Registry 推送和提取容器。
設定秘密並部署副本集
在 AKS 叢集上建立秘密。
kubectl create secret generic azdevops \ --from-literal=AZP_URL=https://dev.azure.com/yourOrg \ --from-literal=AZP_TOKEN=YourPAT \ --from-literal=AZP_POOL=NameOfYourPool
執行此指令將您的容器推送至 Container Registry:
docker push "<acr-server>/azp-agent:<tag>"
設定現有 AKS 叢集的 Container Registry 整合。
注意
如果您在 Azure 入口網站上有多個訂用帳戶,請先使用此命令來選取訂用帳戶
az account set --subscription "<subscription id or subscription name>"
az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
將下列內容儲存至
~/AKS/ReplicationController.yml
:apiVersion: apps/v1 kind: Deployment metadata: name: azdevops-deployment labels: app: azdevops-agent spec: replicas: 1 # here is the configuration for the actual agent always running selector: matchLabels: app: azdevops-agent template: metadata: labels: app: azdevops-agent spec: containers: - name: kubepodcreation image: <acr-server>/azp-agent:<tag> env: - name: AZP_URL valueFrom: secretKeyRef: name: azdevops key: AZP_URL - name: AZP_TOKEN valueFrom: secretKeyRef: name: azdevops key: AZP_TOKEN - name: AZP_POOL valueFrom: secretKeyRef: name: azdevops key: AZP_POOL volumeMounts: - mountPath: /var/run/docker.sock name: docker-volume volumes: - name: docker-volume hostPath: path: /var/run/docker.sock
此 Kubernetes YAML 會建立副本集和部署,其中
replicas: 1
表示在叢集上執行的號碼或代理程式。執行此命令:
kubectl apply -f ReplicationController.yml
現在您的代理程式會執行 AKS 叢集。
設定自訂 MTU 參數
允許為容器作業所使用的網路指定 MTU 值(適用於 k8s 叢集中的 docker-in-docker 案例)。
您必須設定環境變數AGENT_DOCKER_MTU_VALUE來設定 MTU 值,然後重新啟動自我裝載代理程式。 您可以在這裡找到有關代理程式重新啟動的詳細資訊,以及在這裡為每個個別代理程式設定不同的環境變數。
這可讓您設定作業容器的網路參數,使用此命令類似於在容器網路設定時使用下一個命令:
-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE
在 Docker 容器中使用 Docker 掛接磁碟區
如果 Docker 容器在另一個 Docker 容器內執行,它們都會使用主機的精靈,因此所有掛接路徑都會參考主機,而不是容器。
例如,如果我們想要將路徑從主機掛接至外部 Docker 容器,我們可以使用此命令:
docker run ... -v "<path-on-host>:<path-on-outer-container>" ...
如果我們想要將路徑從主機掛接至內部 Docker 容器,則可以使用此命令:
docker run ... -v "<path-on-host>:<path-on-inner-container>" ...
但是,我們無法將外部容器的路徑掛接至內部容器;若要解決此問題,我們必須宣告 ENV 變數:
docker run ... --env DIND_USER_HOME=$HOME ...
在此之後,我們可以使用下列命令,從外部容器啟動內部容器:
docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...
常見錯誤
如果您使用 Windows,並收到下列錯誤:
standard_init_linux.go:178: exec user process caused "no such file or directory"
下載並安裝 git-scm 以安裝 Git Bash。
執行此命令:
dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push
然後再試一次。 您不再收到錯誤。