Запуск локального агента в Docker

Azure DevOps Services | Azure DevOps Server 2022 — Azure DevOps Server 2019

В этой статье приведены инструкции по запуску агента Azure Pipelines в Docker. Вы можете настроить автономный агент в Azure Pipelines для запуска в Windows Server Core (для узлов Windows) или контейнера Ubuntu (для узлов Linux) с помощью Docker. Это полезно, если вы хотите запускать агенты с внешним оркестрацией, например Экземпляры контейнеров Azure. В этой статье описан полный пример контейнера, включая самостоятельное обновление агента.

Windows и Linux поддерживаются как узлы контейнеров. Контейнеры Windows должны работать в Windows vmImage. Чтобы запустить агент в Docker, вы передайте несколько переменных docker runсреды, в которые агент настраивает подключение к Azure Pipelines или Azure DevOps Server. Наконец, вы настраиваете контейнер в соответствии с вашими потребностями. Задачи и скрипты могут зависеть от определенных средств, доступных в контейнере PATH, и это ваша ответственность за обеспечение доступности этих средств.

Для этой функции требуется агент версии 2.149 или более поздней. Azure DevOps 2019 не было отправлено с совместимой версией агента. Однако вы можете отправить правильный пакет агента на уровень приложений , если вы хотите запустить агенты Docker.

Windows

Включение Hyper-V

Hyper-V по умолчанию не включен в Windows. Если требуется обеспечить изоляцию между контейнерами, необходимо включить Hyper-V. В противном случае Docker для Windows не запустится.

Примечание.

Необходимо включить виртуализацию на компьютере. Обычно он включен по умолчанию. Однако если установка Hyper-V завершается сбоем, обратитесь к системной документации по включению виртуализации.

Установка Docker для Windows

Если вы используете Windows 10, вы можете установить Docker Community Edition. Для Windows Server 2016 установите выпуск Enterprise Docker.

Переключение Docker на использование контейнеров Windows

По умолчанию Docker для Windows настроен на использование контейнеров Linux. Чтобы разрешить запуск контейнера Windows, убедитесь, что Docker для Windows работает под управлением управляющей программы Windows.

Создание и сборка Dockerfile

Затем создайте Dockerfile.

  1. Откройте командную строку.

  2. Создайте каталог:

    mkdir "C:\azp-agent-in-docker\"
    
  3. Перейдите к этому новому каталогу:

    cd "C:\azp-agent-in-docker\"
    
  4. Сохраните следующее содержимое в файл с именем 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
    
  5. Сохраните следующее содержимое 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})"
    }
    
  6. Выполните следующую команду в этом каталоге:

    docker build --tag "azp-agent:windows" --file "./azp-agent-windows.dockerfile" .
    

    Окончательный образ помечен.azp-agent:windows

Запуск образа

Теперь, когда вы создали образ, можно запустить контейнер. Это устанавливает последнюю версию агента, настраивает его и запускает агент. Он предназначен для указанного пула агентов ( Default пул агентов по умолчанию) указанного экземпляра Azure DevOps или Azure DevOps Server по своему усмотрению:

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

При возникновении проблем с сетью --network может потребоваться указать параметр.

docker run --network "Default Switch" < . . . >

Возможно, потребуется указать --interactive и флаги (или просто-it), если вы хотите остановить контейнер и удалить агент.Ctrl + C--tty

docker run --interactive --tty < . . . >

Если требуется новый контейнер агента для каждого задания конвейера, передайте --once флаг в run команду.

docker run < . . . > --once

--once С помощью флага может потребоваться использовать систему оркестрации контейнеров, например Kubernetes или Экземпляры контейнеров Azure, чтобы запустить новую копию контейнера после завершения задания.

Вы можете управлять именем агента, пулом агентов и рабочим каталогом агента с помощью необязательных переменных среды.

Linux

Установите Docker.

В зависимости от дистрибутива Linux можно установить Docker Community Edition или Docker выпуск Enterprise.

