Een zelf-hostende agent uitvoeren in Docker

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

Dit artikel bevat instructies voor het uitvoeren van uw Azure Pipelines-agent in Docker. U kunt een zelf-hostende agent in Azure Pipelines instellen voor uitvoering in een Windows Server Core (voor Windows-hosts) of Ubuntu-container (voor Linux-hosts) met Docker. Dit is handig als u agents wilt uitvoeren met buitenste indeling, zoals Azure Container Instances. In dit artikel doorloopt u een volledig containervoorbeeld, waaronder het afhandelen van zelfupdates van agents.

Zowel Windowsals Linux worden ondersteund als containerhosts. Windows-containers moeten worden uitgevoerd op een Windows vmImage. Als u uw agent wilt uitvoeren in Docker, geeft u enkele omgevingsvariabelen door aan docker run, waarmee de agent wordt geconfigureerd om verbinding te maken met Azure Pipelines of Azure DevOps Server. Ten slotte past u de container aan uw behoeften aan. Taken en scripts kunnen afhankelijk zijn van specifieke hulpprogramma's die beschikbaar zijn voor de container PATHen het is uw verantwoordelijkheid om ervoor te zorgen dat deze hulpprogramma's beschikbaar zijn.

Voor deze functie is agentversie 2.149 of hoger vereist. Azure DevOps 2019 is niet geleverd met een compatibele agentversie. U kunt echter het juiste agentpakket uploaden naar uw toepassingslaag als u Docker-agents wilt uitvoeren.

Windows

Hyper-V inschakelen

Hyper-V is niet standaard ingeschakeld in Windows. Als u isolatie tussen containers wilt bieden, moet u Hyper-V inschakelen. Anders wordt Docker voor Windows niet gestart.

Notitie

U moet virtualisatie op uw computer inschakelen. Deze functie is doorgaans standaard ingeschakeld. Als de Hyper-V-installatie echter mislukt, raadpleegt u de systeemdocumentatie voor het inschakelen van virtualisatie.

Docker voor Windows installeren

Als u Windows 10 gebruikt, kunt u de Docker Community Edition installeren. Installeer de Docker Enterprise Edition voor Windows Server 2016.

Docker overschakelen naar het gebruik van Windows-containers

Docker voor Windows is standaard geconfigureerd voor het gebruik van Linux-containers. Als u het uitvoeren van de Windows-container wilt toestaan, controleert u of Docker voor Windows de Windows-daemon uitvoert.

Het Dockerfile maken en bouwen

Maak vervolgens het Dockerfile.

  1. Open een opdrachtprompt.

  2. Maak een nieuwe map:

    mkdir "C:\azp-agent-in-docker\"
    
  3. Ga naar deze nieuwe map:

    cd "C:\azp-agent-in-docker\"
    
  4. Sla de volgende inhoud op in een bestand met de naam 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. Sla de volgende inhoud op in 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. Voer de volgende opdracht uit in die map:

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

    De uiteindelijke afbeelding is getagd azp-agent:windows.

De afbeelding starten

Nu u een installatiekopieën hebt gemaakt, kunt u een container uitvoeren. Hiermee wordt de nieuwste versie van de agent geïnstalleerd, geconfigureerd en wordt de agent uitgevoerd. Deze is gericht op de opgegeven agentgroep (standaard de Default agentgroep) van een opgegeven Azure DevOps- of Azure DevOps Server-exemplaar van uw keuze:

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

Mogelijk moet u de --network parameter opgeven als u netwerkproblemen ondervindt.

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

Mogelijk moet u opgeven --interactive en vlaggen (of gewoon -it) als u de container wilt stoppen en de agent wilt verwijderen met Ctrl + C.--tty

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

Als u een nieuwe agentcontainer voor elke pijplijntaak wilt, geeft u de --once vlag door aan de run opdracht.

docker run < . . . > --once

Met de --once vlag kunt u een containerindelingssysteem, zoals Kubernetes of Azure Container Instances, gebruiken om een nieuwe kopie van de container te starten wanneer de taak is voltooid.

U kunt de agentnaam, de agentgroep en de werkmap van de agent beheren met behulp van optionele omgevingsvariabelen.

Linux

Docker installeren

Afhankelijk van uw Linux-distributie kunt u Docker Community Edition of Docker Enterprise Edition installeren.

