Menjalankan agen yang dihosting sendiri di Docker

Layanan Azure DevOps | Azure DevOps Server 2022 - Azure DevOps Server 2019

Artikel ini menyediakan instruksi untuk menjalankan agen Azure Pipelines Anda di Docker. Anda dapat menyiapkan agen yang dihost sendiri di Azure Pipelines untuk berjalan di dalam Windows Server Core (untuk host Windows), atau kontainer Ubuntu (untuk host Linux) dengan Docker. Ini berguna ketika Anda ingin menjalankan agen dengan orkestrasi luar, seperti Azure Container Instances. Dalam artikel ini, Anda akan menelusuri contoh kontainer lengkap, termasuk menangani pembaruan mandiri agen.

Windows dan Linux didukung sebagai host kontainer. Kontainer Windows harus berjalan pada Windows vmImage. Untuk menjalankan agen di Docker, Anda akan meneruskan beberapa variabel lingkungan ke docker run, yang mengonfigurasi agen untuk terhubung ke Azure Pipelines atau Azure DevOps Server. Terakhir, Anda menyesuaikan kontainer agar sesuai dengan kebutuhan Anda. Tugas dan skrip mungkin bergantung pada alat tertentu yang tersedia di kontainer PATH, dan Anda bertanggung jawab untuk memastikan bahwa alat-alat ini tersedia.

Fitur ini memerlukan agen versi 2.149 atau yang lebih baru. Azure DevOps 2019 tidak dikirim dengan versi agen yang kompatibel. Namun, Anda dapat mengunggah paket agen yang benar ke tingkat aplikasi Jika Anda ingin menjalankan agen Docker.

Jendela

Mengaktifkan Hyper-V

Hyper-V tidak diaktifkan secara default di Windows. Jika Anda ingin memberikan isolasi antar kontainer, Anda harus mengaktifkan Hyper-V. Jika tidak, Docker untuk Windows tidak akan dimulai.

Catatan

Anda harus mengaktifkan virtualisasi pada komputer Anda. Biasanya diaktifkan secara default. Namun, jika penginstalan Hyper-V gagal, lihat dokumentasi sistem Anda tentang cara mengaktifkan virtualisasi.

Menginstal Docker untuk Windows

Jika Anda menggunakan Windows 10, Anda dapat menginstal Docker Community Edition. Untuk Windows Server 2016, instal Docker Enterprise Edition.

Alihkan Docker untuk menggunakan kontainer Windows

Secara default, Docker untuk Windows dikonfigurasi untuk menggunakan kontainer Linux. Untuk mengizinkan menjalankan kontainer Windows, konfirmasikan bahwa Docker untuk Windows menjalankan daemon Windows.

Membuat dan membangun Dockerfile

Selanjutnya, buat Dockerfile.

  1. Buka prompt perintah.

  2. Buat direktori baru:

    mkdir "C:\azp-agent-in-docker\"
    
  3. Buka direktori baru ini:

    cd "C:\azp-agent-in-docker\"
    
  4. Simpan konten berikut ke file yang disebut 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. Simpan konten berikut ke 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. Jalankan perintah berikut dalam direktori tersebut:

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

    Gambar akhir ditandai azp-agent:windows.

Memulai gambar

Setelah membuat gambar, Anda dapat menjalankan kontainer. Ini menginstal versi terbaru agen, mengonfigurasinya, dan menjalankan agen. Ini menargetkan kumpulan agen yang ditentukan ( Default kumpulan agen secara default) dari instans Azure DevOps atau Azure DevOps Server tertentu pilihan Anda:

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

Anda mungkin perlu menentukan --network parameter jika Mengalami masalah jaringan.

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

Anda mungkin perlu menentukan --interactive dan menandai (atau sederhana -it) jika Anda ingin dapat menghentikan kontainer dan menghapus agen denganCCtrl + .--tty

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

Jika Anda menginginkan kontainer agen baru untuk setiap pekerjaan alur, teruskan --once bendera ke run perintah .

docker run < . . . > --once

--once Dengan bendera , Anda mungkin ingin menggunakan sistem orkestrasi kontainer, seperti Kubernetes atau Azure Container Instances, untuk memulai salinan baru kontainer ketika pekerjaan selesai.

Anda dapat mengontrol nama agen, kumpulan agen, dan direktori kerja agen dengan menggunakan variabel lingkungan opsional.

Linux

Menginstal Docker

Bergantung pada Distribusi Linux, Anda dapat menginstal Docker Community Edition atau Docker Enterprise Edition.

