Introducción a Docker Compose
May 09, 2021 ‧ 30 min estimados ‧ #docker #docker-compose #multicontainer |
Contenido Características de Docker Compose |
Docker Compose es una herramienta que sirve para llevar a un nivel superior la ejecución tradicional de contenedores de Docker. Lo que vas a ver en este documento son los siguientes temas:
Docker es una herramienta que utiliza la tecnología de contenedores para configurar e implementar aplicaciones. Permite controlar de manera eficiente los entornos y sus ciclos de vida, y establece un marco de trabajo para poder desplegar aplicaciones de igual manera en diferentes plataformas. Entre algunas de sus ventajas podemos encontrar las siguientes:
A la hora de trabajar con docker se crean imágenes, se inician contenedores, se configuran redes y volúmenes para compartir información, y se gestionan Dockerfiles y registries para obtener y publicar imágenes. Veamos brevemente algunas de estas partes para luego entender de mejor manera la herramienta Docker Compose.
Arquitectura de Docker
La arquitectura de Docker está formada por capas. La capa inferior es el hardware físico donde corre el sistema. La segunda capa es el sistema operativo host (Linux, Windows, MacOS). Sobre el sistema operativo se instala el engine de Docker. Sobre el engine de Docker se manejan los objetos de Docker que están formados por imágenes y contenedores.
Images
Son plantillas que describen cómo está dispuesto un contenedor. Las imágenes se componen de una base y sobre ésta las modificaciones especiales que necesites para una aplicación.
Containers
Son las instancias en ejecución de una imagen. Podés crear, iniciar, detener, mover o eliminar un contenedor mediante la API o CLI de Docker. También podés conectar un contenedor a una o más redes, asignarle almacenamiento o incluso crear una nueva imagen basada en su estado actual.
Dockerfiles
Los Dockerfiles son la forma de convertir tu aplicación en un contenedor. Representan los pasos para construir un contenedor a medida con los requerimientos y lógica que necesita cada aplicación. Si querés crear un contenedor personalizado necesitás escribir un Dockerfile.
Networks
Docker utiliza una interfaz virtual para comunicarse con la red del equipo host. A su vez, podés crear configuraciones especiales de redes para comunicar a los contenedores. Incluso, los contenedores pueden pertenecer a más de una red.
Volumes
Los volúmenes permiten tener un espacio de almacenamiento dentro de cada contenedor. Por lo general los volúmenes se usan para compartir datos/archivos entre el host y vendría a ser un mecanismo similar al de carpetas compartidas de las máquinas virtuales.
Registry
Un registry es un banco de imágenes de Docker. Es un registro público que se puede utilizar libremente, y el engine de Docker está configurado para buscar imágenes en DockerHub de forma predeterminada. También es posible que tengas tu propio registro privado.
Ahora que ya hicimos un repaso por las principales partes del ecosistema Docker, pasemos a otro tema: la ejecución de contenedores.
A la hora de correr aplicaciones complejas a través de contenedores de Docker, es necesario desplegar varios servicios para que estas puedan funcionar. Un diagrama de arquitectura típico podría parecerse al que ves en la siguiente imagen, con clientes accediendo a un proxy, y detrás de éste una aplicación web junto con otros servicios de administración, más una base de datos, por nombrar solo un ejemplo.
Como podrás imaginar, cada uno de estos servicios necesita configuraciones especiales para poder funcionar, tales como archivos de inicialización, variables de entornos, acceso a puertos, comunicaciones con otros servicios, entre otros. Administrar la ejecución de estos servicios con el tradicional comando docker run puede resultar realmente complejo, difícil de mantener y poco escalable.
Para que veas un ejemplo, el comando a continuación muestra cómo ejecutar una base de datos MySQL con algunos argumentos de ejecución.
docker run \ --rm --detach \ --name mysql-server \ --network mysql-net \ --volume /home/app/db:/var/lib/mysql \ |
Imaginate la ejecución de este tipo de comandos para poder correr cada uno de los servicios que necesita tu aplicación. ¿Cómo acordarte de qué argumentos necesita cada uno? Bueno, en este punto las cosas comienzan a complejizarse un poco.
Como primera solución podrías pensar en crear un script de bash para automatizar el despliegue. Continuando con el ejemplo anterior de la base de datos, el siguiente script de bash muestra cómo correr el comando anterior con solo dos argumentos.
#!/bin/bash --rm --detach \ --name mysql-server \ --network $NETWORK_NAME \ --volume $DATABASE_DIR:/var/lib/mysql \ |
El problema en este punto resultaría más sencillo, y para correr el script (suponiendo que se llama start_mysql.sh), el comando que deberías ejecutar sería como el siguiente:
./start_mysql.sh mysql-net "$PWD"/database |
Si bien utilizar un script como este facilita los comandos de ejecución, si tuvieras que coordinar los múltiples contenedores de una app, de qué manera iniciar los servicios, qué pasa si un servicio falla, qué datos comparten los contenedores entre sí, y demás; te resultaría una tarea muy compleja , y es en este punto donde entra en juego Docker Compose.
Docker Compose es una herramienta del ecosistema Docker que sirve para definir aplicaciones multicontenedor en un archivo de texto llamado docker-compose.yml. Dentro de este archivo podés configurar prácticamente las mismas propiedades para los contenedores como si lo hicieras desde el comando docker run o mediante un script, configurando además el comportamiento de los contenedores entre sí, redes de comunicación, volúmenes, entre otros.
Es una herramienta ideal para el desarrollo y testing de aplicaciones, así como también para configurar distintos flujos de integración continua y escenarios de prueba. Algunas de las características más populares de Docker Compose son:
Una vez que definas el comportamiento de la aplicación en el archivo docker-compose.yml, la herramienta te permite iniciar con un único comando todos los contenedores en el orden especificado. En cierto modo, el archivo docker-compose.yml funciona también como documentación, ya que podés ver qué servicios, imágenes, volúmenes, enlaces y demás propiedades tiene la aplicación.
En esta imagen podés ver un ejemplo en el que dentro del archivo docker-compose.yml se definen 3 contenedores; todos ellos están conectados entre sí a través de la APP network. Además, el contenedor 1 y 2 comparten el APP volume. Por último, es posible acceder a la aplicación a través del contenedor 3 que expone un puerto fuera de sí mismo.
Un caso real donde resulta útil usar Docker Compose es un sitio web desarrollado con WordPress, donde se necesita un servidor web con soporte para PHP y una base de datos para almacenar los datos de las páginas (usuarios, artículos, datos, categorías, etc).
Un caso más complejo podría ser una aplicación web está compuesta por un servidor para desplegar nuestro código de backend, el servicio que ejecuta nuestra aplicación, un caché para almacenar datos temporales, una base de datos para persistir información, un proxy que actúa como puerta de entrada a la aplicación, y un servidor FTP para la descarga de archivos.
Desde el caso más sencillo al más complejo, la administración, organización, sincronización y comunicación de los contenedores puede estar completamente centralizada a través del archivo docker-compose.yml, por lo que resulta clave que entiendas el funcionamiento de Docker Compose a la hora de trabajar con el ecosistema Docker.
Como nombramos anteriormente, es una herramienta ideal para el desarrollo y testing de aplicaciones de manera local, así como también para configurar distintos flujos de integración continua y escenarios de prueba. Cuando quieras llevar tu aplicación a producción se utilizan otras herramientas conocidas como orquestadores, que sirven para manejar el escalado y mantenimiento de múltiples contenedores. Algunas de estas herramientas pueden ser Kubernetes o Docker Swarm. |
Con todo el contexto anterior estas en condiciones de entender cómo funciona Docker Compose a través de la creación paso a paso de una aplicación sencilla que ejecuta un contenedor de Wordpress junto con una base de datos MySQL.
Es necesario que tengas instalado Docker y Docker Compose en tu máquina. |
1. Crear estructura de directorios y archivos
Comencemos creando un nuevo directorio llamado wordpress_app y dentro un archivo llamado docker-compose.yml (la extensión puede ser .yml o .yaml). La aplicación también va a necesitar un directorio para guardar datos, así que también crea un directorio llamado database dentro de wordpress_app.
2. Definir el contenido de docker-compose.yml
Cuando tengas la estructura creada, agrega este contenido al archivo docker-compose.yml que define cómo está armada la aplicación y los argumentos de ejecución necesarios para cada servicio.
version: '3' services: mysql-db: image: mysql:5.7 hostname: mysql-db container_name: mysql-db restart: always environment: MYSQL_ROOT_PASSWORD: userpass MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress volumes: - ./database:/var/lib/mysql networks: - net-wordpress-app wordpress: image: wordpress:latest hostname: wordpress container_name: wordpress restart: always environment: WORDPRESS_DB_HOST: mysql-db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress WORDPRESS_DB_NAME: wordpress networks: - net-wordpress-app depends_on: - mysql-db ports: - "8080:80" networks: net-wordpress-app: driver: bridge |
Acá podés ver la explicación de los argumentos de ejecución dentro del archivo:
3. Construir e iniciar la aplicación
Una vez que el contenido del archivo docker-compose.yml está listo, el siguiente paso es construir la aplicación. Desde la raíz del proyecto ejecuta el siguiente comando para iniciar:
docker-compose up |
La ejecución del comando va a crear una red llamada net-wordpress-app, va a descargar las imágenes utilizadas (si no están descargadas) y va a iniciar los servicios en el orden que fueron descritos en el archivo docker-compose.yml. En la terminal, deberías ver una salida similar a la siguiente.
$ docker-compose up Creating network "net-wordpress-app" with the default driver Pulling db (mysql:5.7)... 5.7: Pulling from library/mysql ... Status: Downloaded newer image for mysql:5.7 Pulling wordpress (wordpress:latest)... ... Status: Downloaded newer image for wordpress:latest Creating mysql-db Creating wordpress ... |
Una vez que la aplicación haya iniciado podrías acceder al servicio de Wordpress ingresando la URL http://localhost:8080 en el navegador, donde deberías ver una imagen como la siguiente.
Si querés detener la aplicación presioná CTRL+C, o bien desde otra terminal corré el comando docker-compose down que va a detenerla y eliminar todo su contexto asociado.
Como podés notar, pasar de la ejecución de contenedores a través del comando docker run o utilizando scripts a tenerlo centralizado en un único archivo y ejecutarlos bajo un único comando, realmente simplifica la tarea. Veamos ahora algunos detalles más.
La función principal es crear aplicaciones basadas en múltiples contenedores, sus enlaces, redes y orden de ejecución; aunque en combinación con el engine de Docker la herramienta es capaz de mucho más. Algunas funciones destacadas son:
Veamos de manera general otras funcionalidades destacadas de la herramienta.
Múltiples entornos aislados en un solo host
Compose utiliza un nombre de proyecto para aislar los entornos entre sí. Podés hacer uso de este nombre de proyecto en varios contextos diferentes, como en un host de desarrollo, en un servidor de integración continua o bien en un host compartido o dev host. En cada uno de estos entornos se pueden tener diferentes configuraciones sin que interfieran entre sí.
El nombre del proyecto por defecto es el nombre del directorio del proyecto, aunque podés establecer un nombre personalizado utilizando la opción -p PROJECT_NAME al momento de ejecución o bien la variable de entorno COMPOSE_PROJECT_NAME.
Conservar los datos cuando se crean contenedores
Compose conserva todos los volúmenes utilizados por los servicios de tu aplicación. Cuando ejecutas docker-compose up, si el engine encuentra contenedores de ejecuciones anteriores, copia los volúmenes del contenedor antiguo al contenedor nuevo. Este proceso garantiza que los datos que haya creado en volúmenes no se pierdan.
Regenerar contenedores que hayan cambiado
Compose almacena en caché la configuración utilizada para crear un contenedor. Cuando reinicias un servicio que no ha cambiado, Compose reutiliza los contenedores existentes, lo que significa que podés realizar cambios en tu entorno muy rápidamente.
Variables y movimiento de composiciones entre entornos
Compose admite variables en el archivo docker-compose.yml. Podés usar estas variables para personalizar la composición de diferentes entornos o usuarios. También es posible extender configuraciones desde otro archivo docker-compose, mejorando así la reutilización.
Compose se puede utilizar de muchas formas diferentes. A continuación podés ver algunos casos de uso comunes.
Entornos de desarrollo
Cuando se desarrolla software, la capacidad de ejecutar una aplicación en un entorno aislado e interactuar con ella es fundamental. Podés crear rápidamente el entorno de trabajo e iniciar uno o más contenedores con un solo comando. Utilizando Compose podés pasar de las tradicionales y tediosas guías de configuración a un solo archivo legible y autoexplicativo.
Entornos de prueba automatizados
Una parte importante en el desarrollo es el proceso de integración continua para realizar pruebas automáticas cada vez que realizas una modificación en tu código. Las pruebas automatizadas requieren un entorno específico en el que ejecutar las pruebas y Compose proporciona una forma conveniente de crear y destruir entornos de prueba aislados para tu suite de pruebas.
Implementaciones en producción
Compose comenzó centrándose tradicionalmente en los flujos de trabajo correspondientes al desarrollo e implementación de pruebas, pero con cada actualización avanza también en funciones más orientadas a producción. A través de la modificación del docker-compose.yml, junto con el despliegue de las aplicaciones en hosts remotos es posible utilizar Docker Compose para el despliegue de aplicaciones productivas.
Ahora que ya conoces bastante sobre cómo funciona Docker Compose, veamos algunos de los comandos más frecuentes que necesitarás usar en el día a día.
Estos son sólo alguno de los comandos disponibles y realmente podés hacer muchas acciones a través de los comandos. Si querés conocer más funcionalidades, en la documentación oficial vas a encontrar todos los detalles.
En este documento vimos varios de los conceptos más importantes que necesitas saber para utilizar Docker Compose. Para hacer un resumen vimos los siguientes temas.
Este material es distribuido bajo licencia Creative Commons BY-SA 4.0. Podés encontrar detalles sobre el uso del material en este link.