Uruchamianie własnego agenta na platformie Docker

Azure DevOps Services | Azure DevOps Server 2022 — Azure DevOps Server 2019

Ten artykuł zawiera instrukcje dotyczące uruchamiania agenta usługi Azure Pipelines na platformie Docker. Możesz skonfigurować własnego agenta w usłudze Azure Pipelines do uruchamiania w systemie Windows Server Core (dla hostów systemu Windows) lub kontenera Ubuntu (dla hostów z systemem Linux) za pomocą platformy Docker. Jest to przydatne, gdy chcesz uruchamiać agentów z orkiestracją zewnętrzną, taką jak usługa Azure Container Instances. W tym artykule przedstawiono kompletny przykład kontenera, w tym obsługę samodzielnej aktualizacji agenta.

Zarówno systemy Windows , jak i Linux są obsługiwane jako hosty kontenerów. Kontenery systemu Windows powinny działać w systemie Windows vmImage. Aby uruchomić agenta na platformie Docker, przekażesz kilka zmiennych środowiskowych do docker runprogramu , co umożliwia skonfigurowanie agenta w celu nawiązania połączenia z usługą Azure Pipelines lub serwerem Azure DevOps Server. Na koniec dostosujesz kontener do własnych potrzeb. Zadania i skrypty mogą zależeć od dostępnych narzędzi w kontenerze PATH, a Twoim zadaniem jest zapewnienie dostępności tych narzędzi.

Ta funkcja wymaga agenta w wersji 2.149 lub nowszej. Usługa Azure DevOps 2019 nie jest dostarczana z zgodną wersją agenta. Można jednak przekazać prawidłowy pakiet agenta do warstwy aplikacji, jeśli chcesz uruchomić agentów platformy Docker.

Windows

Włączanie funkcji Hyper-V

Funkcja Hyper-V nie jest domyślnie włączona w systemie Windows. Jeśli chcesz zapewnić izolację między kontenerami, musisz włączyć funkcję Hyper-V. W przeciwnym razie platforma Docker dla systemu Windows nie zostanie uruchomiona.

Uwaga

Należy włączyć wirtualizację na maszynie. Zazwyczaj jest ona domyślnie włączona. Jeśli jednak instalacja funkcji Hyper-V nie powiedzie się, zapoznaj się z dokumentacją systemu, aby dowiedzieć się, jak włączyć wirtualizację.

Instalowanie platformy Docker dla systemu Windows

Jeśli używasz systemu Windows 10, możesz zainstalować platformę Docker Community Edition. W przypadku systemu Windows Server 2016 zainstaluj platformę Docker Enterprise Edition.

Przełączanie platformy Docker do używania kontenerów systemu Windows

Domyślnie platforma Docker dla systemu Windows jest skonfigurowana do używania kontenerów systemu Linux. Aby zezwolić na uruchamianie kontenera systemu Windows, upewnij się, że platforma Docker dla systemu Windows korzysta z demona systemu Windows.

Tworzenie i kompilowanie pliku Dockerfile

Następnie utwórz plik Dockerfile.

  1. Otwórz wiersz polecenia.

  2. Utwórz nowy katalog:

    mkdir "C:\azp-agent-in-docker\"
    
  3. Przejdź do tego nowego katalogu:

    cd "C:\azp-agent-in-docker\"
    
  4. Zapisz następującą zawartość w pliku o nazwie 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. Zapisz następującą zawartość w pliku 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. Uruchom następujące polecenie w tym katalogu:

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

    Końcowy obraz jest oznaczony tagiem azp-agent:windows.

Uruchamianie obrazu

Po utworzeniu obrazu możesz uruchomić kontener. Spowoduje to zainstalowanie najnowszej wersji agenta, skonfigurowanie go i uruchomienie agenta. Jest ona przeznaczona dla określonej puli agentów ( Default domyślnie puli agentów) określonego wystąpienia usługi Azure DevOps lub wybranego wystąpienia usługi Azure DevOps Server:

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

Jeśli wystąpią problemy z siecią, może być konieczne określenie parametru --network .

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

Może być konieczne określenie --interactive flag i --tty (lub po prostu -it), jeśli chcesz zatrzymać kontener i usunąć agenta za pomocą polecenia Ctrl + C.

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

Jeśli chcesz mieć nowy kontener agenta dla każdego zadania potoku, przekaż flagę --oncerun do polecenia .

docker run < . . . > --once

Z flagą --once możesz użyć systemu aranżacji kontenerów, takiego jak Kubernetes lub Azure Container Instances, aby uruchomić nową kopię kontenera po zakończeniu zadania.

