Este es uno de los capítulos del tutorial Tutorial de Docker. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.
Con lo que has visto en los diferentes capítulos de este tutorial de Docker, ya estarás levantando contenedores a diestro y siniestro. Eso si, hasta el momento, solo puedes trabajar con contenedores aislados, contenedores que no se relacionan unos con otros. Ahora, ¿como levantar un WordPress? al fin y al cabo un WordPress está compuesto de diferentes piezas. Por un lado el servidor web, por otro lado la base de datos y por último, el lenguaje de programación. Podrías plantearte levantar un contenedor que contuviera todo esto… Sin embargo, ¿porque no levantar un contenedor para cada uno de estos servicios? En este nuevo capítulo del tutorial sobre docker, verás como puedes levantar varios contenedores y que estos se relacionen entre si. Es decir, vas a orquestar contenedores con docker-compose
.
Orquestar contenedores con Docker Compose
¿Porque varios por separador?
Es posible que te plantees meter todos los servicios que necesitas en un único contenedor. Así, como te indicaba anteriormente, podrías tener tu WordPres, con tu servidor web, tu base de datos, etc, en un solo contenedor. Pero, ¿que pasa si quieres cambiar la versión del servidor web?¿o incluso si quisieras cambiar de servidor de base de datos?
Evidentemente en estos casos, tendrías que detener el contenedor y te quedarías sin servicio. El tiempo que tardes en levantar un nuevo contenedor.
Sin embargo, si cada uno de estos servicios lo tienes en un contenedor separado, la operación es tan sencilla, detener el contenedor docker que te interese y levantar otro.
Chiquito de nuevo
En el capítulo 6, visto como crear una imagen docker paso a paso. Se trataba de una sencilla API realizada en Python, utilizando Flask y SQLite. Pero, ¿y si quisieras utilizar una base de datos externa?. Y ¿si quisieras utilizar MariaDB como tu servidor de bases de datos?
La solución sería por un lado levantar un contenedor con MariaDB, y por el otro lado levantar el contenedor con tu aplicación implementada en Python. De esta manera, por un lado, podrías ser agnóstico, hasta cierto punto, en lo que al servidor de bases de datos se refiere. Por otro lado, puedes actualizar el servidor cuando lo necesites sin excesiva complicación ni problemas. Y por último podrías servir a varias aplicaciones de forma simultánea.
Así, voy a partir del mismo ejemplo que en el caso anterior, sin embargo, las frases de Chiquito de la Calzada irán a parar a un contenedor docker con MariaDB.
Contenedor a contenedor
Primero te voy a mostrar como hacer para levantar los diferentes contenedores y conseguir que se relacionen unos con otros. En seguida te darás cuenta de que esta es una operación tediosa, y tiene muchas posibilidades de error.
El servidor de base de datos
Como te indicaba anteriormente, en lugar de utilizar una base de datos como SQLite, el objetivo es utilizar un servidor de bases de datos en otro contenedor. En este caso, he elegido Mariadb, pero, evidentemente podía elegir cualquier otro.
Tienes que levantar un docker de Mariadb con persistencia de datos, que es lo interesante. De no utilizar persistencia de datos, tendrías que introducir los datos en cada ocasión que quisieras cambiar de servidor de base de datos, o cambiar de versión o lo que fuera. Para levantar el contenedor ejecuta la siguiente instrucción,
docker run -d \
-e MYSQL_ROOT_PASSWORD=password \
-v "$(pwd)"/data:/var/lib/mysql \
-p 3306:3306 \
--name mariadbserver \
mariadb
Para llenar la base de datos con las frases de chiquito, he implementado un sencillo script que por supuesto puedes encontrar en el repositorio de GitHub. Pero, para que te hagas una idea, finalmente todo se resume ejecutar la siguiente instrucción en un terminal,
mysql -h $HOST -P $PORT -u $USER --password=$PASSWORD chiquito < frases.sql
Chiquito as a Service (CaaS)
Por otro lado, he modificado la aplicación de chiquito para que pueda utilizar MariaDB, en lugar de utilizar SQLite. De nuevo tienes que construir esta aplicación, a la que le he puesto una etiqueta composer
, por lo que podrás ver mas adelante. La construcción es tan sencilla como lo que has visto en el capítulo
docker build -t atareao/chiquito:composer .
Una vez construida la imagen, tan solo tienes que ponerla en producción. Para ello, ejecuta la siguiente instrucción,
docker run -d \
-p 5000:5000 \
--name chiquitocomposer \
atareao/chiquito:composer
Sin embargo, te llevarás una desagradable sorpresa, y es que al ponerlo en funcionamiento, te arroja un error. Y te arroja un error, porque el contenedor que lleva tu aplicación de chiquito
es incapaz de ver a la base de datos MariaDB
que se encuentra en el otro contenedor. Para corregir este problema, tienes que añadir una opción adicional,
docker run -d \
-p 5000:5000 \
--name chiquitocomposer \
--link=mariadbserver \
atareao/chiquito:composer
Esta opción, --link
, añade una nueva entrada en el /etc/hosts
que apunta al IP del contenedor identficado por --link=CONTAINER_NAME
.
Una vez en marcha, verás que todo se comporta como se espera. Vas a poder obtener frases aleatorias de Chiquito de la Calzada
Un paso mas…
Sin embargo, como tu mismo has podido comprobar, esto no es ni mucho menos la forma mas sencilla e intuitiva de trabajar con varios contenedores. Lo suyo sería disponer de una herramienta que permitiera orquestar la puesta en marcha y funcionamiento de varrios contenedores. Y efectivamente tienes a tu disposición esta herramienta y se llama docker compose
Instalar docker-compose para orquestar contenedores
Instalar docker-compose
es tan sencillo como ejecutar las siguientes instrucciones en un terminal. Aunque debes tener en cuenta en la versión actual de docker-compose
, porque esta es la que estaba vigente en el momento de escribir el artículo, y con lo rápido que avanza todo esto, vete a saber.
$ sudo apt install jq
$ version=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | jq -r '.tag_name')
$ sudo curl -L "https://github.com/docker/compose/releases/download/${version}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
Una vez descargado tienes que preparar el archivo .yml
. En este archivo definirás cada uno de los contenedores que constituyen el puzzle. En este caso, como has visto anteriormente se trata de un contenedor para el servicio, y un segundo contenedor para la base de datos. Así, el archivo, docker-compose.yml
en cuestión, tendrá la siguiente estructura,
version: '3'
services:
chiquito:
image: atareao/chiquito:composer
ports:
- "5000:5000"
mariadbserver:
image: mariadb
ports:
- "3306:3306"
volumes:
- ./data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: password
Como ves, cada uno de los servicios se corresponde con una de las imágenes que formará tu red de contenedores. El primero, se trata de la imagen de tu aplicación, en este caso Chiquito, particularizada para el caso que utiliza MariaDB como base de datos, y el segundo, es precisamente la base de datos en cuestión. Aquí, al igual que en el caso de la imagen anterior, tienes que definir los distintos parámetros que normalmente defines directamente en la línea de comandos. Así tienes que indicar los puertos que compartes, los volúmenes, y en su caso las variables de entorno.
También es posible construir la imagen de chiquito
directamente en lugar de utilizar la imagen que construiste previamente. Para hacer esto, tan solo tienes que sustituir la línea,
image: atareao/chiquito:composer
Por la línea,
build: .
El problema de esta segunda opción es que cada vez que levantes tu red de contenedores tendrás que construir la imagen previamente, y esto se realizará en cada ocasión. Si ya construiste la imagen en su momento, el proceso de levantar los contenedores será mucho mas rápido
Utilizando docker-compose para orquestar contenedores
Una vez definido el archivo docker-compose.yml
te queda ponerlo en marcha, y cuando hayas terminado con él detenerlo. Así, las instrucciones son las siguientes,
docker-compose up
levanta los contenedoresdocker-composer up -d
hace lo mismo que la instrucción pero en modo desvinculado, detached mode.docker-compose ps
te permite ver los contenedores que están en funcionamiento.docker compose stop
es la herramienta encargada de detener los diferentes contenedores una vez hayas terminado de trabajar con ellos.
Así por ejemplo, en el caso que estamos viendo, lo que te encontrarías al ejecutar las distintas instrucciones sería algo como lo que te muestros a continuación,
- Para levantar los contenedores, utilizaremos docker-compose para orquestar contenedores
$ docker-compose up -d
Creating chiquito-compose_chiquito_1 ... done
Creating chiquito-compose_mariadbserver_1 ... done
- Para ver el estado de los contenedores
$ docker-composer ps
Name Command State Ports
-----------------------------------------------------------------------------------------------
chiquito-compose_chiquito_1 python3 app.py Up 0.0.0.0:5000->5000/tcp
chiquito-compose_mariadbserver_1 docker-entrypoint.sh mysqld Up 0.0.0.0:3306->3306/tcp
Y por último, para detener los contenedores, de nuevo recurrimos a nuestro docker-compose para orquestar contenedores, la instrucción es tan sencilla como ejecutar,
$ docker-composer down
Conclusión
Recordarte que tanto la imagen como el script, y el resto de archivos que he utilizado tanto para crear la base de datos, como para la imagen, los tienes disponibles en GitHub y Docker Hub. En este caso, evidentemente, te tienes que descargar la imagen etiquetada como composer
.
Una vez, te he indicado donde puedes encontrar los recursos para montar todo esto, viene el momento de la reflexión. Aunque, después de lo que te he mostrado, creo que no voy a necesitar mucho esfuerzo para convencerte de la ventaja de esto de orquestar contenedores como docker-compose
para realizar el trabajo. Desde luego desde punto de vista de la sencillez, la simplicidad y la elegancia, este procedimiento está muy por delante de los primeros pasos que has dado. Así, sin lugar a dudas, es bien sencillo levantar tus contenedores y detenerlos en su caso. Y todo ello sin casi ninguna preocupación.
Más información,