Exécuter un agent autohébergé dans Docker
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019
Cet article fournit des instructions pour l’exécution de votre agent Azure Pipelines dans Docker. Vous pouvez configurer un agent autohébergé dans Azure Pipelines pour qu’il s’exécute dans un conteneur Windows Server Core (pour les hôtes Windows) ou Ubuntu Container (pour les hôtes Linux) avec Docker. Cela est utile lorsque vous souhaitez exécuter des agents avec une orchestration externe, comme Azure Container Instances. Dans cet article, vous allez parcourir un exemple de conteneur complet, y compris la gestion de la mise à jour automatique de l’agent.
Windows et Linux sont tous deux pris en charge en tant qu’hôtes de conteneur. Les conteneurs Windows doivent s’exécuter sur un Windows vmImage
.
Pour exécuter votre agent dans Docker, vous allez passer quelques variables d’environnement à docker run
, ce qui configure l’agent pour qu’il se connecte à Azure Pipelines ou Azure DevOps Server. Enfin, vous personnalisez le conteneur en fonction de vos besoins. Les tâches et les scripts peuvent dépendre de la disponibilité d’outils PATH
spécifiques sur le conteneur, et il est de votre responsabilité de vous assurer que ces outils sont disponibles.
Cette fonctionnalité nécessite la version de l’agent 2.149 ou ultérieure. Azure DevOps 2019 n’a pas été fourni avec une version d’agent compatible. Toutefois, vous pouvez charger le package d’agent approprié dans votre couche Application si vous souhaitez exécuter des agents Docker.
Windows
Activer Hyper-V
Hyper-V n’est pas activé par défaut sur Windows. Si vous souhaitez fournir une isolation entre les conteneurs, vous devez activer Hyper-V. Sinon, Docker pour Windows ne démarre pas.
Notes
Vous devez activer la virtualisation sur votre machine. Elle est généralement activée par défaut. Toutefois, si l’installation d’Hyper-V échoue, reportez-vous à la documentation de votre système pour savoir comment activer la virtualisation.
Installer Docker pour Windows
Si vous utilisez Windows 10, vous pouvez installer Docker Community Edition. Pour Windows Server 2016, installez l’Êdition Entreprise Docker.
Basculer Docker pour utiliser des conteneurs Windows
Par défaut, Docker pour Windows est configuré pour utiliser des conteneurs Linux. Pour autoriser l’exécution du conteneur Windows, vérifiez que Docker pour Windows exécute le démon Windows.
Créer et générer le fichier Dockerfile
Puis, créer le Dockerfile.
Ouvrez une invite de commandes.
Créez un nouveau répertoire :
mkdir "C:\azp-agent-in-docker\"
Allez dans ce nouveau répertoire :
cd "C:\azp-agent-in-docker\"
Enregistrez le contenu suivant dans un fichier appelé
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
Enregistrez le contenu suivant dans
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})" }
Exécutez la commande suivante dans ce répertoire :
docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
L’image finale est balisée
azp-agent:windows
.
Démarrer l’image
Maintenant que vous avez créé une image, vous pouvez exécuter un conteneur. Cette opération installe la dernière version de l’agent, la configure et exécute l’agent. Il cible le pool d’agents spécifié (le pool d’agents Default
par défaut) d’une instance Azure DevOps ou Azure DevOps Server spécifiée de votre choix :
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
Vous devrez peut-être spécifier le paramètre --network
si vous rencontrez des problèmes de réseau.
docker run --network "Default Switch" < . . . >
Vous devrez peut-être spécifier les flags --interactive
and --tty
(ou simplement -it
) si vous souhaitez pouvoir arrêter le conteneur et supprimer l'agent avec Ctrl
+ C
.
docker run --interactive --tty < . . . >
Si vous souhaitez un nouveau conteneur d'agent pour chaque tâche de pipeline, transmettez l'--once
indicateur à la commande run
.
docker run < . . . > --once
Avec l'indicateur --once
, vous souhaiterez peut-être utiliser un système d'orchestration de conteneur, comme Kubernetes ou Azure Container Instances, pour démarrer une nouvelle copie du conteneur une fois la tâche terminée.
Vous pouvez contrôler le nom de l'agent, le pool d'agents et le répertoire de travail de l'agent à l'aide de variables d'environnement facultatives.
Linux
Installation de Docker
Selon votre distribution Linux, vous pouvez installer Docker Community Edition ou Docker Êdition Entreprise.
Créer et générer le fichier Dockerfile
Puis, créer le Dockerfile.
Ouvrez un terminal.
Créez un répertoire (recommandé) :
mkdir ~/azp-agent-in-docker/
Allez dans ce nouveau répertoire :
cd ~/azp-agent-in-docker/
Enregistrez le contenu suivant dans
~/azp-agent-in-docker/azp-agent-linux.dockerfile
:Pour 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" ]
Pour 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" ]
Décommentez la ligne
ENV AGENT_ALLOW_RUNASROOT="true"
et supprimez l'ajout de l'utilisateuragent
avant cette ligne si vous souhaitez exécuter l'agent en tant que root.Remarque
Les tâches peuvent dépendre des exécutables que votre conteneur est censé fournir. Pour instance, vous devez ajouter les packages
zip
etunzip
à la commande afin d’exécuter lesRUN apt install -y
tâchesArchiveFiles
etExtractFiles
. En outre, comme il s’agit d’une image Linux Ubuntu que l’agent doit utiliser, vous pouvez personnaliser l’image selon vos besoins. Par exemple, si vous avez besoin de créer des applications .NET, vous pouvez suivre le document Installer le SDK .NET ou le runtime .NET sur Ubuntu et l’ajouter à votre image.Enregistrez le contenu suivant dans
~/azp-agent-in-docker/start.sh
, en veillant à utiliser des fins de ligne de style 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 $!
Notes
Vous devez également utiliser un système d’orchestration de conteneur, comme Kubernetes ou Azure Container Instances, pour démarrer de nouvelles copies du conteneur une fois le travail terminé.
Exécutez la commande suivante dans ce répertoire :
docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
L’image finale est balisée
azp-agent:linux
.
Démarrer l’image
Maintenant que vous avez créé une image, vous pouvez exécuter un conteneur. Cette opération installe la dernière version de l’agent, la configure et exécute l’agent. Il cible le pool d’agents spécifié (le pool d’agents Default
par défaut) d’une instance Azure DevOps ou Azure DevOps Server spécifiée de votre choix :
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
Vous devrez peut-être spécifier les flags --interactive
and --tty
(ou simplement -it
) si vous souhaitez pouvoir arrêter le conteneur et supprimer l'agent avec Ctrl
+ C
.
docker run --interactive --tty < . . . >
Si vous souhaitez un nouveau conteneur d'agent pour chaque tâche de pipeline, transmettez l'--once
indicateur à la commande run
.
docker run < . . . > --once
Avec l'indicateur --once
, vous souhaiterez peut-être utiliser un système d'orchestration de conteneur, comme Kubernetes ou Azure Container Instances, pour démarrer une nouvelle copie du conteneur une fois la tâche terminée.
Vous pouvez contrôler le nom de l'agent, le pool d'agents et le répertoire de travail de l'agent à l'aide de variables d'environnement facultatives.
Variables d'environnement
Variable d’environnement | Description |
---|---|
AZP_URL | URL de l’instance Azure DevOps ou Azure DevOps Server. |
AZP_TOKEN | Jeton d’accès personnel (PAT) avec étendue Pools d’agents (lecture, gestion), créé par un utilisateur autorisé à configurer des agents, à AZP_URL . |
AZP_AGENT_NAME | Nom de l’agent (valeur par défaut : nom d’hôte du conteneur). |
AZP_POOL | Nom du pool d’agents (valeur par défaut : Default ). |
AZP_WORK | Répertoire de travail (valeur par défaut : _work ). |
Ajouter des outils et personnaliser le conteneur
Vous avez créé un agent de build de base. Vous pouvez étendre le fichier Dockerfile pour inclure des outils supplémentaires et leurs dépendances, ou créer votre propre conteneur en utilisant celui-ci comme couche de base. Assurez-vous simplement que les éléments suivants ne sont pas modifiés :
- Le
start.sh
script est appelé par le fichier Dockerfile. - Le
start.sh
script est la dernière commande dans le fichier Dockerfile. - Assurez-vous que les conteneurs dérivés ne suppriment aucune des dépendances indiquées par le fichier Dockerfile.
Utiliser Docker dans un conteneur Docker
Pour utiliser Docker à partir d’un conteneur Docker, vous devez lier-monter le socket Docker.
Attention
Cela a de graves implications en matière de sécurité. Le code à l’intérieur du conteneur peut désormais s’exécuter en tant que racine sur votre hôte Docker.
Si vous êtes sûr de vouloir effectuer cette opération, consultez la documentation sur le montage lié sur Docker.com.
Utiliser un cluster Azure Kubernetes Service
Attention
Veuillez considérer que les tâches basées sur Docker ne fonctionneront pas sur AKS 1.19 ou version ultérieure en raison de la restriction Docker dans Docker. Docker a été remplacé par conteneur dans Kubernetes 1.19, et Docker-in-Docker est devenu indisponible.
Déployer et configurer Azure Kubernetes Service
Suivez les étapes décrites dans Démarrage rapide : Déployer un cluster Azure Kubernetes Service (AKS) à l’aide de la Portail Azure. Après cela, votre console PowerShell ou Shell peut utiliser la kubectl
ligne de commande.
Déployer et configurer Azure Container Registry
Effectuez les étapes contenues dans Démarrage rapide : Créer un registre de conteneurs Azure avec le portail Azure. Après cela, vous pouvez envoyer (push) et extraire des conteneurs à partir d’Azure Container Registry.
Configurer des secrets et déployer un jeu de réplicas
Créez les secrets sur le cluster 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
Exécutez cette commande pour envoyer (push) votre conteneur à Container Registry :
docker push "<acr-server>/azp-agent:<tag>"
Configurez l’intégration de Container Registry pour les clusters AKS existants.
Notes
Si vous avez plusieurs abonnements sur le portail Azure, utilisez d’abord cette commande pour sélectionner un abonnement
az account set --subscription "<subscription id or subscription name>"
az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
Enregistrez le contenu suivant dans
~/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
Ce YAML Kubernetes crée un ensemble de réplicas et un déploiement, où
replicas: 1
indique le nombre ou les agents qui s’exécutent sur le cluster.Exécutez la commande suivante :
kubectl apply -f ReplicationController.yml
À présent, vos agents exécutent le cluster AKS.
Définir le paramètre MTU personnalisé
Autoriser la spécification de la valeur MTU pour les réseaux utilisés par les travaux de conteneur (utile pour les scénarios docker-in-docker dans le cluster k8s).
Vous devez définir la variable d'environnement AGENT_DOCKER_MTU_VALUE pour définir la valeur MTU, puis redémarrer l'agent auto-hébergé. Vous trouverez plus d’informations sur le redémarrage de l’agent ici et sur la définition de différentes variables d’environnement pour chaque agent individuel ici.
Cela vous permet de configurer un paramètre réseau pour le conteneur de travaux. L’utilisation de cette commande est similaire à l’utilisation de la commande suivante lors de la configuration du réseau de conteneur :
-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE
Montage de volumes à l’aide de Docker dans un conteneur Docker
Si un conteneur Docker s’exécute à l’intérieur d’un autre conteneur Docker, ils utilisent tous les deux le démon de l’hôte, de sorte que tous les chemins de montage référencent l’hôte, et non le conteneur.
Par exemple, si nous voulons monter le chemin à partir de l’hôte dans un conteneur Docker externe, nous pouvons utiliser cette commande :
docker run ... -v "<path-on-host>:<path-on-outer-container>" ...
Par exemple, si nous voulons monter le chemin à partir de l’hôte dans un conteneur Docker externe, nous pouvons utiliser cette commande :
docker run ... -v "<path-on-host>:<path-on-inner-container>" ...
Mais nous ne pouvons pas monter des chemins d’accès à partir d’un conteneur externe vers le conteneur interne ; pour contourner ce problème, nous devons déclarer une variable ENV :
docker run ... --env DIND_USER_HOME=$HOME ...
Après cela, nous pouvons démarrer le conteneur interne à partir du conteneur externe à l’aide de la commande suivante :
docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...
Erreurs courantes
Si vous utilisez Windows et que vous obtenez l’erreur suivante :
standard_init_linux.go:178: exec user process caused "no such file or directory"
Installez Git Bash en téléchargeant et en installant git-scm.
Exécutez la commande suivante :
dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push
Réessayez. Vous n’obtenez plus l’erreur.