# Usar Docker Compose


[Docker Compose](/compose/) es una herramienta que ayuda a definir y compartir aplicaciones de múltiples contenedores. Con Compose, puedes crear un archivo YAML para definir los servicios y, con un solo comando, puedes poner todo en marcha o destruirlo por completo.

La gran ventaja de utilizar Compose es que puedes definir la pila de tu aplicación en un archivo, mantenerlo en la raíz del repositorio de tu proyecto (ahora bajo control de versiones) y facilitar que otra persona colabore en tu proyecto. Solo necesitarían clonar tu repositorio e iniciar la aplicación utilizando Compose. De hecho, es muy común ver bastantes proyectos en GitHub/GitLab que hacen exactamente esto actualmente.

## Crear el archivo de Compose

En el directorio `getting-started-app`, crea un archivo llamado `compose.yaml`.

```text
├── getting-started-app/
│ ├── Dockerfile
│ ├── compose.yaml
│ ├── node_modules/
│ ├── package.json
│ ├── package-lock.json
│ ├── spec/
│ └── src/
```

## Definir el servicio de la aplicación

En la [parte 6](/get-started/workshop/07_multi_container/), utilizaste el siguiente comando para iniciar el servicio de la aplicación.

```console
$ docker run -dp 127.0.0.1:3000:3000 \
  -w /app -v ".:/app" \
  --network todo-app \
  -e MYSQL_HOST=mysql \
  -e MYSQL_USER=root \
  -e MYSQL_PASSWORD=secret \
  -e MYSQL_DB=todos \
  node:24-alpine \
  sh -c "npm install && npm run dev"
```

Ahora definirás este servicio en el archivo `compose.yaml`.

1. Abre `compose.yaml` en un editor de texto o código, y comienza definiendo el nombre y la imagen del primer servicio (o contenedor) que deseas ejecutar como parte de tu aplicación. El nombre se convertirá automáticamente en un alias de red, lo que será útil al definir tu servicio MySQL.

   ```yaml
   services:
     app:
       image: node:24-alpine
   ```

2. Normalmente verás `command` cerca de la definición de `image`, aunque no existe un requisito de orden. Agrega `command` a tu archivo `compose.yaml`.

   ```yaml
   services:
     app:
       image: node:24-alpine
       command: sh -c "npm install && npm run dev"
   ```

3. Ahora migra la parte `-p 127.0.0.1:3000:3000` del comando definiendo los puertos (`ports`) para el servicio.

   ```yaml
   services:
     app:
       image: node:24-alpine
       command: sh -c "npm install && npm run dev"
       ports:
         - 127.0.0.1:3000:3000
   ```

4. A continuación, migra tanto el directorio de trabajo (`-w /app`) como el mapeo de volumen (`-v ".:/app"`) utilizando las definiciones `working_dir` y `volumes`.

   Una ventaja de las definiciones de volumen de Docker Compose es que puedes usar rutas relativas desde el directorio actual.

   ```yaml
   services:
     app:
       image: node:24-alpine
       command: sh -c "npm install && npm run dev"
       ports:
         - 127.0.0.1:3000:3000
       working_dir: /app
       volumes:
         - ./:/app
   ```

5. Por último, debes migrar las definiciones de las variables de entorno utilizando la clave `environment`.

   ```yaml
   services:
     app:
       image: node:24-alpine
       command: sh -c "npm install && npm run dev"
       ports:
         - 127.0.0.1:3000:3000
       working_dir: /app
       volumes:
         - ./:/app
       environment:
         MYSQL_HOST: mysql
         MYSQL_USER: root
         MYSQL_PASSWORD: secret
         MYSQL_DB: todos
   ```

### Definir el servicio MySQL

Ahora es el momento de definir el servicio MySQL. El comando que utilizaste para ese contenedor fue el siguiente:

```console
$ docker run -d \
  --network todo-app --network-alias mysql \
  -v todo-mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  -e MYSQL_DATABASE=todos \
  mysql:8.0
```

1. Primero define the nuevo servicio y llámalo `mysql` para que obtenga automáticamente el alias de red. Especifica también la imagen que se va a utilizar.

   ```yaml
   services:
     app:
       # La definición del servicio app
     mysql:
       image: mysql:8.0
   ```

2. A continuación, define el mapeo de volumen. Cuando ejecutaste el contenedor con `docker run`, Docker creó el volumen con nombre automáticamente. Sin embargo, eso no sucede cuando se ejecuta con Compose. Debes definir el volumen en la sección superior `volumes:` y luego especificar el punto de montaje en la configuración del servicio. Al proporcionar simplemente el nombre del volumen, se utilizarán las opciones predeterminadas.

   ```yaml
   services:
     app:
       # La definición del servicio app
     mysql:
       image: mysql:8.0
       volumes:
         - todo-mysql-data:/var/lib/mysql

   volumes:
     todo-mysql-data:
   ```

