Контейнеры служб

Azure DevOps Services

Если конвейеру требуется поддержка одной или нескольких служб, может потребоваться создать, подключиться и очистить службы для каждого задания. Например, конвейер может выполнять тесты интеграции, требующие доступа к созданной базе данных и кэшу памяти для каждого задания в конвейере.

Контейнер предоставляет простой и переносимый способ запуска службы, от которой зависит конвейер. Контейнер службы позволяет автоматически создавать, сети и управлять жизненным циклом контейнерной службы. Каждый контейнер службы доступен только для задания , требующего его. Контейнеры служб работают с любым типом заданий, но чаще всего используются с заданиями контейнеров.

Требования

  • Контейнеры служб должны определять CMD или ENTRYPOINT. Конвейер выполняется docker run для предоставленного контейнера без каких-либо аргументов.

  • Azure Pipelines может запускать контейнеры Linux или Windows. Вы можете использовать размещенный пул контейнеров Ubuntu для контейнеров Linux или размещенный пул Windows для контейнеров Windows. Размещенный пул macOS не поддерживает выполнение контейнеров.

Примечание.

Контейнеры служб не поддерживаются в классических конвейерах.

Одно задание контейнера

В следующем примере определения конвейера YAML показано одно задание контейнера.

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

Предыдущий конвейер извлекает nginx контейнеры buildpack-deps из Docker Hub и запускает контейнеры. Контейнеры объединяются в сеть, чтобы они могли связаться друг с другом по services их имени.

В этом контейнере nginx заданий имя узла разрешается в правильные службы с помощью сети Docker. Все контейнеры в сети автоматически предоставляют все порты друг другу.

Одно неконтайнерное задание

Контейнеры служб также можно использовать без контейнера заданий, как показано в следующем примере.

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

Предыдущий конвейер запускает последние nginx контейнеры. Так как задание не выполняется в контейнере, автоматическое разрешение имен отсутствует. Вместо этого можно получить доступ к службам с помощью localhost. В примере явно предоставляется 8080:80 порт.

Альтернативный подход — позволить случайному порту динамически назначаться во время выполнения. Затем вы можете получить доступ к этим динамическим портам с помощью переменных. Эти переменные принимают форму: agent.services.<serviceName>.ports.<port> В скрипте Bash можно получить доступ к переменным с помощью среды процесса.

В предыдущем примере redis назначается случайный доступный порт на узле. Переменная agent.services.redis.ports.6379 содержит номер порта.

Несколько заданий

Контейнеры служб также полезны для выполнения одних и тех же шагов в нескольких версиях одной службы. В следующем примере те же действия выполняются в нескольких версиях 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

Порты

При вызове ресурса контейнера или встроенного контейнера можно указать массив ports для предоставления в контейнере, как показано в следующем примере.

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

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

Указание ports не требуется, если задание выполняется в контейнере, так как контейнеры в одной сети Docker автоматически предоставляют все порты друг другу по умолчанию.

Если задание выполняется на узле, ports требуется для доступа к службе. Порт принимает форму <hostPort>:<containerPort> или просто <containerPort> с необязательным /<protocol> в конце. Например, 6379/tcp предоставляется tcp через порт 6379, привязанный к случайному порту на хост-компьютере.

Для портов, привязанных к случайному порту на хост-компьютере, конвейер создает переменную формы agent.services.<serviceName>.ports.<port> , чтобы задание получите доступ к порту. Например, agent.services.redis.ports.6379 разрешается на случайный назначенный порт на хост-компьютере.

Объемы

Тома полезны для совместного использования данных между службами или сохранения данных между несколькими запусками задания. Вы указываете тома в виде массива volumes формы <source>:<destinationPath>, где <source> может быть именованный том или абсолютный путь на хост-компьютере и <destinationPath> является абсолютным путем в контейнере. Тома можно назвать томами Docker, анонимными томами Docker или привязывать подключения к узлу.

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

Примечание.

Если вы используете пулы, размещенные Корпорацией Майкрософт, тома не сохраняются между заданиями, так как главный компьютер очищается после завершения каждого задания.

Параметры запуска

Контейнеры служб используют те же ресурсы контейнеров, что и задания контейнеров. Это означает, что можно использовать те же параметры запуска.

Проверка работоспособности

Если какой-либо контейнер службы указывает HEALTHCHECK, агент может при необходимости ждать, пока контейнер не будет работоспособным перед выполнением задания.

Пример нескольких контейнеров со службами

В следующем примере есть веб-контейнер Django Python, подключенный к контейнерам баз данных PostgreSQL и MySQL.

  • База данных PostgreSQL — это база данных-источник, а ее контейнер называется db.
  • Контейнер db использует том /data/db:/var/lib/postgresql/data, и через контейнер envпередаются три переменные базы данных.
  • Контейнер mysql использует порт 3306:3306, а также передаются переменные envбазы данных.
  • web Контейнер открыт с помощью порта8000.

На этом шаге pip устанавливаются зависимости, а затем выполняются тесты Django.

Чтобы настроить рабочий пример, необходимо настроить сайт Django с двумя базами данных. В примере предполагается , что файл manage.py находится в корневом каталоге, а проект Django также находится в этом каталоге. В противном случае может потребоваться обновить /__w/1/s/ путь /__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