# Aplicaciones multicontenedor





## Explicación

Iniciar una aplicación de un solo contenedor es sencillo. Por ejemplo, un script de Python que realiza una tarea específica de procesamiento de datos se ejecuta dentro de un contenedor con todas sus dependencias. De manera similar, una aplicación de Node.js que sirve un sitio web estático con un pequeño punto de enlace de API se puede contenedorizar eficazmente con todas sus bibliotecas y dependencias necesarias. Sin embargo, a medida que las aplicaciones crecen en tamaño, administrarlas como contenedores individuales se vuelve más difícil.

Imagina que el script de Python para procesamiento de datos necesita conectarse a una base de datos. De repente, ahora no solo estás administrando el script, sino también un servidor de base de datos dentro del mismo contenedor. Si el script requiere inicios de sesión de usuario, necesitarás un mecanismo de autenticación, lo que aumentará aún más el tamaño del contenedor.

Una de las mejores prácticas para los contenedores es que cada contenedor debe hacer una sola cosa y hacerla bien. Aunque existen excepciones a esta regla, evita la tendencia de hacer que un contenedor realice múltiples tareas.

Ahora te preguntarás: "¿Necesito ejecutar estos contenedores por separado? Si los ejecuto por separado, ¿cómo los conectaré todos entre sí?"

Aunque `docker run` es una herramienta conveniente para iniciar contenedores, se vuelve difícil administrar una pila de aplicaciones en crecimiento con ella. He aquí por qué:

- Imagina ejecutar varios comandos `docker run` (frontend, backend y base de datos) con diferentes configuraciones para entornos de desarrollo, pruebas y producción. Es propenso a errores y consume mucho tiempo.
- Las aplicaciones a menudo dependen unas de otras. Iniciar manualmente los contenedores en un orden específico y administrar las conexiones de red se vuelve difícil a medida que la pila se expande.
- Cada aplicación necesita su propio comando `docker run`, lo que dificulta escalar los servicios individuales. Escalar toda la aplicación significa desperdiciar potencialmente recursos en componentes que no necesitan un impulso.
- Persistir los datos para cada aplicación requiere montajes de volumen o configuraciones independientes dentro de cada comando `docker run`. Esto crea un enfoque de gestión de datos disperso.
- Configurar variables de entorno para cada aplicación a través de comandos `docker run` independientes es tedioso y propenso a errores.

Ahí es donde Docker Compose entra al rescate.

Docker Compose define toda tu aplicación multicontenedor en un solo archivo YAML llamado `compose.yml`. Este archivo especifica las configuraciones de todos tus contenedores, sus dependencias, variables de entorno e incluso volúmenes y redes. Con Docker Compose:

- No necesitas ejecutar múltiples comandos `docker run`. Todo lo que tienes que hacer es definir toda tu aplicación multicontenedor en un solo archivo YAML. Esto centraliza la configuración y simplifica la gestión.
- Puedes ejecutar contenedores en un orden específico y administrar las conexiones de red fácilmente.
- Puedes simplemente escalar los servicios individuales hacia arriba o hacia abajo dentro de la configuración multicontenedor. Esto permite una asignación eficiente basada en las necesidades en tiempo real.
- Puedes implementar volúmenes persistentes con facilidad.
- Es fácil configurar las variables de entorno una sola vez en tu archivo de Docker Compose.

Al aprovechar Docker Compose para ejecutar configuraciones multicontenedor, puedes compilar aplicaciones complejas con modularidad, escalabilidad y consistencia en su núcleo.

## Pruébalo

En esta guía práctica, verás primero cómo compilar y ejecutar una aplicación web de contador basada en Node.js, un proxy inverso Nginx y una base de datos Redis utilizando los comandos `docker run`. También verás cómo puedes simplificar todo el proceso de implementación utilizando Docker Compose.

### Configuración