3. Por último, debes especificar las variables de entorno.

   ```yaml
   services:
     app:
       # La definición del servicio app
     mysql:
       image: mysql:8.0
       volumes:
         - todo-mysql-data:/var/lib/mysql
       environment:
         MYSQL_ROOT_PASSWORD: secret
         MYSQL_DATABASE: todos

   volumes:
     todo-mysql-data:
   ```

En este punto, tu archivo `compose.yaml` completo debería verse así:

```yaml
services:
  app:
    image: node:24-alpine
    command: sh -c "npm install && npm run dev"
    ports:
      - 127.0.0.1:3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:
```

## Ejecutar la pila de la aplicación

Ahora que tienes tu archivo `compose.yaml`, puedes iniciar tu aplicación.

1. Asegúrate primero de que no se estén ejecutando otras copias de los contenedores. Utiliza `docker ps` para enumerar los contenedores y `docker rm -f <ids>` para eliminarlos.

2. Inicia la pila de la aplicación utilizando el comando `docker compose up`. Agrega la bandera `-d` para ejecutar todo en segundo plano.

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

   Al ejecutar el comando anterior, deberías ver una salida como la siguiente:

   ```plaintext
   Creating network "app_default" with the default driver
   Creating volume "app_todo-mysql-data" with default driver
   Creating app_app_1   ... done
   Creating app_mysql_1 ... done
   ```

   Notarás que Docker Compose creó el volumen así como una red. Por defecto, Docker Compose crea automáticamente una red específicamente para la pila de la aplicación (que es la razón por la que no definiste una en el archivo de Compose).

3. Observa los registros utilizando el comando `docker compose logs -f`. Verás los registros de cada uno de los servicios intercalados en una sola transmisión. Esto es increíblemente útil cuando deseas vigilar problemas relacionados con la sincronización. La bandera `-f` sigue el registro, por lo que te dará la salida en vivo a medida que se genera.

   Si ya ejecutaste el comando, verás una salida que se parece a esto:

   ```plaintext
   mysql_1  | 2019-10-03T03:07:16.083639Z 0 [Note] mysqld: ready for connections.
   mysql_1  | Version: '8.0.31'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
   app_1    | Connected to mysql db at host mysql
   app_1    | Listening on port 3000
   ```

   El nombre del servicio se muestra al principio de la línea (a menudo en color) para ayudar a distinguir los mensajes. Si deseas ver los registros de un servicio específico, puedes agregar el nombre del servicio al final del comando de registros (por ejemplo, `docker compose logs -f app`).

4. En este punto, deberías poder abrir tu aplicación en tu navegador en [http://localhost:3000](http://localhost:3000) y verla ejecutándose.

## Ver la pila de la aplicación en el panel de control de Docker Desktop

Si miras el panel de control (Dashboard) de Docker Desktop, verás que hay un grupo llamado **getting-started-app**. Este es el nombre del proyecto de Docker Compose y se utiliza para agrupar los contenedores. Por defecto, el nombre del proyecto es simplemente el nombre del directorio en el que se encontraba el archivo `compose.yaml`.

Si expandes la pila, verás los dos contenedores que definiste en el archivo de Compose. Los nombres también son un poco más descriptivos, ya que siguen el patrón de `<nombre-servicio>-<numero-replica>`. Por lo tanto, es muy fácil ver rápidamente qué contenedor es tu aplicación y qué contenedor es la base de datos MySQL.

## Destruir todo

Cuando estés listo para destruirlo todo, simplemente ejecuta `docker compose down` o presiona el ícono de la papelera en el panel de control de Docker Desktop para toda la aplicación. Los contenedores se detendrán y la red se eliminará.

> [!WARNING]
>
> Por defecto, los volúmenes con nombre en tu archivo de Compose no se eliminan al ejecutar `docker compose down`. Si deseas eliminar los volúmenes, debes agregar la bandera `--volumes`.
>
> El panel de control de Docker Desktop no elimina los volúmenes cuando borras la pila de la aplicación.

## Resumen

En esta sección, aprendiste sobre Docker Compose y cómo te ayuda a simplificar la forma en que defines y compartes aplicaciones multiservicio.

Información relacionada:

- [Descripción general de Compose](/compose/)
- [Referencia del archivo de Compose](/reference/compose-file/)
- [Referencia de la CLI de Compose](/reference/cli/docker/compose/)

## Siguientes pasos

A continuación, aprenderás sobre algunas de las mejores prácticas que puedes utilizar para mejorar tu Dockerfile.

[Mejores prácticas para la compilación de imágenes](/get-started/workshop/08_using_compose/09_image_best/)

ext="Image-building best practices" url="09_image_best.md" >}}

