Kör en lokalt installerad agent i Docker

Azure DevOps Services | Azure DevOps Server 2022 – Azure DevOps Server 2019

Den här artikeln innehåller instruktioner för att köra Azure Pipelines-agenten i Docker. Du kan konfigurera en lokalt installerad agent i Azure Pipelines så att den körs i en Windows Server Core (för Windows-värdar) eller Ubuntu-container (för Linux-värdar) med Docker. Det här är användbart när du vill köra agenter med yttre orkestrering, till exempel Azure Container Instances. I den här artikeln går du igenom ett komplett containerexempel, inklusive självuppdatering av hanteringsagenten.

Både Windows och Linux stöds som containervärdar. Windows-containrar ska köras på en Windows vmImage. Om du vill köra din agent i Docker skickar du några miljövariabler till docker run, som konfigurerar agenten för att ansluta till Azure Pipelines eller Azure DevOps Server. Slutligen anpassar du containern efter dina behov. Uppgifter och skript kan bero på att specifika verktyg är tillgängliga på containerns PATH, och det är ditt ansvar att se till att dessa verktyg är tillgängliga.

Den här funktionen kräver agentversion 2.149 eller senare. Azure DevOps 2019 levereras inte med en kompatibel agentversion. Du kan dock ladda upp rätt agentpaket till programnivån om du vill köra Docker-agenter.

Windows

Aktivera Hyper-V

Hyper-V är inte aktiverat som standard i Windows. Om du vill tillhandahålla isolering mellan containrar måste du aktivera Hyper-V. Annars startar inte Docker för Windows.

Kommentar

Du måste aktivera virtualisering på datorn. Den är vanligtvis aktiverad som standard. Om Hyper-V-installationen misslyckas läser du dock systemdokumentationen för hur du aktiverar virtualisering.

Installera Docker för Windows

Om du använder Windows 10 kan du installera Docker Community Edition. Installera Docker Enterprise Edition för Windows Server 2016.

Växla Docker till att använda Windows-containrar

Som standard är Docker för Windows konfigurerat att använda Linux-containrar. Om du vill tillåta körning av Windows-containern kontrollerar du att Docker för Windows kör Windows-daemonen.

Skapa och skapa Dockerfile

Skapa sedan Dockerfile.

  1. Öppna kommandotolken.

  2. Skapa en ny katalog:

    mkdir "C:\azp-agent-in-docker\"
    
  3. Gå till den här nya katalogen:

    cd "C:\azp-agent-in-docker\"
    
  4. Spara följande innehåll i en fil med namnet 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
    
  5. Spara följande innehåll i 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})"
    }
    
  6. Kör följande kommando i katalogen:

    docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
    

    Den slutliga bilden är taggad azp-agent:windows.

Starta avbildningen

Nu när du har skapat en avbildning kan du köra en container. Detta installerar den senaste versionen av agenten, konfigurerar den och kör agenten. Den riktar sig till den angivna agentpoolen (agentpoolen Default som standard) för en angiven Azure DevOps- eller Azure DevOps Server-instans som du väljer:

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

Du kan behöva ange parametern --network om du stöter på nätverksproblem.

docker run --network "Default Switch" < . . . >

Du kan behöva ange --interactive och flagga (eller helt enkelt -it) om du vill kunna stoppa containern och ta bort agenten medCCtrl + .--tty

docker run --interactive --tty < . . . >

Om du vill ha en ny agentcontainer för varje pipelinejobb skickar --once du flaggan till run kommandot.

docker run < . . . > --once

--once Med flaggan kanske du vill använda ett containerorkestreringssystem, till exempel Kubernetes eller Azure Container Instances, för att starta en ny kopia av containern när jobbet är klart.

Du kan styra agentnamnet, agentpoolen och agentarbetskatalogen med hjälp av valfria miljövariabler.

Linux

Installera Docker

Beroende på din Linux-distribution kan du antingen installera Docker Community Edition eller Docker Enterprise Edition.

Skapa och skapa Dockerfile

