Dienstcontainer
Azure DevOps Services
Wenn Ihre Pipeline durch Dienste unterstützt werden muss, sollten Sie in vielen Fällen auf Auftragsbasis jeden Dienst erstellen, eine Verbindung mit ihm herstellen und die Bereinigung durchführen. Beispielsweise kann eine Pipeline Integrationstests ausführen, die Zugriff auf eine Datenbank und einen Speichercache erfordern. Die Datenbank und der Arbeitsspeichercache müssen für jeden Auftrag in der Pipeline neu erstellt werden.
Ein Container bietet eine einfache und portierbare Möglichkeit zum Ausführen eines Diensts, von dem Ihre Pipeline abhängig ist. Mit einem Dienstcontainer können Sie den Lebenszyklus Ihres Containerdiensts automatisch erstellen, vernetzen und verwalten. Auf jeden Dienstcontainer kann nur der Auftrag zugreifen, der ihn benötigt. Dienstcontainer funktionieren mit jeder Art von Auftrag, werden aber am häufigsten mit Containeraufträgen verwendet.
Anforderungen
Dienstcontainer müssen CMD
oder ENTRYPOINT
definieren.
Die Pipeline führt docker run
für den bereitgestellten Container ohne zusätzliche Argumente aus.
Azure Pipelines kann Linux- oder Windows-Container ausführen. Verwenden Sie gehostete Ubuntu-für-Linux-Container oder den gehosteten Windows-Containerpool für Windows-Container. (Der gehostete macOS-Pool unterstützt keine ausgeführten Container.)
Auftrag mit einem einzelnen Container
Ein einfaches Beispiel für die Verwendung von Containeraufträgen:
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
Diese Pipeline ruft die Container nginx
und buildpack-deps
von Docker Hub ab und startet sie dann. Die Container sind miteinander vernetzt, sodass sie sich über ihren services
-Namen erreichen können.
Innerhalb dieses Auftragscontainers wird der nginx
-Hostname mithilfe des Docker-Netzwerks in die richtigen Dienste aufgelöst.
Alle Container im Netzwerk machen automatisch alle Ports gegenseitig verfügbar.
Einzelner Auftrag
Sie können Dienstcontainer auch ohne Auftragscontainer verwenden. Ein einfaches Beispiel:
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
Diese Pipeline startet die neuesten nginx
-Container. Da der Auftrag nicht in einem Container ausgeführt wird, gibt es keine automatische Namensauflösung.
In diesem Beispiel wird gezeigt, wie Sie Dienste stattdessen über localhost
erreichen können.
Im obigen Beispiel wird der Port explizit angegeben (z. B. 8080:80
).
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.
In einem Bash-Skript können Sie über die Prozessumgebung auf eine Variable zugreifen. Diese Variablen haben das folgende Format: agent.services.<serviceName>.ports.<port>
.
Im obigen Beispiel wird redis
ein zufällig verfügbarer Port auf dem Host 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 angeben, können Sie ein Array von ports
angeben, die für den Container verfügbar gemacht werden sollen.
resources:
containers:
- container: my_service
image: my_service:latest
ports:
- 8080:80
- 5432
services:
redis:
image: redis
ports:
- 6379/tcp
Die Angabe von ports
ist nicht erforderlich, wenn der Auftrag in einem Container ausgeführt wird, da Container im selben Docker-Netzwerk standardmäßig automatisch alle Ports füreinander verfügbar machen.
Wenn der Auftrag auf dem Host ausgeführt wird, sind ports
zu Zugreifen auf den Dienst erforderlich. Ein Port hat die Form <hostPort>:<containerPort>
oder einfach <containerPort>
mit einem optionalen /<protocol>
am Ende, z. B. 6379/tcp
, um tcp
über Port 6379
, gebunden an einen zufälligen Port auf dem Hostcomputer, verfügbar zu machen.
Für Ports, die an einen zufälligen Port auf dem Hostcomputer gebunden sind, erstellt die Pipeline eine Variable im Format agent.services.<serviceName>.ports.<port>
, sodass der Auftrag darauf zugreifen kann. Beispielsweise wird agent.services.redis.ports.6379
in den zufällig zugewiesenen Port auf dem Hostcomputer aufgelöst.
Volumes
Volumes sind nützlich für die gemeinsame Nutzung von Daten zwischen Diensten oder das Beibehalten von Daten zwischen mehreren Ausführungen eines Auftrags.
Sie können Volumeeinbindungen als Array von volumes
angeben. Volumes können benannte Docker-Volumes, anonyme Docker-Volumes oder Einbindungen auf dem Host sein.
services:
my_service:
image: myservice:latest
volumes:
- mydockervolume:/data/dir
- /data/dir
- /src/dir:/dst/dir
Volumes haben die Form <source>:<destinationPath>
, wobei <source>
ein benanntes Volume oder ein absoluter Pfad auf dem Hostcomputer sein kann und <destinationPath>
ein absoluter Pfad im Container ist.
Hinweis
Wenn Sie unsere gehosteten Pools verwenden, werden Ihre Volumes nicht zwischen Aufträgen beibehalten, da der Hostcomputer nach Abschluss des Auftrags bereinigt wird.
Weitere Optionen
Dienstcontainer nutzen dieselben Containerressourcen wie Containeraufträge. Sie können daher dieselben zusätzlichen Optionen verwenden.
Healthcheck
Wenn ein Dienstcontainer HEALTHCHECK angibt, wartet der Agent optional, bis der Container fehlerfrei ist, bevor er den Auftrag ausführt.
Beispiel für mehrere Container mit Diensten
In diesem Beispiel ist ein Django-Python-Webcontainer mit zwei Datenbankcontainern verbunden: PostgreSQL und MySQL. Die PostgreSQL-Datenbank ist die primäre Datenbank, deren Container den Namen db
hat. Der Container db
verwendet das Volume /data/db:/var/lib/postgresql/data
, und es werden drei Datenbankvariablen über env
an den Container übergeben. Der Container mysql
verwendet das Port 3306:3306
, und es werden außerdem Datenbankvariablen über env
übergeben. Der Container web
ist an Port 8000
geöffnet. In den Schritten installiert pip
Abhängigkeiten, und dann werden Django-Tests ausgeführt. Wenn Sie ein funktionierendes Beispiel einrichten möchten, benötigen Sie eine Django-Site mit zwei Datenbanken. In diesem Beispiel wird davon ausgegangen, dass sich Ihre Datei manage.py
im Stammverzeichnis und Ihr Django-Projekt ebenfalls in diesem Verzeichnis befindet. Möglicherweise müssen Sie den Pfad /__w/1/s/
in /__w/1/s/manage.py test
aktualisieren.
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
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für