Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Azure DevOps Services
In diesem Artikel wird die Verwendung von Dienstcontainern in Azure Pipelines beschrieben. 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 Dienstcontainer bietet eine einfache und portierbare Möglichkeit zum Ausführen von Diensten in Ihrer Pipeline. Auf den Dienstcontainer kann nur für den Auftrag zugegriffen werden, der ihn erfordert.
Mithilfe von Dienstcontainern können Sie die von Ihren Pipelines abhängigen Dienste automatisch erstellen, vernetzen und den Lebenszyklus verwalten. Dienstcontainer funktionieren mit jeder Art von Auftrag, werden jedoch am häufigsten mit Containeraufträgen verwendet.
Hinweis
Klassische Pipelines unterstützen keine Dienstcontainer.
Bedingungen und Einschränkungen
Dienstcontainer müssen
CMDoderENTRYPOINTdefinieren. Die Pipeline wird ohne Argumente für den bereitgestellten Container ausgeführtdocker run.Azure-Pipelines können Linux- oder Windows-Container ausführen. Sie verwenden den gehosteten Ubuntu-Pool für Linux-Container oder den gehosteten Windows-Pool für Windows-Container. Der gehostete macOS-Pool unterstützt keine Ausführung von Containern.
Dienstcontainer verwenden dieselben Containerressourcen wie Containeraufträge, sodass sie dieselben Startoptionen verwenden können.
Wenn ein Dienstcontainer einen HEALTHCHECK angibt, kann der Agent optional darauf warten, bis der Container gesund ist, bevor der Auftrag ausgeführt wird.
Auftrag mit einem einzelnen Container
Im folgenden Beispiel für die YAML-Pipeline wird ein einzelner Containerauftrag definiert, der einen Dienstcontainer verwendet. Die Pipeline ruft die buildpack-deps und nginx Container von Docker Hub ab und startet dann alle Container. Die Container sind vernetzt, damit sie sich über ihre Namen services erreichen können.
Von innerhalb des Auftragscontainers wird mithilfe von Docker-Netzwerkfunktionen der nginx Hostname zu den richtigen Diensten aufgelöst. Alle Container im Netzwerk machen automatisch alle Ports gegenseitig verfügbar.
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
Einzelner Nichtcontainerauftrag
Sie können auch Dienstcontainer in Nicht-Container-Aufträgen verwenden. Die Pipeline startet die neuesten Container, aber da der Job nicht in einem Container ausgeführt wird, gibt es keine automatische Namensauflösung. Stattdessen erreichen Sie Dienste mithilfe von localhost. Die folgende Beispielpipeline gibt explizit den 8080:80 Port für nginx.
Eine alternative Methode besteht darin, zur Laufzeit einen zufälligen Port dynamisch zuzuweisen. Damit der Auftrag auf den Port zugreifen kann, erstellt die Pipeline eine Variable in der Form agent.services.<serviceName>.ports.<port>. Sie können auf den dynamischen Port zugreifen, indem Sie diese Umgebungsvariable in einem Bash-Skript verwenden.
In der folgenden Pipeline erhält redis einen zufällig verfügbaren Port auf dem Host, und die Variable agent.services.redis.ports.6379 enthält die Portnummer.
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
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
Aufträge, die direkt auf dem Host ausgeführt werden, müssen ports auf den Dienstcontainer zugreifen. 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.
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.
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
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 definieren Volume-Einhängungen als ein Array von volumes.
Jedes Volume übernimmt die Form <source>:<destinationPath>, wobei <source> es sich entweder um ein benanntes Volume oder einen absoluten Pfad auf dem Host 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
Von Microsoft gehostete Pools speichern keine Volumes zwischen Aufträgen, da der Hostcomputer nach jedem Auftrag bereinigt wird.
Beispiel für mehrere Container mit Diensten
Die folgende Beispielpipeline verfügt über einen Django Python-Webcontainer, der mit PostgreSQL- und MySQL-Datenbankcontainern verbunden ist.
- Die PostgreSQL-Datenbank ist die primäre Datenbank, und ihr Container wird benannt
db. - Der
db-Container verwendet das Volume/data/db:/var/lib/postgresql/data, und übergibt drei Datenbankvariablen überenv. - Der
mysqlContainer verwendet Port3306:3306und übergibt auch Datenbankvariablen überenv. - Der Container
webist an Port8000geö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 und Ihr Django-Projekt im Stammverzeichnis befinden. 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