Ejecución de un agente autohospedado en Docker
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019
En este artículo se proporcionan instrucciones para ejecutar el agente de Azure Pipelines en Docker. Puede configurar un agente autohospedado en Azure Pipelines para que se ejecute dentro de un contenedor de Windows Server Core (para hosts de Windows) o de Ubuntu (para hosts de Linux) con Docker. Resulta útil si desea ejecutar agentes con orquestación externa, como, por ejemplo, Azure Container Instances. En este artículo se le guiará por un ejemplo de contenedor completo, incluido el control de la actualización automática del agente.
Tanto Windows como Linux se admiten como hosts de contenedor. Los contenedores de Windows deben ejecutarse en una vmImage
de Windows.
Para ejecutar el agente en Docker, deberá pasar algunas variables de entorno a docker run
, que configura el agente para conectarse a Azure Pipelines o a Azure DevOps Server. Por último, deberá personalizar el contenedor para satisfacer sus necesidades. Las tareas y los scripts pueden depender de herramientas específicas que estén disponibles en la PATH
del contenedor y es responsabilidad suya asegurarse de que estas herramientas estén disponibles.
Esta característica requiere la versión del agente 2.149 o posterior. Azure DevOps 2019 no se ha actualizado con una versión del agente compatible. Sin embargo, puede cargar el paquete de agente correcto en el nivel de aplicación si desea ejecutar agentes de Docker.
Windows
Habilitar Hyper-V
Hyper-V no está habilitado de forma predeterminada en Windows. Si desea proporcionar aislamiento entre contenedores, debe habilitar Hyper-V. De lo contrario, Docker para Windows no se iniciará.
Nota:
Debe habilitar la virtualización en la máquina. Suele estar habilitado de forma predeterminada. Sin embargo, si se produce un error en la instalación de Hyper-V, consulte la documentación del sistema sobre cómo habilitar la virtualización.
Instalación de Docker para Windows
Si usa Windows 10, puede instalar Docker Community Edition. Para Windows Server 2016, debe instalar Docker Enterprise Edition.
Cambio de Docker para usar contenedores de Windows
De forma predeterminada, Docker para Windows está configurado para usar contenedores de Linux. Para permitir la ejecución del contenedor de Windows, confirme que Docker para Windows ejecuta el demonio de Windows.
Crear y compilar el Dockerfile
A continuación, cree el archivo Dockerfile.
Abra un símbolo del sistema.
Cree un directorio:
mkdir "C:\azp-agent-in-docker\"
Vaya a este nuevo directorio:
cd "C:\azp-agent-in-docker\"
Guarde el siguiente contenido en un archivo denominado
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
Guarde el siguiente contenido en
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})" }
Ejecute el comando siguiente desde ese directorio:
docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
La imagen final se etiqueta
azp-agent:windows
.
Iniciar la imagen
Ahora que ha creado una imagen, puede ejecutar un contenedor. Se instala la versión más reciente del agente, la configura y ejecuta el agente. Tiene como destino el grupo de agentes especificado (el grupo de agentes de Default
de forma predeterminada) de una instancia de Azure DevOps o Azure DevOps Server especificada de su elección:
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
Es posible que tenga que especificar el parámetro --network
si tiene problemas de red.
docker run --network "Default Switch" < . . . >
Es posible que tenga que especificar las marcas --interactive
y --tty
(o simplemente -it
) si desea poder detener el contenedor y quitar el agente con Ctrl
+ C
.
docker run --interactive --tty < . . . >
Si desea un contenedor de agentes nuevo para cada trabajo de canalización, pase la marca --once
al comando run
.
docker run < . . . > --once
Con la marca --once
, es posible que quiera usar un sistema de orquestación de contenedores, como Kubernetes o Azure Container Instances, para iniciar una nueva copia del contenedor cuando se complete el trabajo.
Puede controlar el nombre del agente, el grupo de agentes y el directorio de trabajo del agente mediante variables de entorno opcionales.
Linux
Instalación de Docker
En función de la distribución de Linux que tenga, puede instalar Docker Community Edition o Docker Enterprise Edition.
Crear y compilar el Dockerfile
A continuación, cree el archivo Dockerfile.
Abra un terminal.
Cree un directorio (recomendado):
mkdir ~/azp-agent-in-docker/
Vaya a este nuevo directorio:
cd ~/azp-agent-in-docker/
Guarde el siguiente contenido en
~/azp-agent-in-docker/azp-agent-linux.dockerfile
:Para 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" ]
Para 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" ]
Quite la marca de comentario de la línea
ENV AGENT_ALLOW_RUNASROOT="true"
y deshaga agregar al usuarioagent
antes de esta línea si desea ejecutar el agente como raíz.Nota:
Las tareas pueden depender de los ejecutables que se prevé que proporcione el contenedor. Por ejemplo, debe agregar los paquetes
zip
yunzip
al comandoRUN apt install -y
para poder ejecutar las tareasArchiveFiles
yExtractFiles
. Además, como se trata de una imagen de Linux Ubuntu para que la use el agente, puede personalizar la imagen según sea necesario. Por ejemplo, si necesita compilar aplicaciones .NET, puede seguir el documento Instalación del SDK de .NET o el entorno de ejecución de .NET en Ubuntu y agregarlo a la imagen.Guarde el siguiente contenido en
~/azp-agent-in-docker/start.sh
, asegurándose de usar finales de línea de estilo 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:
También debe usar un sistema de orquestación de contenedores, como Kubernetes o Azure Container Instances, para iniciar nuevas copias del contenedor cuando finalice el trabajo.
Ejecute el comando siguiente desde ese directorio:
docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
La imagen final se etiqueta
azp-agent:linux
.
Iniciar la imagen
Ahora que ha creado una imagen, puede ejecutar un contenedor. Se instala la versión más reciente del agente, la configura y ejecuta el agente. Tiene como destino el grupo de agentes especificado (el grupo de agentes de Default
de forma predeterminada) de una instancia de Azure DevOps o Azure DevOps Server especificada de su elección:
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
Es posible que tenga que especificar las marcas --interactive
y --tty
(o simplemente -it
) si desea poder detener el contenedor y quitar el agente con Ctrl
+ C
.
docker run --interactive --tty < . . . >
Si desea un contenedor de agentes nuevo para cada trabajo de canalización, pase la marca --once
al comando run
.
docker run < . . . > --once
Con la marca --once
, es posible que quiera usar un sistema de orquestación de contenedores, como Kubernetes o Azure Container Instances, para iniciar una nueva copia del contenedor cuando se complete el trabajo.
Puede controlar el nombre del agente, el grupo de agentes y el directorio de trabajo del agente mediante variables de entorno opcionales.
Variables de entorno
Variable de entorno | Descripción |
---|---|
AZP_URL | Dirección URL de la instancia de Azure DevOps o Azure DevOps Server. |
AZP_TOKEN | Token de acceso personal (PAT) con el ámbito Grupos de agentes (lectura, administración), creado por un usuario que tiene permiso para configurar agentes, en AZP_URL . |
AZP_AGENT_NAME | Nombre del agente (valor predeterminado: el nombre de host del contenedor). |
AZP_POOL | Nombre del grupo de agentes (valor predeterminado: Default ). |
AZP_WORK | Directorio de trabajo (valor predeterminado: _work ). |
Adición de herramientas y personalización del contenedor
Creó un agente de compilación básico. Puede ampliar el archivo Dockerfile para incluir herramientas adicionales y sus dependencias, o bien crear su propio contenedor usando este como capa base. Solo debe asegurarse de que no se toque lo siguiente:
- El archivo Dockerfile llama al script
start.sh
. - El script
start.sh
es el último comando del archivo Dockerfile. - Asegúrese de que los contenedores derivados no quiten ninguna de las dependencias indicadas por el archivo Dockerfile.
Uso de Docker en un contenedor de Docker
Para usar Docker desde un contenedor de Docker, se debe enlazar el socket de Docker.
Precaución
Esto tiene graves implicaciones de seguridad. El código que hay dentro del contenedor ahora se puede ejecutar como raíz en el host de Docker.
Si sabe seguro que desea hacerlo, consulte la documentación de montaje de enlace en Docker.com.
Uso de un clúster de Azure Kubernetes Service
Precaución
Tenga en cuenta que las tareas basadas en Docker no funcionarán en AKS 1.19 o en versiones anteriores debido a la restricción de Docker. Docker se reemplazó por containerd en Kubernetes 1.19 y Docker-in-Docker dejó de estar disponible.
Implementación y configuración de Azure Kubernetes Service
Siga los pasos descritos en Inicio rápido: implementación de un clúster de Azure Kubernetes Service (AKS) mediante Azure Portal. Después, la consola de PowerShell o Shell puede usar la línea de comandos kubectl
.
Implementación y configuración de Azure Container Registry
Siga los pasos de Inicio rápido: Creación de un instancia de Azure Container Registry mediante Azure Portal. Después, puede insertar y extraer contenedores de Azure Container Registry.
Configuración de secretos e implementación de un conjunto de réplicas
Cree los secretos en el clúster de 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
Ejecute este comando para insertar el contenedor en Container Registry:
docker push "<acr-server>/azp-agent:<tag>"
Configure la integración de Container Registry para los clústeres de AKS existentes.
Nota:
Si tiene varias suscripciones en Azure Portal, use este comando primero para seleccionar una suscripción.
az account set --subscription "<subscription id or subscription name>"
az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
Guarde el siguiente contenido en
~/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
Este YAML de Kubernetes crea un conjunto de réplicas y una implementación, donde
replicas: 1
indica el número o los agentes que se ejecutan en el clúster.Ejecute este comando:
kubectl apply -f ReplicationController.yml
Ahora los agentes ejecutarán el clúster de AKS.
Establecimiento del parámetro MTU personalizado
Permite especificar el valor de MTU para las redes que usan los trabajos de contenedor (útiles en los escenarios Docker-in-Docker en el clúster k8s).
Debe establecer la variable de entorno AGENT_DOCKER_MTU_VALUE para establecer el valor de MTU y, a continuación, reiniciar el agente autohospedado. Encontrará más información sobre el reinicio del agente aquí y sobre cómo establecer diferentes variables de entorno para cada agente individual aquí.
De este modo, podrá configurar un parámetro de red para el contenedor de trabajos; el uso de este comando es similar al uso del comando siguiente mientras se configura la red del contenedor:
-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE
Montaje de volúmenes mediante Docker en un contenedor de Docker
Si un contenedor de Docker se ejecuta dentro de otro contenedor de Docker, ambos usan el demonio del host, por lo que todas las rutas de acceso de montaje hacen referencia al host, y no al contenedor.
Por ejemplo, si queremos montar la ruta de acceso del host en un contenedor externo de Docker, podemos usar este comando:
docker run ... -v "<path-on-host>:<path-on-outer-container>" ...
Y si queremos montar la ruta de acceso del host en un contenedor interno de Docker, podemos usar este comando:
docker run ... -v "<path-on-host>:<path-on-inner-container>" ...
Pero no podemos montar rutas de acceso desde el contenedor exterior en el interno; para solucionarlo, tenemos que declarar una variable ENV:
docker run ... --env DIND_USER_HOME=$HOME ...
Después, podemos iniciar el contenedor interno desde el exterior usando este comando:
docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...
Errores comunes
Si usa Windows y recibe el siguiente error:
standard_init_linux.go:178: exec user process caused "no such file or directory"
Instale Git Bash descargando e instalando git-scm.
Ejecute este comando:
dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push
Inténtelo de nuevo. Ya no recibirá el error.