Możesz kontrolować nazwę agenta, pulę agentów i katalog roboczy agenta przy użyciu opcjonalnych zmiennych środowiskowych.

Linux

Zainstaluj platformę Docker

W zależności od dystrybucji systemu Linux można zainstalować program Docker Community Edition lub Docker Enterprise Edition.

Tworzenie i kompilowanie pliku Dockerfile

Następnie utwórz plik Dockerfile.

  1. Otwórz terminal.

  2. Utwórz nowy katalog (zalecane):

    mkdir ~/azp-agent-in-docker/
    
  3. Przejdź do tego nowego katalogu:

    cd ~/azp-agent-in-docker/
    
  4. Zapisz następującą zawartość w pliku ~/azp-agent-in-docker/azp-agent-linux.dockerfile:

    • Dla 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" ]
      
    • Dla systemu 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" ]
      

    Usuń komentarz z ENV AGENT_ALLOW_RUNASROOT="true" wiersza i usuń dodanie agent użytkownika przed tym wierszem, jeśli chcesz uruchomić agenta jako główny.

    Uwaga

    Zadania mogą zależeć od plików wykonywalnych, które powinny zostać podane w kontenerze. Na przykład należy dodać zip pakiety i unzip do RUN apt install -y polecenia , aby uruchomić ArchiveFiles zadania i ExtractFiles . Ponadto, ponieważ jest to obraz systemu Linux Ubuntu do użycia przez agenta, możesz dostosować obraz zgodnie z potrzebami. Na przykład: jeśli musisz utworzyć aplikacje .NET, możesz wykonać czynności opisane w dokumencie Instalowanie zestawu .NET SDK lub środowiska uruchomieniowego platformy .NET w systemie Ubuntu i dodawanie go do obrazu.

  5. Zapisz następującą zawartość w pliku ~/azp-agent-in-docker/start.sh, upewniając się, że używasz zakończeń wierszy w stylu 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 $!
    

    Uwaga

    Należy również użyć systemu aranżacji kontenerów, takiego jak Kubernetes lub Azure Container Instances, aby uruchomić nowe kopie kontenera po zakończeniu pracy.

  6. Uruchom następujące polecenie w tym katalogu:

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

    Końcowy obraz jest oznaczony tagiem azp-agent:linux.

Uruchamianie obrazu

Po utworzeniu obrazu możesz uruchomić kontener. Spowoduje to zainstalowanie najnowszej wersji agenta, skonfigurowanie go i uruchomienie agenta. Jest ona przeznaczona dla określonej puli agentów ( Default domyślnie puli agentów) określonego wystąpienia usługi Azure DevOps lub wybranego wystąpienia usługi Azure DevOps Server:

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

Może być konieczne określenie --interactive flag i --tty (lub po prostu -it), jeśli chcesz zatrzymać kontener i usunąć agenta za pomocą polecenia Ctrl + C.

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

Jeśli chcesz mieć nowy kontener agenta dla każdego zadania potoku, przekaż flagę --oncerun do polecenia .

docker run < . . . > --once

Z flagą --once możesz użyć systemu aranżacji kontenerów, takiego jak Kubernetes lub Azure Container Instances, aby uruchomić nową kopię kontenera po zakończeniu zadania.

Możesz kontrolować nazwę agenta, pulę agentów i katalog roboczy agenta przy użyciu opcjonalnych zmiennych środowiskowych.

Zmienne środowiskowe

Zmienna środowiskowa opis
AZP_URL Adres URL wystąpienia usługi Azure DevOps lub usługi Azure DevOps Server.
AZP_TOKEN Osobisty token dostępu (PAT) z zakresem pul agentów (odczyt, zarządzanie) utworzonym przez użytkownika, który ma uprawnienia do konfigurowania agentów pod adresem AZP_URL.
AZP_AGENT_NAME Nazwa agenta (wartość domyślna: nazwa hosta kontenera).
AZP_POOL Nazwa puli agentów (wartość domyślna: Default).
AZP_WORK Katalog roboczy (wartość domyślna: _work).

Dodawanie narzędzi i dostosowywanie kontenera

Utworzono podstawowego agenta kompilacji. Plik Dockerfile można rozszerzyć tak, aby zawierał dodatkowe narzędzia i ich zależności, lub utworzyć własny kontener przy użyciu tego pliku jako warstwy podstawowej. Upewnij się, że następujące elementy pozostają nietknięte:

  • Skrypt start.sh jest wywoływany przez plik Dockerfile.
  • Skrypt start.sh jest ostatnim poleceniem w pliku Dockerfile.
  • Upewnij się, że kontenery pochodne nie usuwają żadnych zależności określonych przez plik Dockerfile.

