Dienstcontainer
Azure DevOps Services
Wenn Ihre Pipeline die Unterstützung eines oder mehrerer Dienste erfordert, müssen Sie möglicherweise die Dienste pro Auftrag erstellen, verbinden und bereinigen. Ihre Pipeline kann beispielsweise Integrationstests ausführen, die Zugriff auf eine neu erstellte Datenbank und einen Speichercache für jeden Auftrag in der Pipeline erfordern.
Ein Container bietet eine einfache und portierbare Möglichkeit zum Ausführen eines Diensts, von dem Ihre Pipeline abhängt. Mit einem Dienstcontainer können Sie den Lebenszyklus eines containerisierten Diensts automatisch erstellen, netzwerken und verwalten. Auf jeden Dienstcontainer kann nur auf den Auftrag zugegriffen werden, für den er erforderlich ist. Dienstcontainer funktionieren mit jeder Art von Auftrag, werden jedoch am häufigsten mit Containeraufträgen verwendet.
Anforderungen
Dienstcontainer müssen
CMD
oderENTRYPOINT
definieren. Die Pipeline wird für den bereitgestellten Container ohne Argumente ausgeführtdocker run
.Azure-Pipelines können Linux- oder Windows-Container ausführen. Sie können entweder den gehosteten Ubuntu-Containerpool für Linux-Container oder den gehosteten Windows-Pool für Windows-Container verwenden. Der gehostete macOS-Pool unterstützt keine Ausführung von Containern.
Hinweis
Dienstcontainer werden in klassischen Pipelines nicht unterstützt.
Auftrag mit einem einzelnen Container
Das folgende Beispiel für die YAML-Pipelinedefinition zeigt einen einzelnen Containerauftrag.
resources:
containers:
- container: my_container
image: buildpack-deps:focal
- container: nginx
image: nginx
pool:
vmImage: 'ubuntu-latest'
container: my_container
services:
nginx: nginx
steps:
- script: |
curl nginx
displayName: Show that nginx is running
Die vorangehende Pipeline ruft die nginx
Container und buildpack-deps
Container aus Docker Hub ab und startet dann die Container. Die Container sind miteinander vernetzt, sodass sie sich über ihren services
-Namen erreichen können.
Von innerhalb dieses Auftragscontainers wird der nginx
Hostname mithilfe von Docker-Netzwerk zu den richtigen Diensten aufgelöst. Alle Container im Netzwerk machen automatisch alle Ports gegenseitig verfügbar.
Einzelner Nichtcontainerauftrag
Sie können auch Dienstcontainer ohne Auftragscontainer verwenden, wie im folgenden Beispiel gezeigt.
resources:
containers:
- container: nginx
image: nginx
ports:
- 8080:80
env:
NGINX_PORT: 80
- container: redis
image: redis
ports:
- 6379
pool:
vmImage: 'ubuntu-latest'
services:
nginx: nginx
redis: redis
steps:
- script: |
curl localhost:8080
echo $AGENT_SERVICES_REDIS_PORTS_6379
Die vorangehende Pipeline startet die neuesten nginx
Container. Da der Auftrag nicht in einem Container ausgeführt wird, gibt es keine automatische Namensauflösung. Stattdessen können Sie Dienste mithilfe localhost
von . Das Beispiel stellt den 8080:80
Port explizit bereit.
Ein alternativer Ansatz besteht darin, einen zufälligen Port dynamisch zur Laufzeit zuzuweisen. Sie können dann mithilfe von Variablen auf diese dynamischen Ports zugreifen. Diese Variablen haben das folgende Format: agent.services.<serviceName>.ports.<port>
. In einem Bash-Skript können Sie mithilfe der Prozessumgebung auf Variablen zugreifen.
Im vorherigen Beispiel redis
wird dem Host ein zufällig verfügbarer Port zugewiesen. Die Variable agent.services.redis.ports.6379
enthält die Portnummer.
Mehrere Aufträge
Dienstcontainer sind auch nützlich, um dieselben Schritte für mehrere Versionen desselben Diensts auszuführen. Im folgenden Beispiel werden dieselben Schritte für mehrere Versionen von PostgreSQL ausgeführt.
resources:
containers:
- container: my_container
image: ubuntu:22.04
- container: pg15
image: postgres:15
- container: pg14
image: postgres:14
pool:
vmImage: 'ubuntu-latest'
strategy:
matrix:
postgres15:
postgresService: pg15
postgres14:
postgresService: pg14
container: my_container
services:
postgres: $[ variables['postgresService'] ]
steps:
- script: printenv
Ports
Wenn Sie eine Containerressource oder einen Inlinecontainer aufrufen, können Sie wie im folgenden Beispiel ein Array angeben, das ports
für den Container verfügbar gemacht werden soll.
resources:
containers:
- container: my_service
image: my_service:latest
ports:
- 8080:80
- 5432
services:
redis:
image: redis
ports:
- 6379/tcp
Die Angabe ports
ist nicht erforderlich, wenn Ihr Auftrag in einem Container ausgeführt wird, da Container im selben Docker-Netzwerk standardmäßig alle Ports automatisch füreinander verfügbar machen.
Wenn Ihr Auftrag auf dem Host ausgeführt wird, ports
müssen Sie auf den Dienst zugreifen. Ein Port übernimmt das Formular <hostPort>:<containerPort>
oder nur <containerPort>
mit einem optionalen /<protocol>
Ende. Beispielsweise 6379/tcp
wird tcp
über portiert 6379
, gebunden an einen zufälligen Port auf dem Hostcomputer.
Für Ports, die an einen zufälligen Port auf dem Hostcomputer gebunden sind, erstellt die Pipeline eine Variable des Formulars agent.services.<serviceName>.ports.<port>
, damit der Auftrag auf den Port zugreifen kann. Beispielsweise wird agent.services.redis.ports.6379
in den zufällig zugewiesenen Port auf dem Hostcomputer aufgelöst.
Volumes
Volumes eignen sich zum Freigeben von Daten zwischen Diensten oder zum Speichern von Daten zwischen mehreren Ausführungsläufen eines Auftrags. Sie geben Volume-Bereitstellungen als Array des volumes
Formulars <source>:<destinationPath>
an, wobei <source>
es sich um ein benanntes Volume oder einen absoluten Pfad auf dem Hostcomputer handelt und <destinationPath>
ein absoluter Pfad im Container ist. Volumes können Docker-Volumes, anonyme Docker-Volumes oder Bereitstellungen auf dem Host binden.
services:
my_service:
image: myservice:latest
volumes:
- mydockervolume:/data/dir
- /data/dir
- /src/dir:/dst/dir
Hinweis
Wenn Sie von Microsoft gehostete Pools verwenden, werden Ihre Volumes nicht zwischen Aufträgen beibehalten, da der Hostcomputer nach Abschluss der einzelnen Aufträge bereinigt wird.
Startoptionen
Dienstcontainer nutzen dieselben Containerressourcen wie Containeraufträge. Dies bedeutet, dass Sie dieselben Startoptionen verwenden können.
Integritätsprüfung
Wenn ein Dienstcontainer einen HEALTHCHECK angibt, kann der Agent optional warten, bis der Container fehlerfrei ist, bevor der Auftrag ausgeführt wird.
Beispiel für mehrere Container mit Diensten
Im folgenden Beispiel ist ein Django Python-Webcontainer mit PostgreSQL- und MySQL-Datenbankcontainern verbunden.
- Die PostgreSQL-Datenbank ist die primäre Datenbank, und ihr Container wird benannt
db
. - Der
db
Container verwendet Volume/data/db:/var/lib/postgresql/data
, und es gibt drei Datenbankvariablen, die anenv
den Container übergeben werden. - Der
mysql
Container verwendet Port3306:3306
, und es werden auch Datenbankvariablen übergebenenv
. - Der Container
web
ist an Port8000
geöffnet.
In den Schritten pip
werden Abhängigkeiten installiert und dann Django-Tests ausgeführt.
Zum Einrichten eines Funktionierenden Beispiels benötigen Sie eine Django-Website, die mit zwei Datenbanken eingerichtet ist. Im Beispiel wird davon ausgegangen, dass sich ihre manage.py Datei im Stammverzeichnis befindet und sich Ihr Django-Projekt ebenfalls in diesem Verzeichnis befindet. Wenn nicht, müssen Sie den /__w/1/s/
Pfad möglicherweise aktualisieren in /__w/1/s/manage.py test
.
resources:
containers:
- container: db
image: postgres
volumes:
- '/data/db:/var/lib/postgresql/data'
env:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
- container: mysql
image: 'mysql:5.7'
ports:
- '3306:3306'
env:
MYSQL_DATABASE: users
MYSQL_USER: mysql
MYSQL_PASSWORD: mysql
MYSQL_ROOT_PASSWORD: mysql
- container: web
image: python
volumes:
- '/code'
ports:
- '8000:8000'
pool:
vmImage: 'ubuntu-latest'
container: web
services:
db: db
mysql: mysql
steps:
- script: |
pip install django
pip install psycopg2
pip install mysqlclient
displayName: set up django
- script: |
python /__w/1/s/manage.py test