Saltar al contenido principal

Docker 2 · Aplicaciones multi-contenedor

Al final de Docker 1 pusiste en marcha TasteMatch junto a Redis. Preparaste una imagen propia, creaste almacenamiento y una red, configuraste variables, publicaste un puerto y conectaste dos contenedores. También comprobaste el resultado, investigaste incidencias y limpiaste los recursos de la práctica.

Sabes gestionar cada pieza. Pero piensa ahora en el día siguiente: ¿podrías reproducir exactamente la misma aplicación en otro equipo sin olvidar ningún comando, nombre, montaje, puerto o variable?

Con dos contenedores ya tenemos que coordinar varias decisiones:

aplicación
├── imagen propia
├── puerto publicado
├── variables de entorno
└── red compartida

Redis
├── imagen existente
├── almacenamiento
└── red compartida

Hacerlo manualmente sigue siendo válido. El problema es mantener y compartir una secuencia cada vez más larga de comandos. Una opción olvidada puede producir una aplicación distinta; una instrucción desactualizada puede impedir que otra persona la ejecute.

De gestionar piezas a describir la aplicación​

Hasta ahora el recorrido se parecía a este:

docker run ...
docker network ...
docker volume ...
-e ...
-p ...

En este curso reuniremos esas decisiones en una descripción de la aplicación:

describimos la aplicación
↓
compose.yaml
↓
docker compose
↓
servicios + redes + volúmenes + configuración
↓
aplicación multi-contenedor

El archivo compose.yaml expresará qué piezas necesita el proyecto y cómo se relacionan. Docker Compose utilizará esa descripción para gestionar el conjunto.

No necesitas memorizar todavía su sintaxis. Primero entenderemos por qué necesitamos describir la aplicación; después construiremos el archivo de forma progresiva.

Convención del curso

Utilizaremos el comando actual docker compose y el nombre compose.yaml. En proyectos antiguos puedes encontrar docker-compose o docker-compose.yml, pero no serán la convención principal de este recorrido.

Compose organiza conceptos que ya conoces​

Docker Compose no sustituye Docker ni oculta lo aprendido:

  • un servicio describe cómo debe ejecutarse una parte de la aplicación, y Compose crea y gestiona los contenedores necesarios para ese servicio;
  • una red sigue siendo una red Docker;
  • un volumen sigue almacenando datos fuera del ciclo de vida del contenedor;
  • un puerto publicado sigue conectando un puerto del host con uno del contenedor;
  • una variable sigue configurando el proceso que ejecutamos;
  • una imagen propia sigue necesitando un proceso de construcción.
Docker 1
conocemos y gestionamos las piezas
↓
Docker 2
describimos y gestionamos sus relaciones

Podremos seguir inspeccionando contenedores, redes y volúmenes reales. Si una ruta, un puerto o una variable están mal definidos, Compose no los arreglará por arte de magia. Comprender las piezas seguirá siendo la base para diagnosticar el conjunto.

Nuestra aplicación de referencia​

TasteMatch evolucionará hacia una aplicación con varios servicios. En Docker 2 adaptaremos algunas piezas del laboratorio anterior para trabajar también con una base de datos persistente. Su arquitectura principal será sencilla para que el código no eclipse Docker:

             usuario
│
▼
┌───────────────┐
│ TasteMatch │
│ web/backend │
└───────┬───────┘
│
red
│
┌───────▼───────┐
│ base de datos │
└───────┬───────┘
│
volumen
│
▼
datos

Cuando aporte valor podremos incorporar un tercer servicio, pero siempre mantendremos el foco en la aplicación completa: qué necesita, cómo se reproduce y cómo comprobamos que funciona.

Lo que aprenderás​

A lo largo del curso pasarás de los comandos independientes a un flujo reproducible. Aprenderás a:

  • reconocer los servicios que forman una aplicación;
  • describirlos en compose.yaml mediante imágenes propias o existentes;
  • construir y reconstruir los servicios que lo necesiten;
  • proporcionar puertos, variables y archivos de configuración;
  • comunicar servicios mediante redes y nombres;
  • conservar datos con volúmenes;
  • integrar una base de datos en la aplicación;
  • distinguir que un contenedor haya arrancado de que su servicio esté preparado;
  • expresar dependencias y comprobar disponibilidad mediante healthchecks;
  • consultar estado y logs y ejecutar comandos de diagnóstico;
  • mejorar imágenes para acercarlas de forma razonada a un contexto real;
  • etiquetar, publicar y recuperar una imagen mediante un registry;
  • integrar todo el recorrido en un proyecto final multi-contenedor.

No existe una opción que convierta por sí sola una aplicación en «lista para producción». Disponibilidad, backups, secretos, seguridad, observabilidad e infraestructura dependen del contexto y requieren decisiones adicionales. Aquí construiremos fundamentos prácticos para preparar, distribuir y diagnosticar aplicaciones con criterio.

Antes de empezar​

Este curso continúa Docker 0 y Docker 1. Partimos de que ya puedes:

  • trabajar con imágenes y contenedores;
  • crear una imagen mediante un Dockerfile;
  • utilizar puertos, redes, volúmenes y bind mounts;
  • configurar contenedores con variables de entorno;
  • comunicar contenedores por nombre en una red;
  • consultar estado, logs e información de inspección;
  • investigar un fallo cambiando una sola causa cada vez.

No volveremos a estudiar esos conceptos desde cero. Los combinaremos para responder una pregunta nueva:

¿Cómo describimos una aplicación completa para poder crearla, mantenerla y compartirla como un conjunto?

En la primera unidad retomaremos la ejecución manual que ya conoces y observaremos exactamente dónde empieza a resultar difícil de reproducir. Desde ese problema construiremos, paso a paso, el modelo de Docker Compose.