Контейнеры служб
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