Desplegando Aplicaciones con Docker Compose

Advertencia
Este artículo se actualizó por última vez el 2021-09-30, el contenido puede estar desactualizado.

Antes de comenzar, quería contarles que hay una promoción en DigitalOcean donde te dan un crédito de USD 100.00 durante 60 días para que puedas probar los servicios que este Proveedor Cloud ofrece. Lo único que tienes que hacer es suscribirte a DigitalOcean con el siguiente botón:

DigitalOcean Referral Badge

O a través del siguiente enlace: https://bit.ly/digitalocean-itsm


En artículos anteriores hemos usado Docker de manera imperativa, es decir, a través de la linea de comandos ejecutando las ordenes y sus argumentos (docker images, docker ps, docker run, docker exec, etc); cuando mucho hemos trabajado con uno o dos contenedores.


Imaginemos la siguiente situación: queremos desplegar un Wordpress por ejemplo, el cual consta de la aplicación como tal y el Servidor de Base de Datos al que debemos pasarle unos parámetros como el usuario root, la contraseña el puerto, etc. Entonces nos quedaría algo así:

1
2
3
docker run --name wordpress -e WORDPRESS_DB_HOST=10.1.2.3:3306 \
           -e WORDPRESS_DB_USER=usuario_db \
           -e WORDPRESS_DB_PASSWORD=password_db -d wordpress

Y para crear la base de datos:

1
2
3
docker run -p 127.0.0.1:3306:3306  --name mariadb_server \
           -v /directorio/de/datos/:/var/lib/mysql
           -e MARIADB_ROOT_PASSWORD=password_db -d mariadb

Se hace muy engorroso tener que recordar todos los parámetros necesarios para configurar dos servicios diferentes (Wordpress y MariaDB) al mismo tiempo. Así mismo, tendríamos que saber que dirección IP tendría el contenedor de MariaDB ya que como recordarás en el articulo Conceptos y Comandos Básicos en Docker los contenedores son efimeros, y una vez que mueren, se reinician o fallan, esa dirección IP se pierde y al levantar nuevamente el contenedor, se asigna otra diferente.

A través de un archivo en formato .yaml, podemos realizar toda nuestra configuración Declarativamente de manera que vamos a obtener cierto orden en nuestros servicios. Regularmente el archivo lo ubicamos en un directorio aparte que puede contener los datos que vamos a guardar y los archivos de confguracion que le podemos cargar a nuestros servicios (un nginx.conf, my.cnf, etc)

El formato YAML es el mismo usado para Ansible y Kubernetes, consta de una serie de claves y valores que deben ser identados con dos espacios o con un TAB. Una de las desventajas de utilizar YAML es que ese identado suele ser bastante problematico con configuraciones grandes, sin embargo, no hay nada que un buen plugin de de VSCode o VSCodium no puedan manejar.

Es relativamente fácil instalar Docker Compose en Linux, todo lo que debemos hacer es ejecutar el siguiente comando en una terminal:

1
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

En distribuciones como Manjaro o ArchLinux, ya lo tendremos disponible en los repositorios, es solo ejecutar:

1
sudo pacman -S docker-compose 

Para instalar Docker Compose en ambos sistemas operativos, debemos instalar Docker Desktop, el cual es solo descargar el instalador Windows | MacOS con Procesadores Intel | MacOS con Procesadores ARM y seguir las instrucciones del instalador.

Nos aseguramos que Docker Compose esté instalado ejecutando:

1
docker-compose --version
1
2
3
4
docker-compose version 1.29.2, build unknown
docker-py version: 5.0.2
CPython version: 3.9.7
OpenSSL version: OpenSSL 1.1.1l  24 Aug 2021

Consta de tres llaves básicas:

version: "3": aquí declaramos la versión de Docker Compose que queremos utilizar.

service: aquí declaramos todos los contenedores que forman parte de nuestro servicio/aplicación. Le podemos colocar los nombres de los mismos.

