在 Docker 中執行自我裝載代理程式

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

本文提供在 Docker 中執行 Azure Pipelines 代理程式的指示。 您可以在 Azure Pipelines 中設定自我裝載代理程式,以在 Windows 主機) 的 Windows Server Core (內執行,或使用 Docker) Linux 主機的 Ubuntu 容器 (。 如果您想要執行具有外部協調流程的代理程式,例如Azure 容器執行個體,這非常有用。 在本文中,您將逐步解說完整的容器範例,包括處理代理程式自我更新。

WindowsLinux都支援作為容器主機。 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 安裝失敗,請參閱您的系統檔以瞭解如何啟用虛擬化。

安裝 Docker for Windows

如果您使用 Windows 10,您可以安裝Docker Community Edition。 若為 Windows Server 2016,請安裝Docker Enterprise Edition

切換 Docker 以使用 Windows 容器

根據預設,適用于 Windows 的 Docker 會設定為使用 Linux 容器。 若要允許執行 Windows 容器,請確認適用于 Windows 的 Docker 正在執行 Windows 精靈

建立並建置 Dockerfile

接下來,建立 Dockerfile。

  1. 開啟命令提示字元。

  2. 建立新的目錄:

    mkdir C:\dockeragent
    
  3. 將目錄變更為此新目錄:

    cd C:\dockeragent
    
  4. 將下列內容儲存至名為 C:\dockeragent\Dockerfile 的檔案, (沒有副檔名) :

    FROM mcr.microsoft.com/windows/servercore:ltsc2019
    
    WORKDIR /azp
    
    COPY start.ps1 .
    
    CMD powershell .\start.ps1
    
  5. 將下列內容儲存至 C:\dockeragent\start.ps1

    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
    
    Write-Host "1. Determining matching Azure Pipelines agent..." -ForegroundColor Cyan
    
    $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
    
    Write-Host "2. Downloading and installing Azure Pipelines agent..." -ForegroundColor Cyan
    
    $wc = New-Object System.Net.WebClient
    $wc.DownloadFile($packageUrl, "$(Get-Location)\agent.zip")
    
    Expand-Archive -Path "agent.zip" -DestinationPath "\azp\agent"
    
    try
    {
      Write-Host "3. Configuring Azure Pipelines agent..." -ForegroundColor Cyan
    
      .\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
    
      Write-Host "4. Running Azure Pipelines agent..." -ForegroundColor Cyan
    
      .\run.cmd
    }
    finally
    {
      Write-Host "Cleanup. Removing Azure Pipelines agent..." -ForegroundColor Cyan
    
      .\config.cmd remove --unattended `
        --auth PAT `
        --token "$(Get-Content ${Env:AZP_TOKEN_FILE})"
    }
    
  6. 在該目錄中執行下列命令:

    docker build -t dockeragent:latest .
    

    此命令會在目前目錄中建置 Dockerfile。

    最後一個影像會 dockeragent:latest 標記為 。 您可以輕鬆地將它當做 dockeragent 在容器中執行,因為如果未指定任何標籤,則 latest 標記是預設值。

啟動映射

現在您已建立映射,您可以執行容器。

  1. 開啟命令提示字元。

  2. 執行容器。 這會安裝最新版的代理程式、設定並執行代理程式。 其目標為 Default 指定之 Azure DevOps 的集區,或您選擇的Azure DevOps Server實例:

    docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<PAT token> -e AZP_AGENT_NAME=mydockeragent dockeragent:latest
    

您可以選擇性地使用其他 環境變數來控制集區和代理程式工作目錄。

如果您想要每個管線執行的全新代理程式容器,請將--once 旗標傳遞至 run 命令。 您也必須使用容器協調流程系統,例如 Kubernetes 或Azure 容器執行個體,才能在工作完成時啟動容器的新複本。

Linux

安裝 Docker

根據您的 Linux 發行版本,您可以安裝Docker Community EditionDocker Enterprise Edition

建立並建置 Dockerfile

接下來,建立 Dockerfile。

  1. 開啟終端機。

  2. 建立新的目錄 (建議):

    mkdir ~/dockeragent
    
  3. 將目錄變更為此新目錄:

    cd ~/dockeragent
    
  4. 將下列內容儲存至 ~/dockeragent/Dockerfile

    • 針對 Ubuntu 20.04:
      FROM ubuntu:20.04
      RUN DEBIAN_FRONTEND=noninteractive apt-get update
      RUN DEBIAN_FRONTEND=noninteractive apt-get upgrade -y
      
      RUN DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \
          apt-transport-https \
          apt-utils \
          ca-certificates \
          curl \
          git \
          iputils-ping \
          jq \
          lsb-release \
          software-properties-common
      
      RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash
      
      # Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'.
      ENV TARGETARCH=linux-x64
      
      WORKDIR /azp
      
      COPY ./start.sh .
      RUN chmod +x start.sh
      
      ENTRYPOINT [ "./start.sh" ]
      
    • 針對 Ubuntu 18.04:
      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/*
      
      # Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'.
      ENV TARGETARCH=linux-x64
      
      WORKDIR /azp
      
      COPY ./start.sh .
      RUN chmod +x start.sh
      
      ENTRYPOINT ["./start.sh"]
      

    注意

    工作可能取決於容器預期提供的可執行檔。 例如,您必須將 zipunzip 套件新增至 RUN apt-get 命令,才能執行 ArchiveFilesExtractFiles 工作。 此外,由於這是可供代理程式使用的 Linux Ubuntu 映射,因此您可以視需要自訂映射。 例如:如果您需要建置 .NET 應用程式,您可以遵循在 Ubuntu 上安裝 .NET SDK 或 .NET 運行 時間檔,並將該檔案新增至映射。

  5. 將下列內容儲存至 ~/dockeragent/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
    
    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='\033[1;36m'
      nocolor='\033[0m'
      echo -e "${lightcyan}$1${nocolor}"
    }
    
    # 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..."
    
    trap 'cleanup; exit 0' EXIT
    trap 'cleanup; exit 130' INT
    trap 'cleanup; exit 143' TERM
    
    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 容器執行個體,才能在工作完成時啟動容器的新複本。

  6. 在該目錄中執行下列命令:

    docker build -t dockeragent:latest .
    

    此命令會在目前目錄中建置 Dockerfile。

    最後一個影像會 dockeragent:latest 標記為 。 您可以輕鬆地將它當做 dockeragent 在容器中執行,因為如果未指定任何標籤,則 latest 標記是預設值。

啟動映射

現在您已建立映射,您可以執行容器。

  1. 開啟終端機。

  2. 執行容器。 這會安裝最新版的代理程式、設定並執行代理程式。 其目標為 Default 指定之 Azure DevOps 的集區,或您選擇的Azure DevOps Server實例:

    docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<PAT token> -e AZP_AGENT_NAME=mydockeragent dockeragent:latest
    

    如果您想要每個管線作業的全新代理程式容器,請將--once 旗標傳遞至 run 命令。

    docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<PAT token> -e AZP_AGENT_NAME=mydockeragent dockeragent:latest --once
    

您可以選擇性地使用其他 環境變數來控制集區和代理程式工作目錄。

環境變數

環境變數 描述
AZP_URL Azure DevOps 或 Azure DevOps Server 實例的 URL。
AZP_TOKEN 個人存取權杖 (使用代理程式組件區) , (讀取、管理) 範圍,由有權在 設定代理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推送和提取容器。

設定秘密並部署複本集

  1. 在 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
    
  2. 執行此命令將您的容器推送至 Container Registry:

    docker push <acr-server>/dockeragent:latest
    
  3. 設定現有 AKS 叢集的 Container Registry 整合。

注意

如果您在 Azure 入口網站上有多個訂用帳戶,請先使用此命令來選取訂用帳戶

az account set --subscription <subscription id or >subscription name>
az aks update -n myAKSCluster -g myResourceGroup --attach-acr <acr-name>
  1. 將下列內容儲存至 ~/AKS/ReplicationController.yaml

    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>/dockeragent:latest
            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 會指出叢集上執行的數目或代理程式。

  2. 請執行這個命令:

    kubectl apply -f ReplicationController.yaml
    

現在您的代理程式會執行 AKS 叢集。

設定自訂 MTU 參數

允許針對容器作業所使用的網路指定 MTU 值, (適用于 k8s 叢集中的 docker-in-docker 案例) 。

您必須AGENT_MTU_VALUE設定環境變數,以在重新開機自我裝載代理程式之後設定 MTU 值。 您可以 在這裡 找到有關代理程式重新開機的詳細資訊,以及 在這裡為每個個別代理程式設定不同的環境變數。

這可讓您為作業容器設定網路參數,此命令的使用方式類似于在容器網路設定時使用下一個命令:

-o com.docker.network.driver.mtu=AGENT_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 ~/dockeragent/Dockerfile
dos2unix ~/dockeragent/start.sh
git add .
git commit -m 'Fixed CR'
git push

然後再試一次。 您不再收到錯誤。