Docker Compose
Docker Compose es una herramienta usada para definir y administrar aplicaciones de multi-contenedor con Docker. Es bastante útil cuando se tiene varios servicios como apache, mysql, redis ya que se puede crear diferentes contenedores para cada servicio.
Para usa Docker Compose, debes instalar el paquete necesario en tu distribución de Linux preferida con tu sistema de gestión de paquetes. Enseguida, podrás crear y definir tus contenedores utilizando el archivo docker-compose.yml
.
Vamos a iniciar con un ejemplo muy sencillo.
version: '3.9'
services:
web:
image: nginx:latest
En este primer ejemplo hemos creado un docker compose file muy sencillo el cual define un servicio. Veamos que significa cada uno de los elementos.
- version
- Define la versión del formato de archivo de Docker Compose.
- services
- Inicia la definición de los servicios que formarán parte de nuestra aplicación. Cada servicio creará un contenedor.
- web
- Define un servicio llamado "web". Este nombre es totalmente personalizado. Hubiera podido ser "apache" o "server".
- image
- Especifica que queremos usar la imagen más reciente de nginx.
Veamos el siguiente ejemplo basado en el anterior en donde hemos agregado un servicio adicional para base de datos.
version: '3.9'
services:
web:
image: nginx:latest
database:
image: mysql:5.7
Por defecto, todos los servicios creados en el archivo docker compose comparten la misma red, es decir, que se pueden comunicar uno con otro sin necesidad de una configuración adicional. El nombre de host porspuesto, será el nombre del servicio.
Contexto
El "contexto" en Docker y Docker Compose se refiere generalmente al contexto de construcción cuando estamos tratando con la creación de imágenes Docker a partir de un Dockerfile. Supongamos que queremos personalizar un poco la imagen inicial de ngnix para agregar algunas cosas, entonces debemos crear un archivo Dockerfile
. En este caso, lo hemos creado en el mismo directorio de nuestro docker-compose.yml
.
docker-compose.yml
version: '3.9'
services:
web:
build: .
database:
image: mysql:5.7
Dockerfile
FROM nginx:latest
De esta forma nuestro servicio llamado "web" estaría utilizando el Dockerfile en el directorio actual para construir el servicio. El anterior archivo muestra la forma abreviada de especificar el contexto de construcción del servicio. Podríamos utilizar la forma extensa de la siguiente forma y sería equivalente:
version: '3.9'
services:
web:
build:
context: .
dockerfile: Dockerfile
database:
image: mysql:5.7
La forma extensa es útil si necesitas crear una configuración mucho más compleja, generalmente con archivos de configuración adicionales para tu servicio. No es necesario que especifiques el key dockerfile
a menos que quieras que el nombre de tu archivo de docker sea diferente de "Dockerfile".
Supongamos que queremos agregar una configuración al servidor de nginx, podríamos crear una carpeta llamada "web" para guardar todo lo relacionado con el servicio llamado también web. La estructura de directorios sería la siguiente. Nota que el archivo Dockerfile
ahora está en web/Dockerfile
.
mi_proyecto/
|-- docker-compose.yml
|-- web/
|-- Dockerfile
|-- nginx.conf
|-- my_custom_config.conf
Nuestra configuración ahora sería:
version: '3.9'
services:
web:
build:
context: web
database:
image: mysql:5.7
Finalmente, el Dockerfile
podría quedar como sigue copiando la configuración respectiva al directorio de nginx.
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
COPY my_custom_config.conf /etc/nginx/conf.d/
No hemos entrado en detalles respecto a cómo serían los archivos específicos de configuración de nginx ya que no es el objetivo de este post.
Puertos
Como has de adivinar cuando se monta un servidor web se necesitan comunicación con puertos específicos como el puerto 80. En nuestra configuración de docker compose podemos configurar mediante cual puerto accederemos a nuestro servidor web.
version: '3.9'
services:
web:
build:
context: web
ports:
- "8080:80"
database:
image: mysql:5.7
Agregando el elemento ports como "8080:80" podremos acceder desde nuestra máquina host al contenedor mediante el puerto 8080 ya que este puerto será redirigido al puerto 80 del contenedor. En síntesis, cuando accedamos al browser muy seguramente accederemos a 127.0.0.1:8080
.
Volúmenes
Los volúmenes en Docker son mecanismos que permiten persistir y compartir datos entre el host y los contenedores. Esto es útil por ejemplo cuando queremos utilizar el código fuente de nuestro proyecto en el contenedor sin necesidad de copiarlos y crear dos versiones diferentes de cada archivo. Vamos a modificar levemente nuestro ejemplo para que toda la configuración de docker quede bajo el folder de "docker" y todo el código fuente quede en "src".
mi_proyecto/
|-- docker-compose.yml
|-- src/
| |-- index.html
| |-- ...
|-- docker/
|-- web/
| |-- Dockerfile
| |-- nginx.conf
| |-- my_custom_config.conf
para crear un volumen que comparta el código de nuestro proyecto en "src" con el contenedor podemos hacerlo así:
version: '3.9'
services:
web:
build:
context: ./docker/web
dockerfile: Dockerfile
ports:
- "80:80"
volumes:
- ./src:/usr/share/nginx/html
Estando dentro del contenedor veremos los archivos en /usr/share/nginx/html
.
Argumentos
Ya vimos que son los argumentos en nuestro post Variables de Entorno y Argumentos en Docker. Para especificar argumentos en docker compose puedes utilizar el elemento args
bajo el elemento build
.
version: '3.9'
services:
web:
build:
context: ./docker/web
args:
- PHP_VERSION=8.2
Variables de Entorno
Para especificar variables de entorno en docker compose puedes utilizar el elemento enviroment
bajo el elemento build
. Estas variables son llamadas variables en línea.
version: '3.9'
services:
web:
build: .
environment:
- DEBUG_MODE=true
También es posible especificar un archivo de variables de entorno así:
version: '3.9'
services:
web:
build: .
env_file:
- .env.list
Finalmente es importante mencionar que docker compose tomará por defecto las variables del archivo .env
(si existe) o las variables del HOST si estas son declaradas en el docker file. Para saber a más detalle cómo funcionan las variables de entorno puedes ver nuestro artículo Variables de Entorno y Argumentos en Docker.