Contenedores de servicio
Azure DevOps Services
Si la canalización requiere la compatibilidad de uno o varios servicios, en muchos casos querrá crear, conectar y limpiar cada servicio por trabajo. Por ejemplo, una canalización puede ejecutar pruebas de integración que requieran acceso a una base de datos y una memoria caché. La base de datos y la memoria caché deben crearse de nuevo para cada trabajo de la canalización.
Un contenedor proporciona una manera sencilla y portátil de ejecutar un servicio del que depende la canalización. Un contenedor de servicio le permite crear, conectar en red y administrar automáticamente el ciclo de vida del servicio de contenedor. Solo el trabajo que lo requiere puede acceder a cada contenedor de servicios. Los contenedores de servicio funcionan con cualquier tipo de trabajo, pero se usan con mayor frecuencia con trabajos de contenedor.
Requisitos
Los contenedores de servicio deben definir CMD
o ENTRYPOINT
.
La canalización ejecutará docker run
para el contenedor proporcionado sin argumentos adicionales.
Azure Pipelines puede ejecutar contenedores Windows o Linux. Use Ubuntu hospedado para contenedores Linux o el grupo de contenedores Windows hospedados para contenedores de Windows. (El grupo de macOS hospedado no admite la ejecución de contenedores).
Trabajo en un contenedor único
Un ejemplo sencillo de uso de trabajos de contenedor:
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
Esta canalización captura los contenedores nginx
y buildpack-deps
de Docker Hub y, a continuación, los inicia. Los contenedores están conectados en red para que puedan comunicarse entre sí por su nombre services
.
Desde dentro de este contenedor de trabajo, el nombre de host nginx
se resuelve en los servicios correctos mediante redes de Docker.
Todos los contenedores de la red exponen automáticamente todos los puertos entre sí.
Trabajo individual
También puede usar contenedores de servicio sin un contenedor de trabajo. Un ejemplo sencillo:
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
Esta canalización inicia los contenedores nginx
más recientes. Dado que el trabajo no se está ejecutando en un contenedor, no hay ninguna resolución de nombres automática.
En este ejemplo se muestra cómo puede llegar a los servicios mediante localhost
.
En el ejemplo anterior, se proporciona explícitamente el puerto (por ejemplo, 8080:80
).
Un enfoque alternativo consiste en permitir que un puerto aleatorio se asigne dinámicamente en tiempo de ejecución. A continuación, puede acceder a estos puertos dinámicos mediante variables.
En un script de Bash, puede acceder a una variable mediante el entorno de proceso. Estas variables tienen el formato: agent.services.<serviceName>.ports.<port>
.
En el ejemplo anterior, redis
se asigna un puerto disponible aleatorio en el host.
La variable agent.services.redis.ports.6379
contiene el número de puerto.
Varios trabajos
Los contenedores de servicio también son útiles para ejecutar los mismos pasos en varias versiones del mismo servicio. En el siguiente ejemplo, los mismos pasos se ejecutan en varias versiones de 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
Puertos
Al especificar un recurso de contenedor o un contenedor alineado, puede especificar una matriz de ports
para exponer en el contenedor.
resources:
containers:
- container: my_service
image: my_service:latest
ports:
- 8080:80
- 5432
services:
redis:
image: redis
ports:
- 6379/tcp
No es necesario especificar ports
si el trabajo se ejecuta en un contenedor porque los contenedores de la misma red de Docker exponen automáticamente todos los puertos entre sí de forma predeterminada.
Si el trabajo se ejecuta en el host, entonces ports
es necesario para acceder al servicio. Un puerto toma el formato <hostPort>:<containerPort>
o simplemente <containerPort>
, con un /<protocol>
opcional al final, por ejemplo 6379/tcp
para exponer tcp
a través del puerto 6379
, enlazado a un puerto aleatorio en el equipo host.
Para los puertos enlazados a un puerto aleatorio en el equipo host, la canalización crea una variable del formato agent.services.<serviceName>.ports.<port>
para que el trabajo pueda acceder a él. Por ejemplo, agent.services.redis.ports.6379
se resuelve en el puerto asignado aleatoriamente en el equipo host.
Volúmenes
Los volúmenes son útiles para compartir datos entre servicios o para conservar datos entre varias ejecuciones de un trabajo.
Puede especificar montajes de volumen como una matriz de volumes
. Los volúmenes pueden ser volúmenes Docker con nombre, anónimos o montajes de enlace en el host.
services:
my_service:
image: myservice:latest
volumes:
- mydockervolume:/data/dir
- /data/dir
- /src/dir:/dst/dir
Los volúmenes tienen el formato <source>:<destinationPath>
, donde <source>
puede ser un volumen con nombre o una ruta de acceso absoluta en el equipo host y <destinationPath>
es una ruta de acceso absoluta en el contenedor.
Nota:
Si usa nuestros grupos hospedados, los volúmenes no se conservarán entre los trabajos porque el equipo host se limpia una vez completado el trabajo.
Otras opciones
Los contenedores de servicio comparten los mismos recursos de contenedor que los trabajos de contenedor. Esto significa que puede usar las mismas opciones adicionales.
Healthcheck
Si lo desea, si algún contenedor de servicios especifica un HEALTHCHECK, el agente espera hasta que el contenedor esté en buen estado antes de ejecutar el trabajo.
Ejemplo de varios contenedores con servicios
En este ejemplo, hay un contenedor web de Django de Python conectado a dos contenedores de base de datos: PostgreSQL y MySQL. La base de datos PostgreSQL es la base de datos principal y su contenedor tiene el nombre db
. El contenedor db
usa el volumen /data/db:/var/lib/postgresql/data
y hay tres variables de base de datos que se pasan al contenedor a través de env
. El contenedor mysql
usa el puerto 3306:3306
y también hay variables de base de datos pasadas a través de env
. El contenedor web
está abierto con el puerto 8000
. En los pasos, pip
instala las dependencias y, a continuación, se ejecuta la prueba de Django. Si quiere configurar un ejemplo de trabajo, necesitará un sitio de Django configurado con dos bases de datos. En este ejemplo se supone que el archivo manage.py
está en el directorio raíz y que el proyecto de Django está dentro de ese directorio. Es posible que tenga que actualizar el trazado /__w/1/s/
en /__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
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de