Contentores de serviço
Azure DevOps Services
Se o pipeline necessitar do suporte de um ou mais serviços, em muitos casos, irá querer criar, ligar e limpar cada serviço numa base por tarefa. Por exemplo, um pipeline pode executar testes de integração que requerem acesso a uma base de dados e a uma cache de memória. A base de dados e a cache de memória têm de ser criadas recentemente para cada tarefa no pipeline.
Um contentor fornece uma forma simples e portátil de executar um serviço do qual o pipeline depende. Um contentor de serviço permite-lhe criar, rede e gerir automaticamente o ciclo de vida do seu serviço em contentores. Cada contentor de serviço é acessível apenas pela tarefa que o requer. Os contentores de serviço funcionam com qualquer tipo de trabalho, mas são utilizados com mais frequência com tarefas de contentor.
Requisitos
Os contentores de serviço têm de definir um CMD
ou ENTRYPOINT
.
O pipeline será executado docker run
para o contentor fornecido sem argumentos adicionais.
Os Pipelines do Azure podem executar Contentores Linux ou Windows. Utilize o Ubuntu alojado para contentores do Linux ou o Conjunto de Contentores do Windows alojado para contentores do Windows. (O conjunto de macOS alojado não suporta contentores em execução.)
Tarefa de contentor único
Um exemplo simples de utilização de tarefas de contentor:
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
Este pipeline obtém os nginx
contentores e buildpack-deps
do Docker Hub e, em seguida, inicia os contentores. Os contentores são agrupados em rede para que possam alcançar-se entre si pelo respetivo services
nome.
A partir deste contentor de tarefas, o nome do nginx
anfitrião é resolvido para os serviços corretos através da rede do Docker.
Todos os contentores na rede expõem automaticamente todas as portas entre si.
Tarefa única
Também pode utilizar contentores de serviço sem um contentor de tarefas. 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
Este pipeline inicia os contentores mais recentes nginx
. Uma vez que a tarefa não está em execução num contentor, não existe resolução automática de nomes.
Este exemplo mostra como pode, em vez disso, aceder aos serviços com localhost
.
No exemplo acima, fornecemos explicitamente a porta (por exemplo, 8080:80
).
Uma abordagem alternativa é permitir que uma porta aleatória seja atribuída dinamicamente no runtime. Em seguida, pode aceder a estas portas dinâmicas com variáveis.
Num script do Bash, pode aceder a uma variável com o ambiente de processo. Estas variáveis assumem o formulário: agent.services.<serviceName>.ports.<port>
.
No exemplo acima, redis
é atribuída uma porta disponível aleatória no anfitrião.
A agent.services.redis.ports.6379
variável contém o número da porta.
Várias tarefas
Os contentores de serviço também são úteis para executar os mesmos passos em várias versões do mesmo serviço. No exemplo seguinte, os mesmos passos são executados 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 contentor ou um contentor inline, pode especificar uma matriz de ports
para expor no contentor.
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 é necessária se a sua tarefa estiver em execução num contentor porque os contentores na mesma rede do Docker expõem automaticamente todas as portas entre si por predefinição.
Se a sua tarefa estiver em execução no anfitrião, será ports
necessário aceder ao serviço. Uma porta assume o formulário <hostPort>:<containerPort>
ou apenas <containerPort>
, com uma opcional /<protocol>
no final, por exemplo 6379/tcp
, para expor tcp
através da porta 6379
, vinculada a uma porta aleatória no computador anfitrião.
Para portas vinculadas a uma porta aleatória no computador anfitrião, o pipeline cria uma variável do formulário agent.services.<serviceName>.ports.<port>
para que possa ser acedido pela tarefa. Por exemplo, agent.services.redis.ports.6379
resolve para a porta atribuída aleatoriamente no computador anfitrião.
Volumes
Os volumes são úteis para partilhar dados entre serviços ou para dados persistentes entre várias execuções de uma tarefa.
Pode especificar montagens de volume como uma matriz de volumes
. Os volumes podem ser denominados volumes do Docker, volumes do Docker anónimos ou montagens de enlace no anfitrião.
services:
my_service:
image: myservice:latest
volumes:
- mydockervolume:/data/dir
- /data/dir
- /src/dir:/dst/dir
Os volumes assumem o formulário <source>:<destinationPath>
, onde <source>
pode ser um volume com nome ou um caminho absoluto no computador anfitrião e <destinationPath>
é um caminho absoluto no contentor.
Nota
Se utilizar os nossos conjuntos alojados, os volumes não serão mantidos entre tarefas porque o computador anfitrião é limpo após a conclusão da tarefa.
Outras opções
Os contentores de serviço partilham os mesmos recursos de contentor que as tarefas de contentor. Isto significa que pode utilizar as mesmas opções adicionais.
Verificação de estado de funcionamento
Opcionalmente, se um contentor de serviço especificar um HEALTHCHECK, o agente aguarda até que o contentor esteja em bom estado de funcionamento antes de executar a tarefa.
Exemplo de vários contentores com serviços
Neste exemplo, existe um contentor Web do Django Python ligado a dois contentores de base de dados - PostgreSQL e MySQL. A base de dados PostgreSQL é a base de dados primária e o respetivo contentor tem o nome db
. O db
contentor utiliza o volume /data/db:/var/lib/postgresql/data
e existem três variáveis de base de dados transmitidas para o contentor através de env
. O mysql
contentor utiliza a porta 3306:3306
e também existem variáveis de base de dados transmitidas através de env
. O web
contentor está aberto com a porta 8000
. Nos passos, pip
instala dependências e, em seguida, o teste django é executado. Se quiser configurar um exemplo de trabalho, precisará de um site django configurado com duas bases de dados. Este exemplo pressupõe que o seu manage.py
ficheiro está no diretório de raiz e que o projeto Django está dentro desse diretório. Poderá ter de atualizar o /__w/1/s/
caminho 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