Ausführen eines selbstgehosteten Agents in Docker
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019
Dieser Artikel enthält Anweisungen zum Ausführen Ihres Azure Pipelines-Agents in Docker. Sie können in Azure Pipelines einen selbstgehosteten Agent einrichten, der in Windows Server Core (für Windows-Hosts) oder in einem Ubuntu-Container (für Linux-Hosts) mit Docker ausgeführt wird. Dies ist nützlich, wenn Sie Agents mit äußerer Orchestrierung ausführen möchten, z. B. Azure Container Instances. In diesem Artikel werden Sie ein vollständiges Containerbeispiel durcharbeiten, einschließlich der Selbstaktualisierung des Agents.
Sowohl Windows als auch Linux werden als Containerhosts unterstützt. Windows-Container sollten unter einem Windows-vmImage
ausgeführt werden.
Um Ihren Agent in Docker auszuführen, übergeben Sie einige Umgebungsvariablen an docker run
, wodurch der Agent für die Verbindung mit Azure Pipelines oder Azure DevOps Server konfiguriert wird. Schließlich passen Sie den Container an Ihre Anforderungen an. Tasks und Skripts hängen möglicherweise davon ab, dass bestimmte Tools im PATH
des Containers verfügbar sind. Es liegt in Ihrer Verantwortung, sicherzustellen, dass diese Tools verfügbar sind.
Für dieses Feature ist die Agent-Version 2.149 oder höher erforderlich. Azure DevOps 2019 wurde nicht mit einer kompatiblen Agent-Version ausgeliefert. Sie können jedoch das richtige Agent-Paket auf Ihre Anwendungsebene hochladen, wenn Sie Docker-Agents ausführen möchten.
Windows
Aktivieren von Hyper-V
Hyper-V ist unter Windows nicht standardmäßig aktiviert. Wenn Sie Isolierung zwischen Containern bereitstellen möchten, müssen Sie Hyper-V aktivieren. Andernfalls wird Docker für Windows nicht gestartet.
Hinweis
Sie müssen Virtualisierung auf Ihrem Computer aktivieren. Diese ist in der Regel standardmäßig aktiviert. Wenn bei der Installation von Hyper-V jedoch ein Fehler auftritt, können Sie in der Dokumentation Ihres Betriebssystems nachlesen, wie Sie die Virtualisierung aktivieren.
Installieren von Docker für Windows
Wenn Sie Windows 10 verwenden, können Sie die Docker Community Edition installieren. Installieren Sie für Windows Server 2016 die Docker Enterprise Edition.
Umstellen von Docker auf die Verwendung von Windows-Containern
Standardmäßig ist Docker für Windows für die Verwendung von Linux-Containern konfiguriert. Um die Ausführung des Windows-Containers zuzulassen, vergewissern Sie sich, dass Docker für Windows den Windows-Daemon ausführt.
Erstellen und Kompilieren der Dockerfile-Datei
Erstellen Sie nun die Dockerfile-Datei.
Öffnen Sie eine Eingabeaufforderung.
Erstellen Sie ein neues Verzeichnis:
mkdir "C:\azp-agent-in-docker\"
Wechseln Sie zu diesem neuen Verzeichnis:
cd "C:\azp-agent-in-docker\"
Speichern Sie den folgenden Inhalt in einer Datei namens
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
Speichern Sie den folgendem Inhalt unter
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})" }
Führen Sie den folgenden Befehl innerhalb diesed Verzeichnisses aus:
docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
Das endgültige Image wird als
azp-agent:windows
markiert.
Starten des Images
Nachdem Sie nun ein Image erstellt haben, können Sie einen Container ausführen. Dadurch wird die neueste Version des Agents installiert, der Agent konfiguriert und dann ausgeführt. Das Ziel ist der angegebene Agentpool (standardmäßig Default
) einer angegebenen Azure DevOps- oder Azure DevOps Server-Instanz Ihrer Wahl:
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
Bei Netzwerkproblemen müssen Sie möglicherweise den --network
-Parameter angeben.
docker run --network "Default Switch" < . . . >
Wenn Sie den Container beenden und den Agent mit --interactive
--tty
-it
entfernen möchten, müssen Sie möglicherweise die Flags Ctrl
und + oder einfach C
angeben.
docker run --interactive --tty < . . . >
Wenn Sie einen neuen Agent-Container für jeden Pipelineauftrag benötigen, übergeben Sie das --once
-Flag an den run
-Befehl.
docker run < . . . > --once
Sie sollten mit dem --once
-Flag ein Containerorchestrierungssystem wie Kubernetes oder Azure Container Instances verwenden, um nach Abschluss des Auftrags eine neue Kopie des Containers zu starten.
Sie können den Namen und Pool sowie das Arbeitsverzeichnis des Agents mithilfe optionaler Umgebungsvariablen steuern.
Linux
Installieren von Docker
Abhängig von Ihrer Linux-Distribution können Sie entweder Docker Community Edition oder Docker Enterprise Edition installieren.
Erstellen und Kompilieren der Dockerfile-Datei
Erstellen Sie nun die Dockerfile-Datei.
Öffnen Sie ein Terminal.
Erstellen Sie ein neues Verzeichnis (empfohlen):
mkdir ~/azp-agent-in-docker/
Wechseln Sie zu diesem neuen Verzeichnis:
cd ~/azp-agent-in-docker/
Speichern Sie den folgendem Inhalt unter
~/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" ]
Heben Sie die Auskommentierung der Zeile
ENV AGENT_ALLOW_RUNASROOT="true"
auf, und fügen Sie den oder dieagent
-Benutzer*in vor dieser Zeile ein, wenn Sie den Agent mit root-Berechtigungen ausführen möchten.Hinweis
Tasks können von ausführbaren Dateien abhängen, die von Ihrem Container bereitgestellt werden sollen. Beispielsweise müssen Sie dem
RUN apt install -y
-Befehl diezip
- undunzip
-Pakete hinzufügen, um dieArchiveFiles
- undExtractFiles
-Tasks auszuführen. Da dies ein Linux Ubuntu-Image für den Agent ist, können Sie das Image nach Bedarf anpassen. Wenn Sie z. B. .NET-Anwendungen erstellen müssen, können Sie das Dokument Installieren des .NET SDK oder der .NET-Runtime unter Ubuntu verwenden und Ihrem Image diese Elemente hinzufügen.Speichern Sie den folgenden Inhalt unter
~/azp-agent-in-docker/start.sh
, und stellen Sie sicher, dass Zeilenvorschübe im Unix-Stil (LF) verwendet werden:#!/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 $!
Hinweis
Sie müssen auch ein Containerorchestrierungssystem wie Kubernetes oder Azure Container Instances verwenden, um nach Abschluss der Aufgabe neue Kopien des Containers zu starten.
Führen Sie den folgenden Befehl innerhalb diesed Verzeichnisses aus:
docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
Das endgültige Image wird als
azp-agent:linux
markiert.
Starten des Images
Nachdem Sie nun ein Image erstellt haben, können Sie einen Container ausführen. Dadurch wird die neueste Version des Agents installiert, der Agent konfiguriert und dann ausgeführt. Das Ziel ist der angegebene Agentpool (standardmäßig Default
) einer angegebenen Azure DevOps- oder Azure DevOps Server-Instanz Ihrer Wahl:
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
Wenn Sie den Container beenden und den Agent mit --interactive
--tty
-it
entfernen möchten, müssen Sie möglicherweise die Flags Ctrl
und + oder einfach C
angeben.
docker run --interactive --tty < . . . >
Wenn Sie einen neuen Agent-Container für jeden Pipelineauftrag benötigen, übergeben Sie das --once
-Flag an den run
-Befehl.
docker run < . . . > --once
Sie sollten mit dem --once
-Flag ein Containerorchestrierungssystem wie Kubernetes oder Azure Container Instances verwenden, um nach Abschluss des Auftrags eine neue Kopie des Containers zu starten.
Sie können den Namen und Pool sowie das Arbeitsverzeichnis des Agents mithilfe optionaler Umgebungsvariablen steuern.
Umgebungsvariablen
Umgebungsvariable | BESCHREIBUNG |
---|---|
AZP_URL | Die URL der Azure DevOps- oder Azure DevOps Server-Instanz. |
AZP_TOKEN | Persönliches Zugriffstoken (Personal Access Token, PAT) mit Agent-Poolbereich (Lesen, Verwalten), erstellt von einem Benutzer, der über die Berechtigung zum Konfigurieren von Agents verfügt, unter AZP_URL . |
AZP_AGENT_NAME | Der Agent-Name (Standardwert: der Containerhostname). |
AZP_POOL | Der Name des Agent-Pools (Standardwert: Default ). |
AZP_WORK | Das Arbeitsverzeichnis (Standardwert: _work ). |
Hinzufügen von Tools und Anpassen des Containers
Sie haben einen einfachen Build-Agent erstellt. Sie können die Dockerfile-Datei erweitern, um zusätzliche Tools und deren Abhängigkeiten einzuschließen, oder Ihren eigenen Container erstellen, indem Sie diesen Container als Basisebene verwenden. Stellen Sie nur sicher, dass Folgendes unberührt bleibt:
- Das
start.sh
-Skript wird von der Dockerfile-Datei aufgerufen. - Das
start.sh
-Skript ist der letzte Befehl in der Dockerfile-Datei. - Stellen Sie sicher, dass abgeleitete Containern keine der Abhängigkeiten entfernen, die in der Dockerfile-Datei angegeben werden.
Verwenden von Docker in einem Docker-Container
Um Docker aus einem Docker-Container zu verwenden, binden Sie den Docker-Socket ein (bind-mount).
Achtung
Dies hat schwerwiegende Auswirkungen auf die Sicherheit. Der Code im Container kann jetzt als Stammverzeichnis auf Ihrem Docker-Host ausgeführt werden.
Wenn Sie sicher sind, dass Sie so vorgehen möchten, lesen Sie die Dokumentation zu bind-mount auf Docker.com.
Verwenden eines Azure Kubernetes Service-Clusters
Achtung
Beachten Sie unbedingt, dass Docker-basierte Aufgaben aufgrund einer Docker-in-Docker-Einschränkung nicht unter AKS 1.19 oder höher funktionieren. Docker wurde in Kubernetes 1.19 durch containerd ersetzt, und Docker-in-Docker war nicht mehr verfügbar.
Bereitstellen und Konfigurieren von Azure Kubernetes Service
Führen Sie die Schritte unter Schnellstart: Bereitstellen eines AKS-Clusters (Azure Kubernetes Service) mithilfe des Azure-Portal aus. Danach kann Ihre PowerShell- oder Shell-Konsole die kubectl
-Befehlszeile verwenden.
Bereitstellen und Konfigurieren von Azure Container Registry
Befolgen Sie die unter Schnellstart: Erstellen einer Azure-Containerregistrierung über das Azure-Portal beschriebenen Schritte. Danach können Sie Container in Azure Container Registry pushen und daraus pullen.
Konfigurieren von Geheimnissen und Bereitstellen einer Replikatgruppe
Erstellen Sie die Geheimnisse im 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
Führen Sie diesen Befehl aus, um Ihren Container in Container Registry zu pushen:
docker push "<acr-server>/azp-agent:<tag>"
Konfigurieren Sie Container Registry-Integration für vorhandene AKS-Cluster.
Hinweis
Wenn Sie über mehrere Abonnements im Azure-Portal verfügen, verwenden Sie zunächst diesen Befehl, um ein Abonnement auszuwählen.
az account set --subscription "<subscription id or subscription name>"
az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
Speichern Sie den folgendem Inhalt unter
~/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
Dieser Kubernetes-YAML-Code erstellt eine Replikatgruppe und eine Bereitstellung, wobei
replicas: 1
die Anzahl oder die Agents angibt, die im Cluster ausgeführt werden.Führen Sie diesen Befehl aus:
kubectl apply -f ReplicationController.yml
Jetzt führen Ihre Agents den AKS-Cluster aus.
Festlegen des benutzerdefinierten MTU-Parameters
Zulassen der Angabe des MTU-Werts für Netzwerke, die von Containeraufträgen verwendet werden (nützlich für Docker-in-Docker-Szenarien im k8s-Cluster).
Sie müssen die Umgebungsvariable AGENT_DOCKER_MTU_VALUE festlegen, um den MTU-Wert festzulegen, und den selbstgehosteten Agent dann neu starten. Weitere Informationen zum Neustart des Agents finden Sie hier und zum Festlegen verschiedener Umgebungsvariablen für jeden einzelnen Agent hier.
Dadurch können Sie einen Netzwerkparameter für den Auftragscontainer einrichten. Die Verwendung dieses Befehls ähnelt der Verwendung des nächsten Befehls während der Konfiguration des Containernetzwerks:
-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE
Einbinden von Volumes mithilfe von Docker in einem Docker-Container
Wenn ein Docker-Container in einem anderen Docker-Container ausgeführt wird, verwenden beide den Daemon des Hosts, sodass alle Einbindungspfade auf den Host und nicht auf den Container verweisen.
Wenn Sie beispielsweise den Pfad vom Host in einen äußeren Docker-Container einbinden möchten, können Sie diesen Befehl verwenden:
docker run ... -v "<path-on-host>:<path-on-outer-container>" ...
Wenn Sie den Pfad vom Host in einen inneren Docker-Container einbinden möchten, können Sie diesen Befehl verwenden:
docker run ... -v "<path-on-host>:<path-on-inner-container>" ...
Sie können jedoch keine Pfade aus dem äußeren Container in den inneren Container einbinden. Um dieses Problem zu umgehen, müssen Sie eine ENV-Variable deklarieren:
docker run ... --env DIND_USER_HOME=$HOME ...
Danach können Sie den inneren Container mit dem folgenden Befehl aus dem äußeren Container starten:
docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...
Häufige Fehler
Wenn Sie Windows verwenden und der folgende Fehler angezeigt wird:
standard_init_linux.go:178: exec user process caused "no such file or directory"
Installieren Sie Git Bash, indem Sie git-scm herunterladen und installieren.
Führen Sie diesen Befehl aus:
dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push
Versuchen Sie es erneut. Sie erhalten diesen Fehler nicht mehr.