Membuat dan membangun Dockerfile

Selanjutnya, buat Dockerfile.

  1. Buka terminal.

  2. Buat direktori baru (disarankan):

    mkdir ~/azp-agent-in-docker/
    
  3. Buka direktori baru ini:

    cd ~/azp-agent-in-docker/
    
  4. Simpan konten berikut ke ~/azp-agent-in-docker/azp-agent-linux.dockerfile:

    • Untuk Alpine:

      FROM alpine
      
      RUN apk update
      RUN apk upgrade
      RUN apk add bash curl git icu-libs jq
      
      ENV TARGETARCH="linux-musl-x64"
      
      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" ]
      
    • Untuk Ubuntu 22.04:

      FROM ubuntu:22.04
      
      RUN apt update -y && apt upgrade -y && apt install curl git jq libicu70 -y
      
      # Also can be "linux-arm", "linux-arm64".
      ENV TARGETARCH="linux-x64"
      
      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" ]
      

    Batalkan ENV AGENT_ALLOW_RUNASROOT="true" komentar baris dan hapus penambahan agent pengguna sebelum baris ini jika Anda ingin menjalankan agen sebagai root.

    Catatan

    Tugas mungkin bergantung pada executable yang diharapkan disediakan kontainer Anda. Misalnya, Anda harus menambahkan zip paket dan unzip ke RUN apt install -y perintah untuk menjalankan ArchiveFiles tugas dan ExtractFiles . Selain itu, karena ini adalah gambar Ubuntu Linux untuk digunakan agen, Anda dapat menyesuaikan gambar sesuai kebutuhan Anda. Misalnya: jika Anda perlu membangun aplikasi .NET, Anda dapat mengikuti dokumen Instal .NET SDK atau .NET Runtime di Ubuntu dan menambahkannya ke gambar Anda.

  5. Simpan konten berikut ke ~/azp-agent-in-docker/start.sh, pastikan untuk menggunakan akhir baris gaya 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 $!
    

    Catatan

    Anda juga harus menggunakan sistem orkestrasi kontainer, seperti Kubernetes atau Azure Container Instances, untuk memulai salinan baru kontainer saat pekerjaan selesai.

  6. Jalankan perintah berikut dalam direktori tersebut:

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

    Gambar akhir ditandai azp-agent:linux.

Memulai gambar

Setelah membuat gambar, Anda dapat menjalankan kontainer. Ini menginstal versi terbaru agen, mengonfigurasinya, dan menjalankan agen. Ini menargetkan kumpulan agen yang ditentukan ( Default kumpulan agen secara default) dari instans Azure DevOps atau Azure DevOps Server tertentu pilihan Anda:

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

Anda mungkin perlu menentukan --interactive dan menandai (atau sederhana -it) jika Anda ingin dapat menghentikan kontainer dan menghapus agen denganCCtrl + .--tty

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

Jika Anda menginginkan kontainer agen baru untuk setiap pekerjaan alur, teruskan --once bendera ke run perintah .

docker run < . . . > --once

--once Dengan bendera , Anda mungkin ingin menggunakan sistem orkestrasi kontainer, seperti Kubernetes atau Azure Container Instances, untuk memulai salinan baru kontainer ketika pekerjaan selesai.

Anda dapat mengontrol nama agen, kumpulan agen, dan direktori kerja agen dengan menggunakan variabel lingkungan opsional.

Variabel lingkungan

Variabel lingkungan Deskripsi
AZP_URL URL instans Azure DevOps atau Azure DevOps Server.
AZP_TOKEN Token Akses Pribadi (PAT) dengan cakupan Kumpulan Agen (baca, kelola), dibuat oleh pengguna yang memiliki izin untuk mengonfigurasi agen, di AZP_URL.
AZP_AGENT_NAME Nama agen (nilai default: nama host kontainer).
AZP_POOL Nama kumpulan agen (nilai default: Default).
AZP_WORK Direktori kerja (nilai default: _work).

Menambahkan alat dan menyesuaikan kontainer

Anda telah membuat agen build dasar. Anda dapat memperluas Dockerfile untuk menyertakan alat tambahan dan dependensinya, atau membangun kontainer Anda sendiri dengan menggunakan yang ini sebagai lapisan dasar. Pastikan bahwa berikut ini dibiarkan tidak tersentuh:

  • start.sh Skrip dipanggil oleh Dockerfile.
  • start.sh Skrip adalah perintah terakhir di Dockerfile.
  • Pastikan bahwa kontainer turunan tidak menghapus salah satu dependensi yang dinyatakan oleh Dockerfile.