Korzystanie z platformy Docker w kontenerze platformy Docker

Aby można było używać platformy Docker z poziomu kontenera platformy Docker, należy zainstalować gniazdo platformy Docker.

Uwaga

Wykonanie tej czynności ma poważne konsekwencje w zakresie bezpieczeństwa. Kod wewnątrz kontenera może teraz działać jako katalog główny na hoście platformy Docker.

Jeśli na pewno chcesz to zrobić, zapoznaj się z dokumentacją dotyczącą instalacji powiązania w Docker.com.

Korzystanie z klastra usługi Azure Kubernetes Service

Uwaga

Należy wziąć pod uwagę, że żadne zadania oparte na platformie Docker nie będą działać w usłudze AKS 1.19 lub nowszym z powodu ograniczeń platformy Docker. Platforma Docker została zastąpiona kontenerem w rozwiązaniu Kubernetes 1.19, a platforma Docker-in-Docker stała się niedostępna.

Wdrażanie i konfigurowanie usługi Azure Kubernetes Service

Wykonaj kroki opisane w przewodniku Szybki start: wdrażanie klastra usługi Azure Kubernetes Service (AKS) przy użyciu witryny Azure Portal. Następnie konsola programu PowerShell lub powłoki może używać kubectl wiersza polecenia.

Wdrażanie i konfigurowanie usługi Azure Container Registry

Wykonaj kroki opisane w przewodniku Szybki start: tworzenie rejestru kontenerów platformy Azure przy użyciu witryny Azure Portal. Następnie możesz wypchnąć i ściągnąć kontenery z usługi Azure Container Registry.

Konfigurowanie wpisów tajnych i wdrażanie zestawu replik

  1. Utwórz wpisy tajne w klastrze usługi 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. Uruchom to polecenie, aby wypchnąć kontener do usługi Container Registry:

    docker push "<acr-server>/azp-agent:<tag>"
    
  3. Konfigurowanie integracji usługi Container Registry dla istniejących klastrów usługi AKS.

    Uwaga

    Jeśli masz wiele subskrypcji w witrynie Azure Portal, użyj tego polecenia najpierw, aby wybrać subskrypcję

    az account set --subscription "<subscription id or subscription name>"
    
    az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
    
  4. Zapisz następującą zawartość w pliku ~/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
    

    Ten kod YAML platformy Kubernetes tworzy zestaw replik i wdrożenie, gdzie replicas: 1 wskazuje liczbę lub agentów uruchomionych w klastrze.

  5. Uruchom następujące polecenie:

    kubectl apply -f ReplicationController.yml
    

Teraz agenci będą uruchamiać klaster usługi AKS.

Ustawianie niestandardowego parametru MTU

Zezwalaj na określanie wartości jednostki MTU dla sieci używanych przez zadania kontenera (przydatne w scenariuszach platformy Docker in-docker w klastrze k8s).

Należy ustawić zmienną środowiskową AGENT_DOCKER_MTU_VALUE, aby ustawić wartość jednostki MTU, a następnie ponownie uruchomić własnego agenta. Więcej informacji na temat ponownego uruchamiania agenta można znaleźć tutaj i o ustawianiu różnych zmiennych środowiskowych dla każdego pojedynczego agenta tutaj.

Dzięki temu można skonfigurować parametr sieciowy dla kontenera zadań. Użycie tego polecenia jest podobne do użycia następnego polecenia podczas konfigurowania sieci kontenera:

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

Instalowanie woluminów przy użyciu platformy Docker w kontenerze platformy Docker

Jeśli kontener platformy Docker działa wewnątrz innego kontenera platformy Docker, oba używają demona hosta, więc wszystkie ścieżki instalacji odwołują się do hosta, a nie kontenera.

Jeśli na przykład chcemy zainstalować ścieżkę z hosta do zewnętrznego kontenera platformy Docker, możemy użyć tego polecenia:

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

Jeśli chcemy zainstalować ścieżkę z hosta do wewnętrznego kontenera platformy Docker, możemy użyć tego polecenia:

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

Ale nie możemy zainstalować ścieżek z kontenera zewnętrznego do wewnętrznego; aby obejść ten element, musimy zadeklarować zmienną ENV:

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

Następnie możemy uruchomić kontener wewnętrzny z zewnętrznego przy użyciu następującego polecenia:

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

Typowe błędy

Jeśli używasz systemu Windows i wystąpi następujący błąd:

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

Zainstaluj powłokę Git Bash, pobierając i instalując narzędzie git-scm.

Uruchom następujące polecenie:

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

Spróbuj ponownie. Nie otrzymujesz już błędu.