Definieren von Containeraufträgen (YAML)
Azure DevOps Services | Azure DevOps Server 2022 | Azure DevOps Server 2019
Standardmäßig werden Aufträge auf dem Hostcomputer ausgeführt, auf dem der Agent installiert ist. Dies ist praktisch und eignet sich in der Regel gut für Projekte, bei denen gerade erst mit der Einführung von Azure Pipelines begonnen wird. Im Laufe der Zeit stellen Sie möglicherweise fest, dass Sie mehr Kontrolle über den Kontext wünschen, in dem Ihre Aufgaben ausgeführt werden. YAML-Pipelines bieten für diesen Grad an Kontrolle Containeraufträge.
Bei Linux- und Windows-Agents können Aufträge auf dem Host oder in einem Container ausgeführt werden. (Unter macOS und Red Hat Enterprise Linux 6 sind keine Containeraufträge verfügbar.) Container bieten Isolation vom Host und ermöglichen das Anheften bestimmter Versionen von Tools und Abhängigkeiten. Hostaufträge erfordern weniger anfängliche Einrichtung und zu wartende Infrastruktur.
Container bieten eine schlanke Abstraktion des Hostbetriebssystems. Sie können die genauen Versionen von Betriebssystemen, Tools und Abhängigkeiten auswählen, die für Ihren Build erforderlich sind. Wenn Sie in Ihrer Pipeline einen Container angeben, ruft der Agent zuerst den Container ab und startet ihn dann. Anschließend wird jeder Schritt des Auftrags innerhalb des Containers ausgeführt. Geschachtelte Container sind nicht möglich. Container werden nicht unterstützt, wenn ein Agent bereits in einem Container ausgeführt wird.
Wenn Sie eine differenzierte Steuerung auf der Ebene der einzelnen Schritte benötigen, können Sie mit Schrittzielen den Container oder Host für jeden Schritt auswählen.
Anforderungen
Linux-Container
Für das Azure Pipelines-System müssen in Linux-Containern einige Anforderungen erfüllt sein:
- Bash
- glibc-basiert
- Ausführen von Node.js (das der Agent bereitstellt) möglich
- Definiert keinen
ENTRYPOINT
USER
hat Zugriff aufgroupadd
und andere Berechtigungsbefehle ohnesudo
Und auf Ihrem Agent-Host gilt Folgendes:
- Docker muss installiert sein.
- Der Agent muss über die Berechtigung für Zugriff auf den Docker-Daemon verfügen.
Stellen Sie sicher, dass für Ihren Container jedes dieser Tools verfügbar ist. Einige der auf Docker Hub verfügbaren funktionsreduzierten Container, insbesondere diejenigen, die auf Alpine Linux basieren, erfüllen diese Mindestanforderungen nicht. Container mit ENTRYPOINT
funktionieren möglicherweise nicht, da Azure Pipelines mit docker create
einen wartenden Container erstellt und mit docker exec
eine Reihe von Befehlen ausführt, die erwarten, dass der Container stets in Betrieb ist.
Hinweis
Für Windows-basierte Linux-Container muss Node.js vorinstalliert sein.
Windows-Container
Azure Pipelines kann auch Windows-Container ausführen. Die Windows Server-Version 1803 ist mindestens erforderlich. Docker muss installiert sein. Stellen Sie sicher, dass Ihr Pipelines-Agent über die Berechtigung für den Zugriff auf den Docker-Daemon verfügt.
Der Windows-Container muss die Ausführung von Node.js unterstützen. In einem Windows Nano Server-Basiscontainer fehlen Abhängigkeiten, die zum Ausführen von Node.js erforderlich sind.
Gehostete Agents
Nur windows-2019
- und ubuntu-*
-Images unterstützen das Ausführen von Containern.
Das macOS-Image unterstützt das Ausführen von Containern nicht.
Einzelner Auftrag
Ein einfaches Beispiel:
pool:
vmImage: 'ubuntu-latest'
container: ubuntu:18.04
steps:
- script: printenv
Es weist das System an, das ubuntu
-Image mit dem Tag 18.04
von Docker Hub abzurufen und dann den Container zu starten. Wenn der Befehl printenv
ausgeführt wird, geschieht dies innerhalb des ubuntu:18.04
-Containers.
Windows-Beispiel:
pool:
vmImage: 'windows-2019'
container: mcr.microsoft.com/windows/servercore:ltsc2019
steps:
- script: set
Hinweis
Windows erfordert, dass die Kernelversion von Host und Container übereinstimmen.
In diesem Beispiel mit dem Windows 2019-Image verwenden wir das Tag 2019
für den Container.
Mehrere Aufträge
Container sind auch nützlich, um dieselben Schritte in mehreren Aufträgen auszuführen.
Im folgenden Beispiel werden dieselben Schritte in mehreren Versionen von Ubuntu Linux ausgeführt.
(Und wir müssen das Schlüsselwort jobs
nicht erwähnen, da nur ein einzelner Auftrag definiert ist.)
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
ubuntu16:
containerImage: ubuntu:16.04
ubuntu18:
containerImage: ubuntu:18.04
ubuntu20:
containerImage: ubuntu:20.04
container: $[ variables['containerImage'] ]
steps:
- script: printenv
Endpunkte
Container können in anderen Registrierungen als öffentlichen Docker Hub-Registrierungen gehostet werden. Um ein Image in Azure Container Registry oder einer anderen privaten Containerregistrierung (einschließlich einer privaten Docker Hub-Registrierung) zu hosten, fügen Sie eine Dienstverbindung zur privaten Registrierung hinzu. Anschließend können Sie in einer Containerspezifikation darauf verweisen:
container:
image: registry:ubuntu1804
endpoint: private_dockerhub_connection
steps:
- script: echo hello
oder
container:
image: myprivate.azurecr.io/windowsservercore:1803
endpoint: my_acr_connection
steps:
- script: echo hello
Andere Containerregistrierungen können ebenfalls funktionieren. Amazon ECR funktioniert derzeit nicht, da es andere Clienttools gibt, die erforderlich sind, um AWS-Anmeldeinformationen so zu konvertieren, das Docker sie zur Authentifizierung nutzen kann.
Hinweis
Der Red Hat Enterprise Linux 6-Build des Agents kann keinen Containerauftrag ausführen. Wählen Sie eine andere Linux-Variante aus, z. B. Red Hat Enterprise Linux 7 oder höher.
Tastatur
Wenn Sie den Containerstart steuern müssen, können Sie options
angeben.
container:
image: ubuntu:18.04
options: --hostname container-test --ip 192.168.0.1
steps:
- script: echo hello
Wenn Sie docker create --help
ausführen, erhalten Sie eine Liste der unterstützten Optionen. Sie können eine beliebige Option verwenden, die mit dem docker create
-Befehl verfügbar ist.
Definition wiederverwendbarer Container
Im folgenden Beispiel werden die Container im Abschnitt „resources“ definiert.
Auf jeden Container wird später verwiesen, indem auf den ihm zugewiesenen Alias verwiesen wird.
(Hier führen wir das Schlüsselwort jobs
der Klarheit halber explizit auf.)
resources:
containers:
- container: u16
image: ubuntu:16.04
- container: u18
image: ubuntu:18.04
- container: u20
image: ubuntu:20.04
jobs:
- job: RunInContainer
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
ubuntu16:
containerResource: u16
ubuntu18:
containerResource: u18
ubuntu20:
containerResource: u20
container: $[ variables['containerResource'] ]
steps:
- script: printenv
Nicht glibc-basierte Container
Der Azure Pipelines-Agent stellt eine Kopie von Node.js bereit, die zum Ausführen von Aufgaben und Skripts erforderlich ist. Informationen zum Ermitteln der Version von Node.js für einen gehosteten Agent finden Sie unter Von Microsoft gehostete Agents. Die Version von Node.js wird für die C-Runtime kompiliert, die wir in unserer gehosteten Cloud verwenden, in der Regel glibc. Einige Varianten von Linux verwenden andere C-Runtimes. Alpine Linux verwendet beispielsweise musl.
Wenn Sie einen nicht glibc-basierten Container als Auftragscontainer verwenden möchten, müssen Sie einige Dinge selbst in die Hand nehmen. Zunächst müssen Sie Ihre eigene Kopie von Node.js bereitstellen. Zweitens müssen Sie Ihrem Image eine Bezeichnung hinzufügen, die dem Agent mitteilt, wo er die Node.js-Binärdatei finden kann. Und schließlich fehlen im Funktionsumfang von Alpine weitere Abhängigkeiten, auf die Azure Pipelines angewiesen ist: bash, sudo, which und groupadd.
Nutzen einer eigenen Instanz von Node.js
Sie sind dafür verantwortlich, Ihrem Container eine Node.js-Binärdatei hinzuzufügen.
Node.js 14 ist eine sichere Wahl.
Sie können mit dem Image node:14-alpine
beginnen.
Informieren des Agents über Node.js
Der Agent liest die Containerbezeichnung com.azure.dev.pipelines.handler.node.path.
Wenn diese Bezeichnung vorhanden ist, muss sie der Pfad zur Node.js Binärdatei sein.
In einem auf node:10-alpine
basierenden Image fügen Sie beispielsweise diese Zeile in Ihre Dockerfile ein:
LABEL "com.azure.dev.pipelines.agent.handler.node.path"="/usr/local/bin/node"
Anforderungen hinzufügen
Azure Pipelines setzt ein Bash-basiertes System voraus, auf dem die üblichen Verwaltungspakete installiert sind.
Insbesondere Alpine Linux verfügt nicht über mehrere der benötigten Pakete.
Durch Installation von bash
, sudo
und shadow
werden die grundlegenden Anforderungen erfüllt.
RUN apk add bash sudo shadow
Wenn Sie von integrierten oder Marketplace-Aufgaben abhängig sind, müssen Sie auch die dafür erforderlichen Binärdateien bereitstellen.
Vollständiges Beispiel einer Dockerfile
FROM node:10-alpine
RUN apk add --no-cache --virtual .pipeline-deps readline linux-pam \
&& apk add bash sudo shadow \
&& apk del .pipeline-deps
LABEL "com.azure.dev.pipelines.agent.handler.node.path"="/usr/local/bin/node"
CMD [ "node" ]
Mehrere Aufträge mit Agent-Pools auf einem einzelnen gehosteten Agent
Der Containerauftrag verwendet die zugrunde liegende Docker-Datei „config.json“ für den Host-Agent zur Autorisierung der Imageregistrierung, die sich am Ende der Containerinitialisierung der Docker-Registrierung abmeldet. Die Autorisierung für nachfolgende Pulls des Images aus der Registrierung wird möglicherweise wegen „nicht autorisierter Authentifizierung“ verweigert, weil die im System für die Authentifizierung registrierte Docker-Datei „config.json“ bereits von einem der anderen parallel ausgeführten Containeraufträge abgemeldet wurde.
Die Lösung besteht darin, die Docker-Umgebungsvariable DOCKER_CONFIG
festzulegen, die für jeden Agent-Pooldienst spezifisch ist, der auf dem gehosteten Agent ausgeführt wird. Exportieren Sie DOCKER_CONFIG
im Skript „runsvc.sh“ der einzelnen Agent-Pools:
#insert anything to set up env when running as a service
export DOCKER_CONFIG=./.docker