Servicecontainers
Azure DevOps Services
Als voor uw pijplijn ondersteuning van een of meer services is vereist, moet u mogelijk de services per taak maken, er verbinding mee maken en opschonen. Uw pijplijn kan bijvoorbeeld integratietests uitvoeren waarvoor toegang tot een zojuist gemaakte database en geheugencache is vereist voor elke taak in de pijplijn.
Een container biedt een eenvoudige en draagbare manier om een service uit te voeren die afhankelijk is van uw pijplijn. Met een servicecontainer kunt u automatisch de levenscyclus van een containerservice maken, netwerken en beheren. Elke servicecontainer is alleen toegankelijk voor de taak waarvoor deze is vereist. Servicecontainers werken met elk soort taak, maar worden meestal gebruikt met containertaken.
Vereisten
Servicecontainers moeten een
CMD
ofENTRYPOINT
. De pijplijn wordt uitgevoerddocker run
voor de opgegeven container zonder argumenten.Azure Pipelines kan Linux- of Windows-containers uitvoeren. U kunt de gehoste Ubuntu-containergroep voor Linux-containers of de gehoste Windows-pool voor Windows-containers gebruiken. De gehoste macOS-pool biedt geen ondersteuning voor actieve containers.
Notitie
Servicecontainers worden niet ondersteund in klassieke pijplijnen.
Taak met één container
In het volgende voorbeeld van de YAML-pijplijndefinitie wordt één containertaak weergegeven.
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
De voorgaande pijplijn haalt de nginx
en buildpack-deps
containers op uit Docker Hub en start vervolgens de containers. De containers worden samen in een netwerk geplaatst, zodat ze elkaar op hun services
naam kunnen bereiken.
Vanuit deze taakcontainer wordt de nginx
hostnaam omgezet in de juiste services met behulp van Docker-netwerken. Alle containers in het netwerk maken automatisch alle poorten aan elkaar beschikbaar.
Eén niet-containertaak
U kunt ook servicecontainers zonder taakcontainer gebruiken, zoals in het volgende voorbeeld.
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
Met de voorgaande pijplijn worden de meest recente nginx
containers gestart. Omdat de taak niet wordt uitgevoerd in een container, is er geen automatische naamomzetting. In plaats daarvan kunt u services bereiken met behulp van localhost
. In het voorbeeld wordt de 8080:80
poort expliciet geleverd.
Een alternatieve methode is om een willekeurige poort dynamisch toe te wijzen tijdens runtime. U kunt deze dynamische poorten vervolgens openen met behulp van variabelen. Deze variabelen hebben de volgende vorm: agent.services.<serviceName>.ports.<port>
. In een Bash-script hebt u toegang tot variabelen met behulp van de procesomgeving.
In het voorgaande voorbeeld redis
wordt een willekeurige beschikbare poort op de host toegewezen. De agent.services.redis.ports.6379
variabele bevat het poortnummer.
Meerdere taken
Servicecontainers zijn ook handig voor het uitvoeren van dezelfde stappen voor meerdere versies van dezelfde service. In het volgende voorbeeld worden dezelfde stappen uitgevoerd op meerdere versies van PostgreSQL.
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
Poorten
Wanneer u een containerresource of een inlinecontainer aanroept, kunt u een matrix opgeven waarin ports
deze beschikbaar moet worden gesteld voor de container, zoals in het volgende voorbeeld.
resources:
containers:
- container: my_service
image: my_service:latest
ports:
- 8080:80
- 5432
services:
redis:
image: redis
ports:
- 6379/tcp
ports
Opgeven is niet vereist als uw taak wordt uitgevoerd in een container, omdat containers in hetzelfde Docker-netwerk standaard alle poorten automatisch aan elkaar blootstellen.
Als uw taak wordt uitgevoerd op de host, ports
moet u toegang krijgen tot de service. Een poort heeft het formulier <hostPort>:<containerPort>
of alleen <containerPort>
met een optionele /<protocol>
aan het einde. U kunt bijvoorbeeld 6379/tcp
een poort 6379
gebruiken tcp
die is gebonden aan een willekeurige poort op de hostcomputer.
Voor poorten die zijn gebonden aan een willekeurige poort op de hostcomputer, maakt de pijplijn een variabele van het formulier agent.services.<serviceName>.ports.<port>
, zodat de taak toegang heeft tot de poort. Wordt bijvoorbeeld agent.services.redis.ports.6379
omgezet in de willekeurig toegewezen poort op de hostcomputer.
Volumes
Volumes zijn handig voor het delen van gegevens tussen services of voor het behouden van gegevens tussen meerdere uitvoeringen van een taak. U geeft volumekoppelingen op als een matrix van volumes
het formulier <source>:<destinationPath>
, waar <source>
een benoemd volume of een absoluut pad op de hostcomputer kan zijn en <destinationPath>
een absoluut pad in de container is. Volumes kunnen Docker-volumes, anonieme Docker-volumes of bindingskoppelingen op de host zijn.
services:
my_service:
image: myservice:latest
volumes:
- mydockervolume:/data/dir
- /data/dir
- /src/dir:/dst/dir
Notitie
Als u door Microsoft gehoste pools gebruikt, worden uw volumes niet tussen taken bewaard, omdat de hostmachine wordt opgeschoond nadat elke taak is voltooid.
Opstartopties
Servicecontainers delen dezelfde containerbronnen als containertaken. Dit betekent dat u dezelfde opstartopties kunt gebruiken.
Statuscontrole
Als een servicecontainer een STATUSCONTROLE opgeeft, kan de agent eventueel wachten totdat de container in orde is voordat de taak wordt uitgevoerd.
Voorbeeld van meerdere containers met services
In het volgende voorbeeld is een Django Python-webcontainer verbonden met PostgreSQL- en MySQL-databasecontainers.
- De PostgreSQL-database is de primaire database en de container heeft de naam
db
. - De
db
container maakt gebruik van volume/data/db:/var/lib/postgresql/data
en er zijn drie databasevariabelen doorgegeven aan de container viaenv
. - De
mysql
container maakt gebruik van poort3306:3306
en er worden ook databasevariabelen doorgegeven viaenv
. - De
web
container is geopend met poort8000
.
In de stappen pip
installeert u afhankelijkheden en vervolgens worden Django-tests uitgevoerd.
Als u een werkvoorbeeld wilt instellen, hebt u een Django-site nodig die is ingesteld met twee databases. In het voorbeeld wordt ervan uitgegaan dat uw manage.py-bestand zich in de hoofdmap bevindt en uw Django-project zich ook in die map bevindt. Zo niet, dan moet u mogelijk het /__w/1/s/
pad bijwerken 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