Contêineres de serviço
Azure DevOps Services
Se o pipeline exigir o suporte de um ou mais serviços, em muitos casos você desejará criar, conectar e limpar cada serviço, por trabalho. Por exemplo, um pipeline pode executar testes de integração que exigem acesso a um banco de dados e a um cache de memória. O banco de dados e o cache de memória precisam ser criados recentemente para cada trabalho no pipeline.
Um contêiner fornece uma maneira simples e portátil de executar um serviço do qual seu pipeline depende. Um contêiner de serviço permite que você crie, interaja e gerencie o ciclo de vida do serviço em contêineres. Cada contêiner de serviço é acessível apenas pelo trabalho que o requer. Os contêineres de serviço funcionam com qualquer tipo de trabalho, mas são mais comumente usados com trabalhos de contêiner.
Requisitos
Os contêineres de serviço precisam definir um CMD
ou ENTRYPOINT
.
O pipeline executará docker run
para o contêiner fornecido, sem argumentos adicionais.
O Azure Pipelines pode executar contêineres do Linux ou do Windows. Use o Ubuntu hospedado para contêineres do Linux ou o pool de contêineres hospedado do Windows para contêineres do Windows. (O pool de macOS hospedado não dá suporte à execução de contêineres.)
Trabalho de contêiner único
Um exemplo simples de uso de trabalhos de contêiner:
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
Esse pipeline busca os contêineres nginx
e buildpack-deps
do Docker Hub e, em seguida, inicia os contêineres. Os contêineres são agrupados em rede para que possam alcançar uns aos outros pelo nome services
deles.
De dentro desse contêiner de trabalho, o nome do host nginx
é resolvido para os serviços corretos usando a rede do Docker.
Todos os contêineres na rede expõem automaticamente todas as portas uns para os outros.
Trabalho único
Você também pode usar contêineres de serviço sem um contêiner de trabalho. Um exemplo simples:
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
Esse pipeline inicia os nginx
contêineres mais recentes. Como o trabalho não está em execução em um contêiner, não há resolução automática de nomes.
Este exemplo mostra como você pode, em vez disso, acessar serviços usando localhost
.
No exemplo acima, fornecemos a porta explicitamente (por exemplo, 8080:80
).
Uma abordagem alternativa é permitir que uma porta aleatória seja atribuída dinamicamente em runtime. Em seguida, você pode acessar essas portas dinâmicas usando variáveis.
Em um script Bash, você pode acessar uma variável usando o ambiente de processo. Essas variáveis usam o seguinte formato: agent.services.<serviceName>.ports.<port>
.
No exemplo acima, uma porta disponível aleatória é atribuída a redis
no host.
A variável agent.services.redis.ports.6379
contém o número de versão.
Vários trabalhos
Os contêineres de serviço também são úteis para executar as mesmas etapas em várias versões do mesmo serviço. No exemplo a seguir, as mesmas etapas são executadas em várias versões do 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
Portas
Ao especificar um recurso de contêiner ou um contêiner embutido, você pode especificar uma matriz de ports
para expor no contêiner.
resources:
containers:
- container: my_service
image: my_service:latest
ports:
- 8080:80
- 5432
services:
redis:
image: redis
ports:
- 6379/tcp
A especificação ports
não será necessária se o trabalho estiver em execução em um contêiner, porque os contêineres na mesma rede do Docker expõem automaticamente todas as portas entre eles por padrão.
Se o trabalho estiver em execução no host, ports
será necessário acessar o serviço. Uma porta usa o formato <hostPort>:<containerPort>
ou apenas <containerPort>
, com um /<protocol>
opcional no final, por exemplo, 6379/tcp
, para expor tcp
pela porta 6379
, associada a uma porta aleatória no computador host.
Para portas associadas a uma porta aleatória no computador host, o pipeline cria uma variável no formato agent.services.<serviceName>.ports.<port>
para que possa ser acessado pelo trabalho. Por exemplo, agent.services.redis.ports.6379
resolve para a porta atribuída aleatoriamente no computador host.
Volumes
Os volumes são úteis para compartilhar dados entre serviços ou para manter dados entre várias execuções de um trabalho.
Você pode especificar montagens de volume como uma matriz de volumes
. Os volumes podem ser nomeados como volumes do Docker, volumes anônimos do Docker ou montagens de vinculação no host.
services:
my_service:
image: myservice:latest
volumes:
- mydockervolume:/data/dir
- /data/dir
- /src/dir:/dst/dir
Os volumes assumem o formato <source>:<destinationPath>
, em que <source>
pode ser um volume nomeado ou um caminho absoluto no computador host, e <destinationPath>
é um caminho absoluto no contêiner.
Observação
Se você usar nossos pools hospedados, os volumes não serão persistidos entre os trabalhos porque o computador host será limpo após a conclusão do trabalho.
Outras opções
Os contêineres de serviço compartilham os mesmos recursos de contêiner que os trabalhos de contêiner. Isso significa que você pode usar as mesmas opções adicionais.
Healthcheck
Opcionalmente, se qualquer contêiner de serviço especificar um HEALTHCHECK, o agente aguardará até que o contêiner esteja íntegro antes de executar o trabalho.
Exemplo de vários contêineres com serviços
Neste exemplo, há um contêiner Web do Django Python conectado a dois contêineres de banco de dados : PostgreSQL e MySQL. O banco de dados PostgreSQL é o banco de dados primário, e o contêiner dele tem o nome db
. O contêiner db
usa o volume /data/db:/var/lib/postgresql/data
e há três variáveis de banco de dados passadas para o contêiner por meio de env
. O contêiner mysql
usa a porta 3306:3306
, e também há variáveis de banco de dados passadas por meio de env
. O contêiner web
está aberto com a porta 8000
. Nas etapas, pip
instala dependências e, em seguida, o teste do Django é executado. Se você quiser configurar um exemplo de trabalho, precisará de um site do Django configurado com dois bancos de dados. Este exemplo pressupõe que o arquivo manage.py
esteja no diretório raiz e que o projeto do Django esteja dentro desse diretório. Talvez seja necessário atualizar o caminho /__w/1/s/
em /__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
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de