Menggunakan Docker dalam kontainer Docker

Untuk menggunakan Docker dari dalam kontainer Docker, Anda mengikat-mount soket Docker.

Perhatian

Melakukan ini memiliki implikasi keamanan yang serius. Kode di dalam kontainer sekarang dapat berjalan sebagai root pada host Docker Anda.

Jika Anda yakin ingin melakukan ini, lihat dokumentasi pemasangan ikatan di Docker.com.

Menggunakan kluster Azure Kubernetes Service

Perhatian

Harap, pertimbangkan bahwa setiap tugas berbasis docker tidak akan berfungsi pada AKS 1.19 atau yang lebih baru karena docker dalam pembatasan docker. Docker diganti dengan kontainer di Kubernetes 1.19, dan Docker-in-Docker menjadi tidak tersedia.

Menyebarkan dan mengonfigurasi Azure Kubernetes Service

Ikuti langkah-langkah dalam Mulai Cepat: Menyebarkan kluster Azure Kubernetes Service (AKS) dengan menggunakan portal Azure. Setelah ini, konsol PowerShell atau Shell Anda dapat menggunakan kubectl baris perintah.

Menyebarkan dan mengonfigurasi Azure Container Registry

Ikuti langkah-langkah di Mulai Cepat: Membuat registri kontainer Azure dengan menggunakan portal Azure. Setelah ini, Anda dapat mendorong dan menarik kontainer dari Azure Container Registry.

Mengonfigurasi rahasia dan menyebarkan set replika

  1. Buat rahasia pada kluster 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. Jalankan perintah ini untuk mendorong kontainer Anda ke Container Registry:

    docker push "<acr-server>/azp-agent:<tag>"
    
  3. Konfigurasikan integrasi Container Registry untuk kluster AKS yang ada.

    Catatan

    Jika Anda memiliki beberapa langganan di Portal Microsoft Azure, silakan gunakan perintah ini terlebih dahulu untuk memilih langganan

    az account set --subscription "<subscription id or subscription name>"
    
    az aks update -n "<myAKSCluster>" -g "<myResourceGroup>" --attach-acr "<acr-name>"
    
  4. Simpan konten berikut ke ~/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 ini membuat set replika dan penyebaran, di mana replicas: 1 menunjukkan jumlah atau agen yang berjalan pada kluster.

  5. Jalankan perintah ini:

    kubectl apply -f ReplicationController.yml
    

Sekarang agen Anda akan menjalankan kluster AKS.

Mengatur parameter MTU kustom

Izinkan menentukan nilai MTU untuk jaringan yang digunakan oleh pekerjaan kontainer (berguna untuk skenario docker-in-docker di kluster k8s).

Anda perlu mengatur variabel lingkungan AGENT_DOCKER_MTU_VALUE untuk mengatur nilai MTU, lalu memulai ulang agen yang dihost sendiri. Anda dapat menemukan lebih lanjut tentang memulai ulang agen di sini dan tentang mengatur variabel lingkungan yang berbeda untuk setiap agen individu di sini.

Ini memungkinkan Anda untuk menyiapkan parameter jaringan untuk kontainer pekerjaan, penggunaan perintah ini mirip dengan penggunaan perintah berikutnya sementara konfigurasi jaringan kontainer:

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

Memasang volume menggunakan Docker dalam kontainer Docker

Jika kontainer Docker berjalan di dalam kontainer Docker lain, keduanya menggunakan daemon host, sehingga semua jalur pemasangan mereferensikan host, bukan kontainer.

Misalnya, jika kita ingin memasang jalur dari host ke kontainer Docker luar, kita dapat menggunakan perintah ini:

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

Dan jika kita ingin memasang jalur dari host ke dalam kontainer Docker, kita dapat menggunakan perintah ini:

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

Tetapi kita tidak dapat memasang jalur dari kontainer luar ke dalam; untuk mengatasinya, kita harus mendeklarasikan variabel ENV:

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

Setelah ini, kita dapat memulai kontainer dalam dari yang luar menggunakan perintah ini:

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

Kesalahan umum

Jika Anda menggunakan Windows, dan Anda mendapatkan kesalahan berikut:

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

Instal Git Bash dengan mengunduh dan menginstal git-scm.

Jalankan perintah ini:

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

Coba lagi. Anda tidak lagi mendapatkan kesalahan.