Создание и сборка Dockerfile

Затем создайте Dockerfile.

  1. Откройте окно терминала.

  2. Создайте каталог (рекомендуется):

    mkdir ~/azp-agent-in-docker/
    
  3. Перейдите к этому новому каталогу:

    cd ~/azp-agent-in-docker/
    
  4. Сохраните следующее содержимое ~/azp-agent-in-docker/azp-agent-linux.dockerfile:

    • Для 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" ]
      
    • Для 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" ]
      

    Раскомментируйте ENV AGENT_ALLOW_RUNASROOT="true" строку и удалите добавление agent пользователя перед этой строкой, если вы хотите запустить агент в качестве корневого каталога.

    Примечание.

    Задачи могут зависеть от исполняемых файлов, предоставляемых контейнером. Например, необходимо добавить zip в команду и unzip пакеты RUN apt install -y , чтобы выполнить ArchiveFiles задачи и ExtractFiles задачи. Кроме того, так как это образ Ubuntu linux для используемого агента, вы можете настроить образ по мере необходимости. Например, если вам нужно создать приложения .NET, вы можете выполнить установку пакета SDK для .NET или среды выполнения .NET в Ubuntu и добавить его в образ.

  5. Сохраните следующее содержимое~/azp-agent-in-docker/start.sh, чтобы убедиться, что используется конец строки стиле 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 $!
    

    Примечание.

    Кроме того, необходимо использовать систему оркестрации контейнеров, например Kubernetes или Экземпляры контейнеров Azure, чтобы начать новые копии контейнера после завершения работы.

  6. Выполните следующую команду в этом каталоге:

    docker build --tag "azp-agent:linux" --file "./azp-agent-linux.dockerfile" .
    

    Окончательный образ помечен.azp-agent:linux

Запуск образа

Теперь, когда вы создали образ, можно запустить контейнер. Это устанавливает последнюю версию агента, настраивает его и запускает агент. Он предназначен для указанного пула агентов ( Default пул агентов по умолчанию) указанного экземпляра Azure DevOps или Azure DevOps Server по своему усмотрению:

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

Возможно, потребуется указать --interactive и флаги (или просто-it), если вы хотите остановить контейнер и удалить агент.Ctrl + C--tty

docker run --interactive --tty < . . . >

Если требуется новый контейнер агента для каждого задания конвейера, передайте --once флаг в run команду.

docker run < . . . > --once

--once С помощью флага может потребоваться использовать систему оркестрации контейнеров, например Kubernetes или Экземпляры контейнеров Azure, чтобы запустить новую копию контейнера после завершения задания.

Вы можете управлять именем агента, пулом агентов и рабочим каталогом агента с помощью необязательных переменных среды.

Переменные среды

Переменная среды Description
AZP_URL URL-адрес экземпляра Azure DevOps или Azure DevOps Server.
AZP_TOKEN Личный маркер доступа (PAT) с областью "Пулы агентов" (чтение, управление), созданная пользователем, у которого есть разрешение на настройку агентов.AZP_URL
AZP_AGENT_NAME Имя агента (значение по умолчанию: имя узла контейнера).
AZP_POOL Имя пула агентов (значение по умолчанию: Default).
AZP_WORK Рабочий каталог (значение по умолчанию: _work).

Добавление средств и настройка контейнера

Вы создали базовый агент сборки. Вы можете расширить Dockerfile, чтобы включить дополнительные средства и их зависимости, или создать собственный контейнер с помощью этого файла в качестве базового слоя. Просто убедитесь, что указанные ниже элементы остаются неуправляемыми:

  • Скрипт start.sh вызывается Dockerfile.
  • Скрипт start.sh — это последняя команда в Dockerfile.
  • Убедитесь, что производные контейнеры не удаляют ни одного из зависимостей, указанных в Dockerfile.

Использование Docker в контейнере Docker

Чтобы использовать Docker из контейнера Docker, необходимо привязать сокет Docker.

Внимание

