Executar um agente autoalojado no Docker
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
Este artigo fornece instruções para executar seu agente do Azure Pipelines no Docker. Você pode configurar um agente auto-hospedado no Azure Pipelines para ser executado dentro de um contêiner Windows Server Core (para hosts Windows) ou Ubuntu (para hosts Linux) com o Docker. Isso é útil quando você deseja executar agentes com orquestração externa, como Instâncias de Contêiner do Azure. Neste artigo, você percorrerá um exemplo completo de contêiner, incluindo a autoatualização do agente de manipulação.
O Windows e o Linux são suportados como hosts de contêiner. Os contêineres do Windows devem ser executados em um Windows vmImage
.
Para executar seu agente no Docker, você passará algumas variáveis de ambiente para docker run
o , que configura o agente para se conectar ao Azure Pipelines ou ao Azure DevOps Server. Finalmente, você personaliza o contêiner para atender às suas necessidades. As tarefas e os scripts podem depender da disponibilidade de PATH
ferramentas específicas no contêiner, e é sua responsabilidade garantir que essas ferramentas estejam disponíveis.
Esse recurso requer a versão 2.149 ou posterior do agente. O Azure DevOps 2019 não foi fornecido com uma versão de agente compatível. No entanto, você pode carregar o pacote de agente correto para sua camada de aplicativo se quiser executar agentes do Docker.
Windows
Ativar Hyper-V
O Hyper-V não está habilitado por padrão no Windows. Se quiser fornecer isolamento entre contêineres, habilite o Hyper-V. Caso contrário, o Docker para Windows não será iniciado.
Nota
Você deve habilitar a virtualização em sua máquina. Normalmente, é ativado por padrão. No entanto, se a instalação do Hyper-V falhar, consulte a documentação do sistema para saber como habilitar a virtualização.
Instalar o Docker para Windows
Se estiver a utilizar o Windows 10, pode instalar o Docker Community Edition. Para o Windows Server 2016, instale o Docker Enterprise Edition.
Alternar o Docker para usar contêineres do Windows
Por padrão, o Docker para Windows está configurado para usar contêineres Linux. Para permitir a execução do contêiner do Windows, confirme se o Docker para Windows está executando o daemon do Windows.
Criar e construir o Dockerfile
Em seguida, crie o Dockerfile.
Abra uma linha de comandos.
Crie um novo diretório:
mkdir "C:\azp-agent-in-docker\"
Vá para este novo diretório:
cd "C:\azp-agent-in-docker\"
Salve o seguinte conteúdo em um arquivo chamado
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
Salve o seguinte conteúdo em
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})" }
Execute o seguinte comando dentro desse diretório:
docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
A imagem final está marcada com .
azp-agent:windows
Iniciar a imagem
Agora que você criou uma imagem, você pode executar um contêiner. Isso instala a versão mais recente do agente, configura-a e executa o agente. Ele tem como alvo o pool de agentes especificado (o Default
pool de agentes por padrão) de uma instância especificada do Azure DevOps ou do Azure DevOps Server de sua escolha:
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
Talvez seja necessário especificar o parâmetro se tiver problemas de --network
rede.
docker run --network "Default Switch" < . . . >
Talvez seja necessário especificar --interactive
e sinalizar (ou simplesmente -it
) se quiser parar o contêiner e remover o agente com Ctrl
+ C
.--tty
docker run --interactive --tty < . . . >
Se você quiser um novo contêiner de agente para cada trabalho de pipeline, passe o --once
sinalizador para o run
comando.
docker run < . . . > --once
Com o --once
sinalizador, talvez você queira usar um sistema de orquestração de contêiner, como Kubernetes ou Instâncias de Contêiner do Azure, para iniciar uma nova cópia do contêiner quando o trabalho for concluído.
Você pode controlar o nome do agente, o pool de agentes e o diretório de trabalho do agente usando variáveis de ambiente opcionais.
Linux
Instalar o Docker
Dependendo da sua distribuição Linux, você pode instalar o Docker Community Edition ou o Docker Enterprise Edition.
Criar e construir o Dockerfile
Em seguida, crie o Dockerfile.
Abra um terminal.
Crie um novo diretório (recomendado):
mkdir ~/azp-agent-in-docker/
Vá para este novo diretório:
cd ~/azp-agent-in-docker/
Salve o seguinte conteúdo em
~/azp-agent-in-docker/azp-agent-linux.dockerfile
:Para a 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" ]
Descomente a
ENV AGENT_ALLOW_RUNASROOT="true"
linha e remova a adição doagent
usuário antes dessa linha se quiser executar o agente como root.Nota
As tarefas podem depender dos executáveis que se espera que seu contêiner forneça. Por exemplo, você deve adicionar os
zip
pacotes eunzip
aoRUN apt install -y
comando para executar asArchiveFiles
tarefas eExtractFiles
. Além disso, como esta é uma imagem do Linux Ubuntu para o agente usar, você pode personalizar a imagem conforme necessário. Por exemplo: se você precisar criar aplicativos .NET, você pode seguir o documento Instalar o SDK do .NET ou o Tempo de Execução do .NET no Ubuntu e adicioná-lo à sua imagem.Salve o seguinte conteúdo no
~/azp-agent-in-docker/start.sh
, certificando-se de usar terminações de linha no 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
Você também deve usar um sistema de orquestração de contêiner, como Kubernetes ou Instâncias de Contêiner do Azure, para iniciar novas cópias do contêiner quando o trabalho for concluído.
Execute o seguinte comando dentro desse diretório:
docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
A imagem final está marcada com .
azp-agent:linux
Iniciar a imagem
Agora que você criou uma imagem, você pode executar um contêiner. Isso instala a versão mais recente do agente, configura-a e executa o agente. Ele tem como alvo o pool de agentes especificado (o Default
pool de agentes por padrão) de uma instância especificada do Azure DevOps ou do Azure DevOps Server de sua escolha:
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
Talvez seja necessário especificar --interactive
e sinalizar (ou simplesmente -it
) se quiser parar o contêiner e remover o agente com Ctrl
+ C
.--tty
docker run --interactive --tty < . . . >
Se você quiser um novo contêiner de agente para cada trabalho de pipeline, passe o --once
sinalizador para o run
comando.
docker run < . . . > --once
Com o --once
sinalizador, talvez você queira usar um sistema de orquestração de contêiner, como Kubernetes ou Instâncias de Contêiner do Azure, para iniciar uma nova cópia do contêiner quando o trabalho for concluído.
Você pode controlar o nome do agente, o pool de agentes e o diretório de trabalho do agente usando variáveis de ambiente opcionais.
Variáveis de ambiente
Variável de ambiente | Description |
---|---|
AZP_URL | A URL da instância do Azure DevOps ou do Azure DevOps Server. |
AZP_TOKEN | Token de Acesso Pessoal (PAT) com escopo de Pools de Agentes (ler, gerenciar), criado por um usuário que tem permissão para configurar agentes, em AZP_URL . |
AZP_AGENT_NAME | Nome do agente (valor padrão: o nome do host do contêiner). |
AZP_POOL | Nome do pool de agentes (valor padrão: Default ). |
AZP_WORK | Diretório de trabalho (valor padrão: _work ). |
Adicionar ferramentas e personalizar o contêiner
Você criou um agente de compilação básico. Você pode estender o Dockerfile para incluir ferramentas adicionais e suas dependências ou criar seu próprio contêiner usando este como uma camada base. Apenas certifique-se de que os seguintes itens são deixados intocados:
- O
start.sh
script é chamado pelo Dockerfile. - O
start.sh
script é o último comando no Dockerfile. - Certifique-se de que os contêineres derivados não removam nenhuma das dependências declaradas pelo Dockerfile.
Usar o Docker em um contêiner do Docker
Para usar o Docker de dentro de um contêiner do Docker, você vincula e monta o soquete do Docker.
Atenção
Fazer isso tem sérias implicações de segurança. O código dentro do contêiner agora pode ser executado como root no host do Docker.
Se tiver certeza de que deseja fazer isso, consulte a documentação de montagem de ligação em Docker.com.
Usar o cluster do Serviço Kubernetes do Azure
Atenção
Por favor, considere que qualquer tarefa baseada no docker não funcionará no AKS 1.19 ou posterior devido à restrição do docker no docker. O Docker foi substituído por containerd no Kubernetes 1.19 e o Docker-in-Docker ficou indisponível.
Implantar e configurar o Serviço Kubernetes do Azure
Siga as etapas em Guia de início rápido: implantar um cluster do Serviço Kubernetes do Azure (AKS) usando o portal do Azure. Depois disso, seu console do PowerShell ou do Shell pode usar a linha de kubectl
comando.
Implantar e configurar o Registro de Contêiner do Azure
Siga as etapas em Guia de início rápido: criar um registro de contêiner do Azure usando o portal do Azure. Depois disso, você pode enviar e extrair contêineres do Registro de Contêiner do Azure.
Configurar segredos e implantar um conjunto de réplicas
Crie os segredos no 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
Execute este comando para enviar seu contêiner para o Registro de contêiner:
docker push "<acr-server>/azp-agent:<tag>"
Configure a integração do Registro de Contêiner para clusters AKS existentes.
Nota
Se você tiver várias assinaturas no Portal do Azure, use este comando primeiro para selecionar uma assinatura
az account set --subscription "<subscription id or subscription name>"
az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
Salve o seguinte conteúdo em
~/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 Kubernetes YAML cria um conjunto de réplicas e uma implantação, onde
replicas: 1
indica o número ou os agentes que estão sendo executados no cluster.Execute este comando:
kubectl apply -f ReplicationController.yml
Agora, seus agentes executarão o cluster AKS.
Definir parâmetro MTU personalizado
Permitir a especificação do valor MTU para redes usadas por trabalhos de contêiner (útil para cenários de docker-in-docker no cluster k8s).
Você precisa definir a variável de ambiente AGENT_DOCKER_MTU_VALUE definir o valor de MTU e, em seguida, reiniciar o agente auto-hospedado. Você pode encontrar mais sobre a reinicialização do agente aqui e sobre a configuração de variáveis de ambiente diferentes para cada agente individual aqui.
Isso permite que você configure um parâmetro de rede para o contêiner de trabalho, o uso deste comando é semelhante ao uso do próximo comando durante a configuração de rede de contêiner:
-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE
Montagem de volumes usando o Docker em um contêiner do Docker
Se um contêiner do Docker for executado dentro de outro contêiner do Docker, ambos usarão o daemon do host, portanto, todos os caminhos de montagem fazem referência ao host, não ao contêiner.
Por exemplo, se quisermos montar o caminho do host para o contêiner externo do Docker, podemos usar este comando:
docker run ... -v "<path-on-host>:<path-on-outer-container>" ...
E se quisermos montar o caminho do host para o contêiner interno do Docker, podemos usar este comando:
docker run ... -v "<path-on-host>:<path-on-inner-container>" ...
Mas não podemos montar caminhos do recipiente externo para o interno; para contornar isso, temos que declarar uma variável ENV:
docker run ... --env DIND_USER_HOME=$HOME ...
Depois disso, podemos iniciar o recipiente interno a partir do externo usando este comando:
docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...
Erros comuns
Se estiver a utilizar o Windows e receber o seguinte erro:
standard_init_linux.go:178: exec user process caused "no such file or directory"
Instale o Git Bash baixando e instalando o git-scm.
Execute este comando:
dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push
Tente novamente. Você não recebe mais o erro.