Eseguire un agente self-hosted in Docker
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
Questo articolo fornisce istruzioni per l'esecuzione dell'agente di Azure Pipelines in Docker. È possibile configurare un agente self-hosted in Azure Pipelines per l'esecuzione in un contenitore Windows Server Core (per gli host Windows) o Ubuntu (per gli host Linux) con Docker. Ciò è utile quando si vogliono eseguire agenti con orchestrazione esterna, ad esempio Istanze di Azure Container. In questo articolo verrà illustrato un esempio completo di contenitore, inclusa la gestione dell'aggiornamento automatico dell'agente.
Sia Windows che Linux sono supportati come host contenitore. I contenitori di Windows devono essere eseguiti in windows vmImage
.
Per eseguire l'agente in Docker, si passeranno alcune variabili di ambiente a docker run
, che configura l'agente per connettersi ad Azure Pipelines o azure DevOps Server. Infine, è possibile personalizzare il contenitore in base alle proprie esigenze. Le attività e gli script possono dipendere da strumenti specifici disponibili nel contenitore ed è responsabilità dell'utente PATH
assicurarsi che questi strumenti siano disponibili.
Questa funzionalità richiede l'agente versione 2.149 o successiva. Azure DevOps 2019 non è stato fornito con una versione compatibile dell'agente. Tuttavia, è possibile caricare il pacchetto agente corretto nel livello applicazione se si vogliono eseguire agenti Docker.
Finestre
Abilita Hyper-V
Hyper-V non è abilitato per impostazione predefinita in Windows. Se si vuole fornire l'isolamento tra contenitori, è necessario abilitare Hyper-V. In caso contrario, Docker per Windows non verrà avviato.
Nota
È necessario abilitare la virtualizzazione nel computer. In genere è abilitato per impostazione predefinita. Tuttavia, se l'installazione di Hyper-V non riesce, vedere la documentazione del sistema per informazioni su come abilitare la virtualizzazione.
Installare Docker per Windows
Se si usa Windows 10, è possibile installare Docker Community Edition. Per Windows Server 2016, installare il edizione Enterprise Docker.
Passare a Docker per usare i contenitori di Windows
Per impostazione predefinita, Docker per Windows è configurato per l'uso di contenitori Linux. Per consentire l'esecuzione del contenitore windows, verificare che Docker per Windows esegua il daemon di Windows.
Creare e compilare il Dockerfile
Creare quindi il Dockerfile.
Aprire un prompt dei comandi.
Creare una nuova directory:
mkdir "C:\azp-agent-in-docker\"
Passare a questa nuova directory:
cd "C:\azp-agent-in-docker\"
Salvare il contenuto seguente in un file denominato
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
Salvare il contenuto seguente 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})" }
Eseguire il comando seguente all'interno di tale directory:
docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
L'immagine finale è contrassegnata con
azp-agent:windows
.
Avviare l'immagine
Dopo aver creato un'immagine, è possibile eseguire un contenitore. Viene installata la versione più recente dell'agente, la configura ed esegue l'agente. È destinato al pool di agenti specificato (il pool di agenti per impostazione predefinita) di un'istanza Default
di Azure DevOps o azure DevOps Server specificata a scelta:
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
Potrebbe essere necessario specificare il --network
parametro se si verificano problemi di rete.
docker run --network "Default Switch" < . . . >
Potrebbe essere necessario specificare --interactive
e --tty
flag (o semplicemente -it
) se si vuole essere in grado di arrestare il contenitore e rimuovere l'agente con Ctrl
+ C
.
docker run --interactive --tty < . . . >
Se si vuole un nuovo contenitore di agenti per ogni processo della pipeline, passare il --once
flag al run
comando .
docker run < . . . > --once
Con il --once
flag potrebbe essere necessario usare un sistema di orchestrazione dei contenitori, ad esempio Kubernetes o Istanze di Azure Container, per avviare una nuova copia del contenitore al termine del processo.
È possibile controllare il nome dell'agente, il pool di agenti e la directory di lavoro dell'agente usando variabili di ambiente facoltative.
Linux
Installare Docker
A seconda della distribuzione Linux, è possibile installare Docker Community Edition o Docker edizione Enterprise.
Creare e compilare il Dockerfile
Creare quindi il Dockerfile.
Aprire un terminale.
Creare una nuova directory (operazione consigliata):
mkdir ~/azp-agent-in-docker/
Passare a questa nuova directory:
cd ~/azp-agent-in-docker/
Salvare il contenuto seguente in
~/azp-agent-in-docker/azp-agent-linux.dockerfile
:Per 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" ]
Per 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" ]
Rimuovere il commento dalla
ENV AGENT_ALLOW_RUNASROOT="true"
riga e rimuovere l'aggiunta dell'utenteagent
prima di questa riga se si vuole eseguire l'agente come radice.Nota
Le attività possono dipendere dai file eseguibili previsti dal contenitore. Ad esempio, è necessario aggiungere i
zip
pacchetti eunzip
alRUN apt install -y
comando per eseguire leArchiveFiles
attività eExtractFiles
. Inoltre, poiché si tratta di un'immagine Linux Ubuntu da usare per l'agente, è possibile personalizzare l'immagine in base alle esigenze. Ad esempio, se è necessario compilare applicazioni .NET, è possibile seguire il documento Installare .NET SDK o .NET Runtime in Ubuntu e aggiungerlo all'immagine.Salvare il contenuto seguente in
~/azp-agent-in-docker/start.sh
, assicurandosi di usare terminazioni di riga di tipo 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 $!
Nota
È anche necessario usare un sistema di orchestrazione dei contenitori, ad esempio Kubernetes o Istanze di Azure Container, per avviare nuove copie del contenitore al termine del lavoro.
Eseguire il comando seguente all'interno di tale directory:
docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
L'immagine finale è contrassegnata con
azp-agent:linux
.
Avviare l'immagine
Dopo aver creato un'immagine, è possibile eseguire un contenitore. Viene installata la versione più recente dell'agente, la configura ed esegue l'agente. È destinato al pool di agenti specificato (il pool di agenti per impostazione predefinita) di un'istanza Default
di Azure DevOps o azure DevOps Server specificata a scelta:
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
Potrebbe essere necessario specificare --interactive
e --tty
flag (o semplicemente -it
) se si vuole essere in grado di arrestare il contenitore e rimuovere l'agente con Ctrl
+ C
.
docker run --interactive --tty < . . . >
Se si vuole un nuovo contenitore di agenti per ogni processo della pipeline, passare il --once
flag al run
comando .
docker run < . . . > --once
Con il --once
flag potrebbe essere necessario usare un sistema di orchestrazione dei contenitori, ad esempio Kubernetes o Istanze di Azure Container, per avviare una nuova copia del contenitore al termine del processo.
È possibile controllare il nome dell'agente, il pool di agenti e la directory di lavoro dell'agente usando variabili di ambiente facoltative.
Variabili di ambiente
Variabile di ambiente | Descrizione |
---|---|
AZP_URL | URL dell'istanza di Azure DevOps o azure DevOps Server. |
AZP_TOKEN | Token di accesso personale (PAT) con ambito pool di agenti (lettura, gestione), creato da un utente che dispone dell'autorizzazione per configurare gli agenti all'indirizzo AZP_URL . |
AZP_AGENT_NAME | Nome agente (valore predefinito: nome host contenitore). |
AZP_POOL | Nome pool di agenti (valore predefinito: Default ). |
AZP_WORK | Directory di lavoro (valore predefinito: _work ). |
Aggiungere strumenti e personalizzare il contenitore
È stato creato un agente di compilazione di base. È possibile estendere il Dockerfile per includere strumenti aggiuntivi e le relative dipendenze oppure creare un contenitore personalizzato usando questo file come livello di base. Assicurarsi che i seguenti elementi rimangano invariati:
- Lo
start.sh
script viene chiamato dal Dockerfile. - Lo
start.sh
script è l'ultimo comando nel Dockerfile. - Assicurarsi che i contenitori derivati non rimuovono alcuna delle dipendenze indicate dal Dockerfile.
Usare Docker all'interno di un contenitore Docker
Per usare Docker da un contenitore Docker, è necessario montare il socket Docker.
Attenzione
Questa operazione ha gravi implicazioni per la sicurezza. Il codice all'interno del contenitore può ora essere eseguito come radice nell'host Docker.
Se si è certi di voler eseguire questa operazione, vedere la documentazione sul montaggio di binding in Docker.com.
Usare servizio Azure Kubernetes cluster
Attenzione
Tenere presente che tutte le attività basate su Docker non funzioneranno nel servizio Azure Kubernetes 1.19 o versione successiva a causa di docker in restrizioni docker. Docker è stato sostituito con il contenitore in Kubernetes 1.19 e Docker-in-Docker non è più disponibile.
Distribuire e configurare servizio Azure Kubernetes
Seguire la procedura descritta in Avvio rapido: Distribuire un cluster del servizio Azure Kubernetes servizio Azure Kubernetes usando il portale di Azure. Successivamente, la console di PowerShell o Shell può usare la kubectl
riga di comando.
Distribuire e configurare Registro Azure Container
Seguire la procedura descritta in Avvio rapido: Creare un Registro Azure Container usando il portale di Azure. Successivamente, è possibile eseguire il push e il pull dei contenitori da Registro Azure Container.
Configurare i segreti e distribuire un set di repliche
Creare i segreti nel cluster del servizio Azure Kubernetes.
kubectl create secret generic azdevops \ --from-literal=AZP_URL=https://dev.azure.com/yourOrg \ --from-literal=AZP_TOKEN=YourPAT \ --from-literal=AZP_POOL=NameOfYourPool
Eseguire questo comando per eseguire il push del contenitore in Registro Contenitori:
docker push "<acr-server>/azp-agent:<tag>"
Configurare l'integrazione del Registro Container per i cluster del servizio Azure Kubernetes esistenti.
Nota
Se nel portale di Azure sono presenti più sottoscrizioni, usare prima di tutto questo comando per selezionare una sottoscrizione
az account set --subscription "<subscription id or subscription name>"
az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
Salvare il contenuto seguente 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
Questo YAML di Kubernetes crea un set di repliche e una distribuzione, dove
replicas: 1
indica il numero o gli agenti in esecuzione nel cluster.Eseguire questo comando:
kubectl apply -f ReplicationController.yml
Ora gli agenti eseguiranno il cluster del servizio Azure Kubernetes.
Impostare il parametro MTU personalizzato
Consentire di specificare il valore MTU per le reti usate dai processi del contenitore (utile per gli scenari docker in docker nel cluster k8s).
È necessario impostare la variabile di ambiente AGENT_DOCKER_MTU_VALUE per impostare il valore MTU e quindi riavviare l'agente self-hosted. Altre informazioni sul riavvio dell'agente sono disponibili qui e sull'impostazione di variabili di ambiente diverse per ogni singolo agente qui.
In questo modo è possibile configurare un parametro di rete per il contenitore di processi, l'uso di questo comando è simile all'uso del comando successivo durante la configurazione di rete del contenitore:
-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE
Montaggio di volumi tramite Docker all'interno di un contenitore Docker
Se un contenitore Docker viene eseguito all'interno di un altro contenitore Docker, entrambi usano il daemon dell'host, quindi tutti i percorsi di montaggio fanno riferimento all'host, non al contenitore.
Ad esempio, se si vuole montare il percorso dall'host al contenitore Docker esterno, è possibile usare questo comando:
docker run ... -v "<path-on-host>:<path-on-outer-container>" ...
Se si vuole montare il percorso dall'host al contenitore Docker interno, è possibile usare questo comando:
docker run ... -v "<path-on-host>:<path-on-inner-container>" ...
Ma non è possibile montare i percorsi dal contenitore esterno a quello interno; per risolvere questo problema, è necessario dichiarare una variabile ENV:
docker run ... --env DIND_USER_HOME=$HOME ...
Successivamente, è possibile avviare il contenitore interno dall'esterno usando questo comando:
docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...
Errori comuni
Se si usa Windows e viene visualizzato l'errore seguente:
standard_init_linux.go:178: exec user process caused "no such file or directory"
Installare Git Bash scaricando e installando git-scm.
Eseguire questo comando:
dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push
Riprovare. Non viene più visualizzato l'errore.