Menjalankan agen yang dihost sendiri di Docker
Azure DevOps | Azure DevOps Server 2020 | 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 Anda 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.
Windows
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. Ini 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.
Beralih Docker untuk menggunakan kontainer Windows
Secara default, Docker untuk Windows dikonfigurasi untuk menggunakan kontainer Linux. Untuk memperbolehkan menjalankan kontainer Windows, konfirmasikan bahwa Docker untuk Windows menjalankan daemon Windows.
Membuat dan membangun Dockerfile
Selanjutnya, buat Dockerfile.
Buka prompt perintah.
Buat direktori baru:
mkdir C:\dockeragentUbah direktori ke direktori baru ini:
cd C:\dockeragentSimpan konten berikut ke file yang disebut
C:\dockeragent\Dockerfile(tidak ada ekstensi file):FROM mcr.microsoft.com/windows/servercore:ltsc2019 WORKDIR /azp COPY start.ps1 . CMD powershell .\start.ps1Simpan konten berikut ke
C:\dockeragent\start.ps1: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 Write-Host "1. Determining matching Azure Pipelines agent..." -ForegroundColor Cyan $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 Write-Host "2. Downloading and installing Azure Pipelines agent..." -ForegroundColor Cyan $wc = New-Object System.Net.WebClient $wc.DownloadFile($packageUrl, "$(Get-Location)\agent.zip") Expand-Archive -Path "agent.zip" -DestinationPath "\azp\agent" try { Write-Host "3. Configuring Azure Pipelines agent..." -ForegroundColor Cyan .\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 Write-Host "4. Running Azure Pipelines agent..." -ForegroundColor Cyan .\run.cmd } finally { Write-Host "Cleanup. Removing Azure Pipelines agent..." -ForegroundColor Cyan .\config.cmd remove --unattended ` --auth PAT ` --token "$(Get-Content ${Env:AZP_TOKEN_FILE})" }Jalankan perintah berikut dalam direktori tersebut:
docker build -t dockeragent:latest .Perintah ini membangun Dockerfile di direktori saat ini.
Gambar akhir ditandai
dockeragent:latest. Anda dapat dengan mudah menjalankannya dalam kontainer sebagaidockeragent, karenalatesttag adalah default jika tidak ada tag yang ditentukan.
Memulai gambar
Setelah membuat gambar, Anda dapat menjalankan kontainer.
Buka prompt perintah.
Jalankan kontainer. Ini menginstal versi terbaru agen, mengonfigurasinya, dan menjalankan agen. Ini menargetkan kumpulan
Defaultinstans Azure DevOps atau Azure DevOps Server pilihan Anda yang ditentukan:docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<PAT token> -e AZP_AGENT_NAME=mydockeragent dockeragent:latest
Secara opsional, Anda dapat mengontrol kumpulan dan direktori kerja agen dengan menggunakan variabel lingkungan tambahan.
Jika Anda menginginkan kontainer agen baru untuk setiap eksekusi alur, teruskan --once bendera ke run perintah .
Anda juga harus menggunakan sistem orkestrasi kontainer, seperti Kubernetes atau Azure Container Instances, untuk memulai salinan baru kontainer saat pekerjaan selesai.
Linux
Memasang Docker
Bergantung pada Distribusi Linux, Anda dapat menginstal Docker Community Edition atau Docker Enterprise Edition.
Membuat dan membangun Dockerfile
Selanjutnya, buat Dockerfile.
Buka terminal.
Buat direktori baru (disarankan):
mkdir ~/dockeragentUbah direktori ke direktori baru ini:
cd ~/dockeragentSimpan konten berikut ke
~/dockeragent/Dockerfile:- Untuk Ubuntu 20.04:
FROM ubuntu:20.04 RUN DEBIAN_FRONTEND=noninteractive apt-get update RUN DEBIAN_FRONTEND=noninteractive apt-get upgrade -y RUN DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends \ apt-transport-https \ apt-utils \ ca-certificates \ curl \ git \ iputils-ping \ jq \ lsb-release \ software-properties-common RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash # Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'. ENV TARGETARCH=linux-x64 WORKDIR /azp COPY ./start.sh . RUN chmod +x start.sh ENTRYPOINT [ "./start.sh" ] - Untuk Ubuntu 18.04:
FROM ubuntu:18.04 # To make it easier for build and release pipelines to run apt-get, # configure apt to not require confirmation (assume the -y argument by default) ENV DEBIAN_FRONTEND=noninteractive RUN echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ jq \ git \ iputils-ping \ libcurl4 \ libicu60 \ libunwind8 \ netcat \ libssl1.0 \ && rm -rf /var/lib/apt/lists/* RUN curl -LsS https://aka.ms/InstallAzureCLIDeb | bash \ && rm -rf /var/lib/apt/lists/* # Can be 'linux-x64', 'linux-arm64', 'linux-arm', 'rhel.6-x64'. ENV TARGETARCH=linux-x64 WORKDIR /azp COPY ./start.sh . RUN chmod +x start.sh ENTRYPOINT ["./start.sh"]
Catatan
Tugas mungkin bergantung pada executable yang diharapkan untuk disediakan kontainer Anda. Misalnya, Anda harus menambahkan
zippaket danunzipkeRUN apt-getperintah untuk menjalankanArchiveFilestugas danExtractFiles. 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 tambahkan itu ke gambar Anda.- Untuk Ubuntu 20.04:
Simpan konten berikut ke
~/dockeragent/start.sh, pastikan untuk menggunakan akhiran 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 export AGENT_ALLOW_RUNASROOT="1" cleanup() { 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 "${lightcyan}$1${nocolor}" } # 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 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..." trap 'cleanup; exit 0' EXIT trap 'cleanup; exit 130' INT trap 'cleanup; exit 143' TERM chmod +x ./run-docker.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-docker.sh "$@" & wait $!Catatan
Anda juga harus menggunakan sistem orkestrasi kontainer, seperti Kubernetes atau Azure Container Instances, untuk memulai salinan baru kontainer saat pekerjaan selesai.
Jalankan perintah berikut dalam direktori tersebut:
docker build -t dockeragent:latest .Perintah ini membangun Dockerfile di direktori saat ini.
Gambar akhir ditandai
dockeragent:latest. Anda dapat dengan mudah menjalankannya dalam kontainer sebagaidockeragent, karenalatesttag adalah default jika tidak ada tag yang ditentukan.
Memulai gambar
Setelah membuat gambar, Anda dapat menjalankan kontainer.
Buka terminal.
Jalankan kontainer. Ini menginstal versi terbaru agen, mengonfigurasinya, dan menjalankan agen. Ini menargetkan kumpulan
Defaultinstans Azure DevOps atau Azure DevOps Server pilihan Anda yang ditentukan:docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<PAT token> -e AZP_AGENT_NAME=mydockeragent dockeragent:latestJika Anda menginginkan kontainer agen baru untuk setiap pekerjaan alur, teruskan
--oncebendera kerunperintah .docker run -e AZP_URL=<Azure DevOps instance> -e AZP_TOKEN=<PAT token> -e AZP_AGENT_NAME=mydockeragent dockeragent:latest --once
Secara opsional, Anda dapat mengontrol kumpulan dan direktori kerja agen dengan menggunakan variabel lingkungan tambahan.
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 tidak tersentuh:
start.shSkrip dipanggil oleh Dockerfile.start.shSkrip 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
Catatan
Instruksi berikut hanya berfungsi pada AKS 1.18 dan yang lebih rendah karena 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 Microsoft 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 Microsoft Azure. Setelah ini, Anda dapat mendorong dan menarik kontainer dari Azure Container Registry.
Mengonfigurasi rahasia dan menyebarkan set replika
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=NameOfYourPoolJalankan perintah ini untuk mendorong kontainer Anda ke Container Registry:
docker push <acr-server>/dockeragent:latestKonfigurasikan integrasi Container Registry untuk kluster AKS yang ada.
az aks update -n myAKSCluster -g myResourceGroup --attach-acr <acr-name>Simpan konten berikut ke
~/AKS/ReplicationController.yaml: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>/dockeragent:latest 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.sockYAML Kubernetes ini membuat set replika dan penyebaran, di mana
replicas: 1menunjukkan jumlah atau agen yang berjalan pada kluster.Jalankan perintah ini:
kubectl apply -f ReplicationController.yaml
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_MTU_VALUE untuk mengatur nilai MTU, setelah itu mulai ulang agen yang dihost sendiri. Anda dapat menemukan lebih lanjut tentang mulai ulang agen di sini dan tentang mengatur variabel lingkungan yang berbeda untuk setiap agen individu di sini.
Ini memungkinkan Anda menyiapkan parameter jaringan untuk kontainer pekerjaan, penggunaan perintah ini mirip dengan penggunaan perintah berikutnya saat konfigurasi jaringan kontainer:
-o com.docker.network.driver.mtu=AGENT_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 kontainer Docker dalam, 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 ~/dockeragent/Dockerfile
dos2unix ~/dockeragent/start.sh
git add .
git commit -m 'Fixed CR'
git push
Coba lagi. Anda tidak lagi mendapatkan kesalahan.