Servicecontainers

Azure DevOps Services

Als uw pijplijn ondersteuning van een of meer services vereist, wilt u in veel gevallen elke service per taak maken, verbinden en opschonen. Een pijplijn kan bijvoorbeeld integratietests uitvoeren waarvoor toegang tot een database en een geheugencache is vereist. De database en geheugencache moeten nieuw worden gemaakt voor elke taak in de pijplijn.

Een container biedt een eenvoudige en draagbare manier om een service uit te voeren waarvan uw pijplijn afhankelijk is. Met een servicecontainer kunt u automatisch de levenscyclus van uw containerservice maken, netwerken en beheren. Elke servicecontainer is alleen toegankelijk voor de taak waarvoor deze is vereist. Servicecontainers werken met elk type taak, maar ze worden het meest gebruikt met containertaken.

Vereisten

Servicecontainers moeten een CMD of ENTRYPOINTdefiniëren. De pijplijn wordt zonder extra argumenten uitgevoerd docker run voor de opgegeven container.

Azure Pipelines kan Linux- of Windows-containers uitvoeren. Gebruik gehoste Ubuntu voor Linux-containers of de gehoste Windows-containergroep voor Windows-containers. (De gehoste macOS-pool biedt geen ondersteuning voor actieve containers.)

Taak met één container

Een eenvoudig voorbeeld van het gebruik van containertaken:

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

Deze pijplijn haalt de nginx containers en buildpack-deps op uit Docker Hub en start vervolgens de containers. De containers zijn aan elkaar gekoppeld, 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 alle poorten automatisch beschikbaar voor elkaar.

Eén taak

U kunt ook servicecontainers zonder taakcontainer gebruiken. Een eenvoudig 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 deze pijplijn worden de meest recente nginx containers gestart. Omdat de taak niet wordt uitgevoerd in een container, is er geen automatische naamomzetting. In dit voorbeeld ziet u hoe u in plaats daarvan services kunt bereiken met behulp van localhost. In het bovenstaande voorbeeld geven we de poort expliciet op (bijvoorbeeld 8080:80).

Een alternatieve benadering is om een willekeurige poort dynamisch te laten toewijzen tijdens runtime. U kunt deze dynamische poorten vervolgens openen met behulp van variabelen. In een Bash-script hebt u toegang tot een variabele met behulp van de procesomgeving. Deze variabelen hebben de vorm: agent.services.<serviceName>.ports.<port>. In het bovenstaande voorbeeld redis krijgt 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 voor 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 opgeeft, kunt u een matrix van ports opgeven voor de container.

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 automatisch alle poorten aan elkaar blootstellen.

Als uw taak wordt uitgevoerd op de host, ports moet u toegang krijgen tot de service. Een poort heeft de vorm <hostPort>:<containerPort> of alleen <containerPort>, met een optionele /<protocol> aan het einde, bijvoorbeeld 6379/tcp om beschikbaar te maken tcp via poort 6379, 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 de vorm agent.services.<serviceName>.ports.<port> , zodat deze kan worden geopend door de taak. 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 persistent maken van gegevens tussen meerdere uitvoeringen van een taak.

U kunt volumekoppelingen opgeven als een matrix van volumes. Volumes kunnen de naam Docker-volumes, anonieme Docker-volumes of bindingskoppelingen op de host hebben.

services:
  my_service:
    image: myservice:latest
    volumes:
    - mydockervolume:/data/dir
    - /data/dir
    - /src/dir:/dst/dir

Volumes hebben de vorm <source>:<destinationPath>, waarbij <source> een benoemd volume of een absoluut pad op de hostcomputer kan zijn en <destinationPath> een absoluut pad in de container is.

Notitie

Als u onze gehoste pools gebruikt, blijven uw volumes niet behouden tussen taken omdat de hostcomputer wordt opgeschoond nadat de taak is voltooid.

Andere opties

Servicecontainers delen dezelfde containerresources als containertaken. Dit betekent dat u dezelfde extra opties kunt gebruiken.

Statuscontrole

Als een servicecontainer een STATUSCONTROLE opgeeft, wacht de agent optioneel totdat de container in orde is voordat de taak wordt uitgevoerd.

Voorbeeld van meerdere containers met services

In dit voorbeeld is er een Django Python-webcontainer verbonden met twee databasecontainers: PostgreSQL en MySQL. 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 worden drie databasevariabelen aan de container doorgegeven via env. De mysql container maakt gebruik van poort 3306:3306 en er worden ook databasevariabelen doorgegeven via env. De web container is geopend met poort 8000. In de stappen pip installeert u afhankelijkheden en vervolgens wordt de Django-test uitgevoerd. Als u een werkend voorbeeld wilt instellen, moet u een Django-site instellen met twee databases. In dit voorbeeld wordt ervan uitgegaan dat uw manage.py bestand zich in de hoofdmap bevindt en uw Django-project zich in die map bevindt. Mogelijk moet u 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