1. Obtén la aplicación de muestra. Si tienes Git, puedes clonar el repositorio de la aplicación de muestra. De lo contrario, puedes descargar la aplicación de muestra. Elige una de las siguientes opciones.

   **Clone with git**



   Utiliza el siguiente comando en una terminal para clonar el repositorio de la aplicación de muestra.

   ```console
   $ git clone https://github.com/dockersamples/nginx-node-redis
   ```

   Navega al directorio `nginx-node-redis`:

   ```console
   $ cd nginx-node-redis
   ```

   Dentro de este directorio, encontrarás dos subdirectorios: `nginx` y `web`.

   **Download**



   Descarga el código fuente y extráelo.

   [Download the source](https://github.com/dockersamples/nginx-node-redis/archive/refs/heads/main.zip)


   Navega al directorio `nginx-node-redis-main`:

   ```console
   $ cd nginx-node-redis-main
   ```

   Dentro de este directorio, encontrarás dos subdirectorios: `nginx` y `web`.

   

2. [Descarga e instala](/get-started/get-docker/) Docker Desktop.

### Compilar las imágenes

1. Navega al directorio `nginx` para compilar la imagen ejecutando el siguiente comando:

   ```console
   $ docker build -t nginx .
   ```

2. Navega al directorio `web` y ejecuta el siguiente comando para compilar la primera imagen web:

   ```console
   $ docker build -t web .
   ```

### Ejecutar los contenedores

1. Antes de poder ejecutar una aplicación multicontenedor, necesitas crear una red para que todos se comuniquen a través de ella. Puedes hacerlo utilizando el comando `docker network create`:

   ```console
   $ docker network create sample-app
   ```

2. Inicia el contenedor de Redis ejecutando el siguiente comando, que lo conectará a la red creada anteriormente y creará un alias de red (útil para búsquedas DNS):

   ```console
   $ docker run -d  --name redis --network sample-app --network-alias redis redis
   ```

3. Inicia el primer contenedor web ejecutando el siguiente comando:

   ```console
   $ docker run -d --name web1 -h web1 --network sample-app --network-alias web1 web
   ```

4. Inicia el segundo contenedor web ejecutando el siguiente comando:

   ```console
   $ docker run -d --name web2 -h web2 --network sample-app --network-alias web2 web
   ```

5. Inicia el contenedor de Nginx ejecutando el siguiente comando:

   ```console
   $ docker run -d --name nginx --network sample-app  -p 80:80 nginx
   ```

   > [!NOTE]
   >
   > Nginx se utiliza normalmente como un proxy inverso para aplicaciones web, enrutando el tráfico a los servidores backend. En este caso, enruta a los contenedores backend de Node.js (web1 o web2).

6. Verifica que los contenedores estén funcionando ejecutando el siguiente comando:

   ```console
   $ docker ps
   ```

   Verás una salida como la siguiente:

   ```text
   CONTAINER ID   IMAGE     COMMAND                  CREATED              STATUS              PORTS                NAMES
   2cf7c484c144   nginx     "/docker-entrypoint.…"   9 seconds ago        Up 8 seconds        0.0.0.0:80->80/tcp   nginx
   7a070c9ffeaa   web       "docker-entrypoint.s…"   19 seconds ago       Up 18 seconds                            web2
   6dc6d4e60aaf   web       "docker-entrypoint.s…"   34 seconds ago       Up 33 seconds                            web1
   008e0ecf4f36   redis     "docker-entrypoint.s…"   About a minute ago   Up About a minute   6379/tcp             redis
   ```

7. Si miras el Panel de Docker Desktop, puedes ver los contenedores y profundizar en su configuración.

   ![Una captura de pantalla del Panel de Docker Desktop que muestra aplicaciones multicontenedor](/get-started/docker-concepts/running-containers/multi-container-applications/images/multi-container-apps.webp?w=5000&border=true)

8. Con todo funcionando, puedes abrir [http://localhost](http://localhost) en tu navegador para ver el sitio. Actualiza la página varias veces para ver el host que está manejando la solicitud y el número total de solicitudes:

   ```console
   web2: Number of visits is: 9
   web1: Number of visits is: 10
   web2: Number of visits is: 11
   web1: Number of visits is: 12
   ```

   > [!NOTE]
   >
   > Es posible que hayas notado que Nginx, actuando como un proxy inverso, probablemente distribuye las solicitudes entrantes de manera round-robin entre los dos contenedores backend. Esto significa que cada solicitud podría dirigirse a un contenedor diferente (web1 y web2) de forma rotativa. La salida muestra incrementos consecutivos para ambos contenedores web1 y web2, y el valor real del contador almacenado en Redis se actualiza solo después de que la respuesta se envía de vuelta al cliente.

9. Puedes usar el Panel de Docker Desktop para eliminar los contenedores seleccionándolos y haciendo clic en el botón **Delete**.

   ![Una captura de pantalla del Panel de Docker Desktop que muestra cómo eliminar las aplicaciones multicontenedor](/get-started/docker-concepts/running-containers/multi-container-applications/images/delete-multi-container-apps.webp?border=true)

## Simplificar la implementación utilizando Docker Compose

Docker Compose proporciona un enfoque estructurado y simplificado para gestionar implementaciones multicontenedor. Como se mencionó anteriormente, con Docker Compose, no es necesario ejecutar múltiples comandos `docker run`. Todo lo que necesitas hacer es definir toda tu aplicación multicontenedor en un solo archivo YAML llamado `compose.yml`. Veamos cómo funciona.

Navega a la raíz del directorio del proyecto. Dentro de este directorio, encontrarás un archivo llamado `compose.yml`. En este archivo YAML es donde ocurre toda la magia. Define todos los servicios que componen tu aplicación, junto con sus configuraciones. Cada servicio especifica su imagen, puertos, volúmenes, redes y cualquier otra configuración necesaria para su funcionamiento.

1. Utiliza el comando `docker compose up` para iniciar la aplicación:

   ```console
   $ docker compose up -d --build
   ```

   Cuando ejecutes este comando, deberías ver una salida similar a la siguiente:

   ```console
    ✔ Network nginx-node-redis_default   Created                                                                                                   0.0s
    ✔ Container nginx-node-redis-web2-1  Created                                                                                                   0.1s
    ✔ Container nginx-node-redis-web1-1  Created                                                                                                   0.1s
    ✔ Container nginx-node-redis-redis-1 Created                                                                                                   0.1s
    ✔ Container nginx-node-redis-nginx-1 Created

   ```

2. Si miras el Panel de Docker Desktop, puedes ver los contenedores y profundizar en su configuración.

   ![Una captura de pantalla del Panel de Docker Desktop que muestra los contenedores de la pila de aplicaciones implementada utilizando Docker Compose](/get-started/docker-concepts/running-containers/multi-container-applications/images/list-containers.webp?border=true)

3. Alternativamente, puedes usar el Panel de Docker Desktop para eliminar los contenedores seleccionando la pila de aplicaciones y haciendo clic en el botón **Delete**.

   ![Una captura de pantalla del Panel de Docker Desktop que muestra cómo eliminar los contenedores que implementaste utilizando Docker Compose](/get-started/docker-concepts/running-containers/multi-container-applications/images/delete-containers.webp?border=true)

En esta guía, aprendiste lo fácil que es usar Docker Compose para iniciar y detener una aplicación multicontenedor en comparación con `docker run`, que es propenso a errores y difícil de administrar.

## Recursos adicionales

- [`docker container run` referencia de CLI](/get-started/docker-concepts/running-containers/multi-container-applications/reference/cli/docker/container/run)
- [Qué es Docker Compose](/get-started/docker-concepts/the-basics/what-is-docker-compose/)

