Tjänstcontainrar

Azure DevOps Services

Om din pipeline kräver stöd för en eller flera tjänster kan du behöva skapa, ansluta till och rensa tjänsterna per jobb. Din pipeline kan till exempel köra integreringstester som kräver åtkomst till en nyligen skapad databas och minnescachen för varje jobb i pipelinen.

En container är ett enkelt och bärbart sätt att köra en tjänst som din pipeline är beroende av. Med en tjänstcontainer kan du automatiskt skapa, nätverka och hantera livscykeln för en containerbaserad tjänst. Varje tjänstcontainer är endast tillgänglig för det jobb som kräver det. Tjänstcontainrar fungerar med alla typer av jobb, men används oftast med containerjobb.

Krav

  • Tjänstcontainrar måste definiera en CMD eller ENTRYPOINT. Pipelinen körs docker run för den angivna containern utan argument.

  • Azure Pipelines kan köra Linux- eller Windows-containrar. Du kan använda antingen den värdbaserade Ubuntu-containerpoolen för Linux-containrar eller den värdbaserade Windows-poolen för Windows-containrar. Den värdbaserade macOS-poolen stöder inte containrar som körs.

Kommentar

Tjänstcontainrar stöds inte i klassiska pipelines.

Jobb med en enda container

I följande exempel visar YAML-pipelinedefinitionen ett enda containerjobb.

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

Den föregående pipelinen hämtar containrarna nginx och buildpack-deps från Docker Hub och startar sedan containrarna. Containrarna är sammankopplade i nätverk så att de kan nå varandra med deras services namn.

Inifrån den här jobbcontainern nginx matchas värdnamnet till rätt tjänster med hjälp av Docker-nätverk. Alla containrar i nätverket exponerar automatiskt alla portar för varandra.

Ett enda icke-kontainerjobb

Du kan också använda tjänstcontainrar utan en jobbcontainer, som i följande exempel.

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

Den föregående pipelinen startar de senaste nginx containrarna. Eftersom jobbet inte körs i en container finns det ingen automatisk namnmatchning. I stället kan du nå tjänster med hjälp localhostav . Exemplet innehåller uttryckligen 8080:80 porten.

En annan metod är att låta en slumpmässig port tilldelas dynamiskt vid körning. Du kan sedan komma åt dessa dynamiska portar med hjälp av variabler. Dessa variabler har formatet : agent.services.<serviceName>.ports.<port>. I ett Bash-skript kan du komma åt variabler med hjälp av processmiljön.

I föregående exempel redis tilldelas en slumpmässig tillgänglig port på värden. Variabeln agent.services.redis.ports.6379 innehåller portnumret.

Flera jobb

Tjänstcontainrar är också användbara för att köra samma steg mot flera versioner av samma tjänst. I följande exempel körs samma steg mot flera versioner av 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

Hamnar

När du anropar en containerresurs eller en infogad container kan du ange en matris ports med som ska exponeras för containern, som i följande exempel.

resources:
  containers:
  - container: my_service
    image: my_service:latest
    ports:
    - 8080:80
    - 5432

services:
  redis:
    image: redis
    ports:
    - 6379/tcp

Det krävs inte att ports du anger om jobbet körs i en container, eftersom containrar i samma Docker-nätverk automatiskt exponerar alla portar för varandra som standard.

Om jobbet körs på värden ports måste du komma åt tjänsten. En port tar formuläret <hostPort>:<containerPort> eller bara <containerPort> med ett valfritt /<protocol> i slutet. Till exempel 6379/tcp exponeras tcp via port 6379, bunden till en slumpmässig port på värddatorn.

För portar som är bundna till en slumpmässig port på värddatorn skapar pipelinen en variabel i formuläret agent.services.<serviceName>.ports.<port> så att jobbet kan komma åt porten. Till exempel agent.services.redis.ports.6379 matchar den slumpmässigt tilldelade porten på värddatorn.

Volymer

Volymer är användbara för att dela data mellan tjänster eller för att bevara data mellan flera körningar av ett jobb. Du anger volymmonteringar som en matris i volumes formuläret <source>:<destinationPath>, där <source> kan vara en namngiven volym eller en absolut sökväg på värddatorn och <destinationPath> är en absolut sökväg i containern. Volymer kan namnges Docker-volymer, anonyma Docker-volymer eller bindningsmonteringar på värden.

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

Kommentar

Om du använder Microsoft-värdbaserade pooler sparas inte dina volymer mellan jobb eftersom värddatorn rensas när varje jobb har slutförts.

Startalternativ

Tjänstcontainrar delar samma containerresurser som containerjobb. Det innebär att du kan använda samma startalternativ.

Hälsokontroll

Om någon tjänstcontainer anger en HEALTHCHECK kan agenten eventuellt vänta tills containern är felfri innan jobbet körs.

Exempel på flera containrar med tjänster

I följande exempel finns en Django Python-webbcontainer ansluten till PostgreSQL- och MySQL-databascontainrar.

  • PostgreSQL-databasen är den primära databasen och dess container heter db.
  • Containern db använder volymen /data/db:/var/lib/postgresql/data, och det finns tre databasvariabler som skickas till containern via env.
  • Containern mysql använder port 3306:3306, och det finns även databasvariabler som skickas via env.
  • Containern web är öppen med port 8000.

I stegen pip installerar du beroenden och sedan körs Django-tester.

Om du vill konfigurera ett fungerande exempel behöver du en Django-webbplats som har konfigurerats med två databaser. Exemplet förutsätter att din manage.py-fil finns i rotkatalogen och att Django-projektet också finns i den katalogen. Annars kan du behöva uppdatera /__w/1/s/ sökvägen i /__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