networks (opcional): aquí declaramos el driver de red que usarán nuestros servicios. Recordemos que en Docker tenemos los drivers: bridge (es el driver por defecto. Los contenedores que la usen van a obtener una IP interna y se van a poder comunicar entre ellas, también en el host), host (toma la dirección IP directamente de nuestro Router), Macvlan (el contenedor dentro de esta red, se le va a asignar una dirección MAC única y además va a estar en la red real, pudiendo acceder a los recursos de la misma (DHCP, DNS, etc)), null (El contenedor que se encuentre en esta red, no tendrá IP. Es útil en aquellos casos donde se ejecuten tareas o scripts en el cual el resultado deba ser almacenado en un volumen)

Retomando el ejemplo anterior (Wordpress + MariaDB), el archivo docker-compose.yaml quedaría de la siguiente manera:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: '3.1'
services:
  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: root
      WORDPRESS_DB_PASSWORD: password
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - $PWD/wordpress/:/var/www/html
    depends_on:
      - db
  db:
    image: mariadb
    restart: always
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - $PWD/db/:/var/lib/mysql

Desglosemos uno a uno los parámetros:

  • image: wordpress: la imagen que vamos a usar.

  • restart: always: con este parámetro nos aseguramos que se reinicie el contenedor siempre así haya un error con el mismo. También podemos hacer que el contenedor se inicie automáticamente al reiniciar el sistema.

  • ports: puerto del host:puerto del contenedor. El guión significa que es un parámetro de tipo lista, por lo que podemos redireccionar más puertos si fuese necesario.

  • environment:: aquí colocamos las variables de entorno que necesiamos para que ambos servicios funcionen. Si observas bien, hay varios parámetros como WORDPRESS_DB_HOST, WORDPRESS_DB_USER, WORDPRESS_DB_PASSWORD y WORDPRESS_DB_NAME que la imagen de Wordpress necesita para poder conectarse a la base de datos. Hay un detalle a considerar con el parámetro WORDPRESS_DB_HOST: db es que db es el nombre que le colocamos al servicio que se ocupa de levantar la base de datos MariaDB con lo va a hacer match con esa etiqueta, permitiendonos conectarnos a la db sin necesidad de colocar la dirección IP de la base de datos.

  • depends_on: con este parámetro le decimos especificamente al servicio Wordpress que espere a que el servicio db esté iniciado antes de levantar el Wordpress. Es útil cuando tenemos un servicio que tarda un poco en iniciar (normalmente aplicaciones Java o de base de datos)

  • volumes: con $PWD estamos mapeando nuestro directorio actual (donde se encuentra el docker-compose.yaml) al directorio del contenedor donde están los archivos de datos. En el caso de MariaDB redirecciona el directorio db del host a /var/lib/mysql del contenedor. Lo mismo con Wordpress

Para iniciar nuestra aplicación de ejemplo con Wordpress y MariaDB, debemos estar en el directorio donde se encuentra nuestro docker-compose.yaml y ejecutamos:

1
docker-compose up -d

Para verificar que Wordpress haya iniciado correctamente, en cualquier navegador colocamos la direccion http://localhost:8080 y voilà.

/images/docker-compose/service.png
Wordpress

Si omitimos el -d veremos que nuestro servicio inicia en primer plano y veremos lo que está ocurriendo con las aplicaciones.

Para detener el servicio:

1
docker-compose stop

Para iniciar solo un servicio en particular:

1
docker-compose up -d db

Para detener un servicio en particular:

1
docker compose stop wordpress

Para ver los contenedores en ejecución:

1
docker-compose ps

Para entrar a un servicio y ejecutar comandos:

1
docker-compose exec db bash

Para ver las imagenes utilizadas:

1
docker-compose images

Si queremos actualizar las imagenes de los contenedores sin interrumpir el servicio:

1
docker-compose pull

Para eliminar todo:

1
docker-compose rm

Nos vemos en la próxima! Happy Dockering 😄



Si te pareció útil este artículo y el proyecto en general, considera brindarme un café :)

Buy me a coffeeBuy me a coffee