Skapa sedan Dockerfile.

  1. Öppna en terminal.

  2. Skapa en ny katalog (rekommenderas):

    mkdir ~/azp-agent-in-docker/
    
  3. Gå till den här nya katalogen:

    cd ~/azp-agent-in-docker/
    
  4. Spara följande innehåll i ~/azp-agent-in-docker/azp-agent-linux.dockerfile:

    • För 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" ]
      
    • För 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" ]
      

    Avkommentar raden ENV AGENT_ALLOW_RUNASROOT="true" och ta bort lägga till agent användaren före den här raden om du vill köra agenten som rot.

    Kommentar

    Uppgifter kan bero på körbara filer som din container förväntas tillhandahålla. Du måste till exempel lägga till paketen zip RUN apt install -y och unzip i kommandot för att kunna köra aktiviteterna ArchiveFiles och ExtractFiles . Eftersom det här är en Linux Ubuntu-avbildning som agenten ska använda kan du också anpassa avbildningen efter behov. T.ex. om du behöver skapa .NET-program kan du följa dokumentet Installera .NET SDK eller .NET Runtime på Ubuntu och lägga till det i avbildningen.

  5. Spara följande innehåll i ~/azp-agent-in-docker/start.shoch se till att använda linjeslut i Unix-stil (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 $!
    

    Kommentar

    Du måste också använda ett containerorkestreringssystem, till exempel Kubernetes eller Azure Container Instances, för att starta nya kopior av containern när arbetet är klart.

  6. Kör följande kommando i katalogen:

    docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
    

    Den slutliga bilden är taggad azp-agent:linux.

Starta avbildningen

Nu när du har skapat en avbildning kan du köra en container. Detta installerar den senaste versionen av agenten, konfigurerar den och kör agenten. Den riktar sig till den angivna agentpoolen (agentpoolen Default som standard) för en angiven Azure DevOps- eller Azure DevOps Server-instans som du väljer:

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

Du kan behöva ange --interactive och flagga (eller helt enkelt -it) om du vill kunna stoppa containern och ta bort agenten medCCtrl + .--tty

docker run --interactive --tty < . . . >

Om du vill ha en ny agentcontainer för varje pipelinejobb skickar --once du flaggan till run kommandot.

docker run < . . . > --once

--once Med flaggan kanske du vill använda ett containerorkestreringssystem, till exempel Kubernetes eller Azure Container Instances, för att starta en ny kopia av containern när jobbet är klart.

Du kan styra agentnamnet, agentpoolen och agentarbetskatalogen med hjälp av valfria miljövariabler.

Miljövariabler

Miljövariabel beskrivning
AZP_URL URL:en för Azure DevOps- eller Azure DevOps Server-instansen.
AZP_TOKEN Personlig åtkomsttoken (PAT) med agentpooler (läs, hantera) omfång, som skapats av en användare som har behörighet att konfigurera agenter, på AZP_URL.
AZP_AGENT_NAME Agentnamn (standardvärde: containerns värdnamn).
AZP_POOL Agentpoolens namn (standardvärde: Default).
AZP_WORK Arbetskatalog (standardvärde: _work).

Lägga till verktyg och anpassa containern

Du har skapat en grundläggande byggagent. Du kan utöka Dockerfile till att omfatta ytterligare verktyg och deras beroenden, eller skapa en egen container med hjälp av den här som ett baslager. Se bara till att följande lämnas orörda:

  • Skriptet start.sh anropas av Dockerfile.
  • Skriptet start.sh är det sista kommandot i Dockerfile.
  • Se till att derivatcontainrar inte tar bort något av de beroenden som anges av Dockerfile.

Använda Docker i en Docker-container

För att kunna använda Docker inifrån en Docker-container binder du docker-socketen.

Varning

Att göra detta har allvarliga säkerhetskonsekvenser. Koden i containern kan nu köras som rot på Docker-värden.

Om du är säker på att du vill göra det kan du läsa dokumentationen om bindningsmonteringDocker.com.

Använda Azure Kubernetes Service-kluster

Varning

Tänk på att alla docker-baserade aktiviteter inte fungerar på AKS 1.19 eller senare på grund av docker i docker-begränsning. Docker ersattes med container i Kubernetes 1.19 och Docker-in-Docker blev otillgänglig.

Distribuera och konfigurera Azure Kubernetes Service

Följ stegen i Snabbstart: Distribuera ett AKS-kluster (Azure Kubernetes Service) med hjälp av Azure Portal. Därefter kan PowerShell- eller Shell-konsolen använda kommandoraden kubectl .

Distribuera och konfigurera Azure Container Registry

Följ stegen i Snabbstart: Skapa ett Azure-containerregister med hjälp av Azure Portal. Därefter kan du push-överföra och hämta containrar från Azure Container Registry.

Konfigurera hemligheter och distribuera en replikuppsättning

  1. Skapa hemligheterna i AKS-klustret.

    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. Kör det här kommandot för att skicka containern till Container Registry:

    docker push "<acr-server>/azp-agent:<tag>"
    
  3. Konfigurera Container Registry-integrering för befintliga AKS-kluster.

    Kommentar

    Om du har flera prenumerationer på Azure-portalen använder du det här kommandot först för att välja en prenumeration

    az account set --subscription "<subscription id or subscription name>"
    
    az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
    
  4. Spara följande innehåll i ~/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
    

    Denna Kubernetes YAML skapar en replikuppsättning och en distribution, där replicas: 1 anger antalet eller agenterna som körs i klustret.

  5. Kör följande kommando:

    kubectl apply -f ReplicationController.yml
    

Nu ska dina agenter köra AKS-klustret.

Ange anpassad MTU-parameter

Tillåt att MTU-värde anges för nätverk som används av containerjobb (användbart för docker-in-docker-scenarier i k8s-kluster).

Du måste ange miljövariabeln AGENT_DOCKER_MTU_VALUE för att ange MTU-värdet och sedan starta om den lokalt installerade agenten. Mer information om agentomstart finns här och om hur du ställer in olika miljövariabler för varje enskild agent här.

På så sätt kan du konfigurera en nätverksparameter för jobbcontainern. Användningen av det här kommandot liknar användningen av nästa kommando vid konfiguration av containernätverk:

-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE

Montera volymer med Docker i en Docker-container

Om en Docker-container körs i en annan Docker-container använder båda värdens daemon, så alla monteringssökvägar refererar till värden, inte containern.

Om vi till exempel vill montera sökvägen från värden till den yttre Docker-containern kan vi använda det här kommandot:

docker run ... -v "<path-on-host>:<path-on-outer-container>" ...

Och om vi vill montera sökvägen från värden till den inre Docker-containern kan vi använda det här kommandot:

docker run ... -v "<path-on-host>:<path-on-inner-container>" ...

Men vi kan inte montera sökvägar från den yttre containern till den inre. för att undvika detta måste vi deklarera en ENV-variabel:

docker run ... --env DIND_USER_HOME=$HOME ...

Efter detta kan vi starta den inre containern från den yttre med hjälp av det här kommandot:

docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...

Vanliga fel

Om du använder Windows och får följande fel:

standard_init_linux.go:178: exec user process caused "no such file or directory"

Installera Git Bash genom att ladda ned och installera git-scm.

Kör följande kommando:

dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push

Försök igen. Du får inte längre felet.