Это имеет серьезные последствия для безопасности. Теперь код внутри контейнера может выполняться в качестве корневого каталога на узле Docker.

Если вы уверены, что хотите сделать это, см . документацию по подключению привязки на Docker.com.

Использование кластера Служба Azure Kubernetes

Внимание

Обратите внимание, что любые задачи на основе docker не будут работать в AKS 1.19 или более поздней версии из-за docker в ограничении Docker. Docker был заменен контейнером в Kubernetes 1.19, и Docker-in-Docker стал недоступным.

Развертывание и настройка Служба Azure Kubernetes

Выполните действия, описанные в кратком руководстве. Развертывание кластера Служба Azure Kubernetes (AKS) с помощью портал Azure. После этого консоль PowerShell или Shell может использовать командную kubectl строку.

Развертывание и настройка Реестр контейнеров Azure

Выполните действия, описанные в разделе Краткое руководство. Создание реестра контейнеров Azure с помощью портала Azure. После этого можно отправить и извлечь контейнеры из Реестр контейнеров Azure.

Настройка секретов и развертывание набора реплик

  1. Создайте секреты в кластере 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
    
  2. Выполните следующую команду, чтобы отправить контейнер в реестр контейнеров:

    docker push "<acr-server>/azp-agent:<tag>"
    
  3. Настройте интеграцию реестра контейнеров для существующих кластеров AKS.

    Примечание.

    Если на портале Azure несколько подписок, сначала используйте эту команду, чтобы выбрать подписку.

    az account set --subscription "<subscription id or subscription name>"
    
    az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
    
  4. Сохраните следующее содержимое ~/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
    

    Этот YAML Kubernetes создает набор реплик и развертывание, где replicas: 1 указывается число или агенты, работающие в кластере.

  5. Выполните следующую команду:

    kubectl apply -f ReplicationController.yml
    

Теперь агенты будут запускать кластер AKS.

Настройка настраиваемого параметра MTU

Разрешить указание значения MTU для сетей, используемых заданиями контейнеров (полезно для сценариев docker в docker в кластере k8s).

Необходимо задать переменную среды AGENT_DOCKER_MTU_VALUE, чтобы задать значение MTU, а затем перезапустить локальный агент. Дополнительные сведения о перезапуске агента см. здесь и о настройке различных переменных среды для каждого отдельного агента здесь.

Это позволяет настроить сетевой параметр для контейнера заданий, использование этой команды аналогично использованию следующей команды при настройке сети контейнеров:

-o com.docker.network.driver.mtu=AGENT_DOCKER_MTU_VALUE

Подключение томов с помощью Docker в контейнере Docker

Если контейнер Docker выполняется внутри другого контейнера Docker, они оба используют управляющей программы узла, поэтому все пути подключения ссылаются на узел, а не контейнер.

Например, если мы хотим подключить путь от узла к внешнему контейнеру Docker, мы можем использовать следующую команду:

docker run ... -v "<path-on-host>:<path-on-outer-container>" ...

И если мы хотим подключить путь от узла к внутреннему контейнеру Docker, мы можем использовать следующую команду:

docker run ... -v "<path-on-host>:<path-on-inner-container>" ...

Но мы не можем подключить пути из внешнего контейнера в внутренний; чтобы обойти это, необходимо объявить переменную ENV:

docker run ... --env DIND_USER_HOME=$HOME ...

После этого можно запустить внутренний контейнер из внешнего контейнера с помощью следующей команды:

docker run ... -v "${DIND_USER_HOME}:<path-on-inner-container>" ...

Распространенные ошибки

Если вы используете Windows, и вы получите следующую ошибку:

standard_init_linux.go:178: exec user process caused "no such file or directory"

Установите Git Bash, скачав и установив git-scm.

Выполните следующую команду:

dos2unix ~/azp-agent-in-docker/Dockerfile
dos2unix ~/azp-agent-in-docker/start.sh
git add .
git commit -m "Fixed CR"
git push

Повторите попытку. Вы больше не получите ошибку.