Het Dockerfile maken en bouwen

Maak vervolgens het Dockerfile.

  1. Open een terminal.

  2. Een nieuwe map maken (aanbevolen):

    mkdir ~/azp-agent-in-docker/
    
  3. Ga naar deze nieuwe map:

    cd ~/azp-agent-in-docker/
    
  4. Sla de volgende inhoud op in ~/azp-agent-in-docker/azp-agent-linux.dockerfile:

    • Voor Alpine:

      FROM alpine
      
      RUN apk update
      RUN apk upgrade
      RUN apk add bash curl git icu-libs jq
      
      ENV TARGETARCH="linux-musl-x64"
      
      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" ]
      
    • Voor Ubuntu 22.04:

      FROM ubuntu:22.04
      
      RUN apt update -y && apt upgrade -y && apt install curl git jq libicu70 -y
      
      # Also can be "linux-arm", "linux-arm64".
      ENV TARGETARCH="linux-x64"
      
      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" ]
      

    Verwijder opmerkingen bij de ENV AGENT_ALLOW_RUNASROOT="true" regel en verwijder het toevoegen van de agent gebruiker vóór deze regel als u de agent als hoofdmap wilt uitvoeren.

    Notitie

    Taken zijn mogelijk afhankelijk van uitvoerbare bestanden die naar verwachting door uw container worden verstrekt. U moet bijvoorbeeld de zip en unzip pakketten toevoegen aan de RUN apt install -y opdracht om de ArchiveFiles en ExtractFiles taken uit te voeren. Omdat dit een Linux Ubuntu-installatiekopie is die door de agent moet worden gebruikt, kunt u de installatiekopie naar wens aanpassen. Bijvoorbeeld: als u .NET-toepassingen wilt bouwen, kunt u het document De .NET SDK of de .NET Runtime op Ubuntu volgen en deze toevoegen aan uw installatiekopie.

  5. Sla de volgende inhoud ~/azp-agent-in-docker/start.shop in, zorg ervoor dat u einden van unix-stijl (LF) gebruikt:

    #!/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 $!
    

    Notitie

    U moet ook een containerindelingssysteem, zoals Kubernetes of Azure Container Instances, gebruiken om nieuwe kopieën van de container te starten wanneer het werk is voltooid.

  6. Voer de volgende opdracht uit in die map:

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

    De uiteindelijke afbeelding is getagd azp-agent:linux.

De afbeelding starten

Nu u een installatiekopieën hebt gemaakt, kunt u een container uitvoeren. Hiermee wordt de nieuwste versie van de agent geïnstalleerd, geconfigureerd en wordt de agent uitgevoerd. Deze is gericht op de opgegeven agentgroep (standaard de Default agentgroep) van een opgegeven Azure DevOps- of Azure DevOps Server-exemplaar van uw keuze:

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

Mogelijk moet u opgeven --interactive en vlaggen (of gewoon -it) als u de container wilt stoppen en de agent wilt verwijderen met Ctrl + C.--tty

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

Als u een nieuwe agentcontainer voor elke pijplijntaak wilt, geeft u de --once vlag door aan de run opdracht.

docker run < . . . > --once

Met de --once vlag kunt u een containerindelingssysteem, zoals Kubernetes of Azure Container Instances, gebruiken om een nieuwe kopie van de container te starten wanneer de taak is voltooid.

U kunt de agentnaam, de agentgroep en de werkmap van de agent beheren met behulp van optionele omgevingsvariabelen.

Omgevingsvariabelen

Omgevingsvariabele Omschrijving
AZP_URL De URL van het Azure DevOps- of Azure DevOps Server-exemplaar.
AZP_TOKEN Persoonlijk toegangstoken (PAT) met agentgroepen (lezen, beheren) bereik, gemaakt door een gebruiker die gemachtigd is om agents te configureren op AZP_URL.
AZP_AGENT_NAME Agentnaam (standaardwaarde: de hostnaam van de container).
AZP_POOL Naam van agentgroep (standaardwaarde: Default).
AZP_WORK Werkmap (standaardwaarde: _work).

Hulpprogramma's toevoegen en de container aanpassen

