Delen via


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 of ENTRYPOINT. De pijplijn wordt uitgevoerd docker 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 6379gebruiken 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/dataen er zijn drie databasevariabelen doorgegeven aan de container via env.
  • De mysql container maakt gebruik van poort 3306:3306en er worden ook databasevariabelen doorgegeven via env.
  • De web container is geopend met poort 8000.

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