Dela via


Tjänstcontainrar

Azure DevOps-tjänster

Den här artikeln beskriver hur du använder tjänstcontainrar i Azure Pipelines. 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 tjänstcontainer ger ett enkelt och portabelt sätt att köra tjänster i din pipeline. Tjänstcontainern är endast tillgänglig för det jobb som kräver det.

Med tjänstcontainrar kan du automatiskt skapa, nätverka och hantera livscykeln för tjänster som dina pipelines är beroende av. Tjänstekontainrar fungerar med alla typer av jobb, men används oftast med containerjobb.

Kommentar

Klassiska pipelines stöder inte tjänstcontainrar.

Villkor och begränsningar

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

  • Azure Pipelines kan köra Linux- eller Windows-containrar. Du använder den värdbaserade Ubuntu-poolen för Linux-containrar eller den värdbaserade Windows-poolen för Windows-containrar. Den värdbaserade macOS-poolen stöder inte körning av containrar.

  • Tjänstcontainrar delar samma containerresurser som containerjobb, så att de kan använda samma startalternativ.

  • Om en tjänstcontainer anger en HEALTHCHECK kan agenten välja att vänta tills containern är i hälsosamt tillstånd innan jobbet körs.

Jobb med en enda container

I det följande exemplet definieras en YAML-pipeline med ett enda containerjobb som använder en servicecontainer. Pipelinen hämtar containrarna buildpack-deps och nginx från Docker Hub och startar sedan alla containrar. Containrarna är nätverkskopplade så att de kan nå varandra med sina services namn.

Inifrån 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.

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

Ett enda icke-kontainerjobb

Du kan också använda tjänstcontainer i icke-kontainerjobb. Pipelinen startar de senaste containrarna, men eftersom jobbet inte körs i en container, finns det ingen automatisk namnuppslagning. I stället kan du nå tjänster med hjälp av localhost. I följande exempelpipeline anges uttryckligen 8080:80 porten för nginx.

En annan metod är att tilldela en slumpmässig port dynamiskt vid körning. För att jobbet ska få åtkomst till porten skapar pipelinen en variabel i formuläret agent.services.<serviceName>.ports.<port>. Du kan komma åt den dynamiska porten med hjälp av den här miljövariabeln i ett Bash-skript.

I följande pipeline redis hämtar du en slumpmässig tillgänglig port på värden och variabeln agent.services.redis.ports.6379 innehåller portnumret.

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

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

Jobb som körs direkt på värden kräver ports för att få åtkomst till tjänstcontainern. Det är inte nödvändigt att specificera ports om ditt jobb körs i en container, eftersom containrar i samma Docker-nätverk automatiskt exponerar alla portar för varandra som standard.

En port tar formen <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.

När du anropar en containerresurs eller en infogad container kan du ange en matris av ports för att exponera dem på 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

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 med volumes.

Varje volym har formatet <source>:<destinationPath>, där <source> antingen är en namngiven volym eller en absolut sökväg på värden 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

Microsoft-hostade pooler bevarar inte volymer mellan jobb, eftersom värddatorn städas upp efter varje jobb.

Exempel på flera containrar med tjänster

I följande exempelpipeline 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/dataoch skickar tre databasvariabler till containern via env.
  • Containern mysql använder port 3306:3306och skickar även databasvariabler 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 och ditt Django-projekt finns i rotkatalogen. 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