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.
Öppna kommandotolken.
Skapa en ny katalog:
mkdir "C:\azp-agent-in-docker\"
Gå till den här nya katalogen:
cd "C:\azp-agent-in-docker\"
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
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})" }
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 medC
Ctrl
+ .--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.
Öppna en terminal.
Skapa en ny katalog (rekommenderas):
mkdir ~/azp-agent-in-docker/
Gå till den här nya katalogen:
cd ~/azp-agent-in-docker/
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 tillagent
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
ochunzip
i kommandot för att kunna köra aktiviteternaArchiveFiles
ochExtractFiles
. 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.Spara följande innehåll i
~/azp-agent-in-docker/start.sh
och 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.
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 medC
Ctrl
+ .--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 bindningsmontering på Docker.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
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
Kör det här kommandot för att skicka containern till Container Registry:
docker push "<acr-server>/azp-agent:<tag>"
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>"
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.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.