U hebt een eenvoudige buildagent gemaakt. U kunt het Dockerfile uitbreiden met extra hulpprogramma's en hun afhankelijkheden, of uw eigen container bouwen met behulp van deze als basislaag. Zorg ervoor dat het volgende ongewijzigd blijft:

  • Het start.sh script wordt aangeroepen door het Dockerfile.
  • Het start.sh script is de laatste opdracht in het Dockerfile.
  • Zorg ervoor dat afgeleide containers geen van de afhankelijkheden verwijderen die zijn opgegeven door het Dockerfile.

Docker gebruiken in een Docker-container

Als u Docker wilt gebruiken vanuit een Docker-container, koppelt u de Docker-socket.

Let op

Dit heeft ernstige gevolgen voor de beveiliging. De code in de container kan nu worden uitgevoerd als root op uw Docker-host.

Als u zeker weet dat u dit wilt doen, raadpleegt u de bindingskoppelingsdocumentatie op Docker.com.

Azure Kubernetes Service-cluster gebruiken

Let op

Houd er rekening mee dat alle docker-taken niet werken op AKS 1.19 of hoger vanwege docker in docker-beperking. Docker is vervangen door containers in Kubernetes 1.19 en Docker-in-Docker is niet meer beschikbaar.

Azure Kubernetes Service implementeren en configureren

Volg de stappen in quickstart: Een AKS-cluster (Azure Kubernetes Service) implementeren met behulp van Azure Portal. Hierna kan uw PowerShell- of Shell-console de kubectl opdrachtregel gebruiken.

Azure Container Registry implementeren en configureren

Volg de stappen in quickstart: Een Azure-containerregister maken met behulp van Azure Portal. Hierna kunt u containers pushen en ophalen uit Azure Container Registry.

Geheimen configureren en een replicaset implementeren

  1. Maak de geheimen in het AKS-cluster.

    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. Voer deze opdracht uit om uw container naar Container Registry te pushen:

    docker push "<acr-server>/azp-agent:<tag>"
    
  3. Container Registry-integratie configureren voor bestaande AKS-clusters.

    Notitie

    Als u meerdere abonnementen in Azure Portal hebt, gebruikt u deze opdracht eerst om een abonnement te selecteren

    az account set --subscription "<subscription id or subscription name>"
    
    az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
    
  4. Sla de volgende inhoud op in ~/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
    

    Met deze Kubernetes YAML maakt u een replicaset en een implementatie, waarbij replicas: 1 het aantal of de agents worden aangegeven die op het cluster worden uitgevoerd.

  5. Voer deze opdracht uit:

    kubectl apply -f ReplicationController.yml
    

Uw agents voeren nu het AKS-cluster uit.

Aangepaste MTU-parameter instellen

Geef MTU-waarde op voor netwerken die door containertaken worden gebruikt (handig voor docker-in-docker-scenario's in k8s-cluster).

U moet de omgevingsvariabele instellen AGENT_DOCKER_MTU_VALUE om de MTU-waarde in te stellen en de zelf-hostende agent opnieuw op te starten. Hier vindt u meer informatie over het opnieuw opstarten van agents en over het instellen van verschillende omgevingsvariabelen voor elke afzonderlijke agent.

Hiermee kunt u een netwerkparameter instellen voor de taakcontainer. Het gebruik van deze opdracht is vergelijkbaar met het gebruik van de volgende opdracht terwijl de containernetwerkconfiguratie:

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

Volumes koppelen met Docker in een Docker-container

Als een Docker-container wordt uitgevoerd in een andere Docker-container, gebruiken ze beide de daemon van de host, zodat alle koppelpaden verwijzen naar de host, niet naar de container.

Als we bijvoorbeeld het pad van de host willen koppelen aan de buitenste Docker-container, kunnen we deze opdracht gebruiken:

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

En als we het pad van de host willen koppelen aan de binnenste Docker-container, kunnen we deze opdracht gebruiken:

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

Maar we kunnen geen paden van de buitenste container koppelen aan de binnenste container; om dit te omzeilen, moeten we een ENV-variabele declareren:

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

Hierna kunnen we de binnenste container starten vanuit de buitenste container met behulp van deze opdracht:

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

Algemene fouten

Als u Windows gebruikt en de volgende fout wordt weergegeven:

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

Installeer Git Bash door git-scm te downloaden en te installeren.

Voer deze opdracht uit:

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

Probeer het opnieuw. U krijgt de fout niet meer.