# Desplegar una pila (stack) en un swarm


Al ejecutar Docker Engine en modo swarm, puedes utilizar el comando `docker stack deploy` para desplegar una pila de aplicaciones completa en el swarm. El comando `deploy` acepta una descripción de la pila en forma de [archivo Compose](/reference/compose-file/legacy-versions/).



> [!NOTE]
>
> El comando `docker stack deploy` utiliza el formato heredado
> [versión 3 del archivo Compose](/reference/compose-file/legacy-versions/),
> utilizado por Compose V1. El formato definido por la
> [especificación de Compose](/reference/compose-file/)
> no es compatible con el comando `docker stack deploy`.
>
> Para obtener más información sobre la evolución de Compose, consulta la
> [Historia de Compose](/compose/history/).


Para realizar este tutorial, necesitas:

1.  Un Docker Engine ejecutándose en [modo Swarm](/engine/swarm/stack-deploy/swarm-mode/).
    Si no estás familiarizado con el modo Swarm, es recomendable leer los
    [Conceptos clave del modo Swarm](/engine/swarm/stack-deploy/key-concepts/)
    y [Cómo funcionan los servicios](/engine/swarm/stack-deploy/how-swarm-mode-works/services/).

    > [!NOTE]
    > 
    > Si estás probando esto en un entorno de desarrollo local,
    > puedes activar el modo Swarm en tu motor de ejecución con `docker swarm init`.
    > 
    > Si ya tienes un swarm de múltiples nodos en funcionamiento, ten en cuenta que todos los
    > comandos `docker stack` y `docker service` deben ejecutarse desde un nodo administrador (manager).

2.  Una versión reciente de [Docker Compose](/compose/install/).

## Configurar un registro de Docker (Registry)

Dado que un swarm consta de múltiples Docker Engines, se requiere un registro para distribuir las imágenes a todos ellos. Puedes utilizar [Docker Hub](https://hub.docker.com) o mantener tu propio registro. A continuación, se detalla cómo crear un registro temporal, que podrás eliminar después.

1.  Inicia el registro como un servicio en tu swarm:

    ```console
    $ docker service create --name registry --publish published=5000,target=5000 registry:2
    ```

2.  Comprueba su estado con `docker service ls`:

    ```console
    $ docker service ls

    ID            NAME      REPLICAS  IMAGE                                                                               COMMAND
    l7791tpuwkco  registry  1/1       registry:2@sha256:1152291c7f93a4ea2ddc95e46d142c31e743b6dd70e194af9e6ebe530f782c17
    ```

    Cuando se lea `1/1` en la columna `REPLICAS`, estará en funcionamiento. Si indica `0/1`, probablemente todavía esté descargando la imagen.

3.  Verifica que esté funcionando utilizando `curl`:

    ```console
    $ curl http://127.0.0.1:5000/v2/

    {}
    ```

## Crear la aplicación de ejemplo

La aplicación utilizada en esta guía se basa en la aplicación de contador de visitas de la guía [Primeros pasos con Docker Compose](/compose/gettingstarted/). Consiste en una aplicación en Python que mantiene un contador en una instancia de Redis e incrementa el contador cada vez que la visitas.

1.  Crea un directorio para el proyecto:

    ```console
    $ mkdir stackdemo
    $ cd stackdemo
    ```

2.  Crea un archivo llamado `app.py` en el directorio del proyecto y pega el siguiente contenido:

    ```python
    from flask import Flask
    from redis import Redis

    app = Flask(__name__)
    redis = Redis(host='redis', port=6379)

    @app.route('/')
    def hello():
        count = redis.incr('hits')
        return 'Hello World! I have been seen {} times.\n'.format(count)

    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8000, debug=True)
    ```

3.  Crea un archivo llamado `requirements.txt` y pega estas dos líneas:

    ```text
    flask
    redis
    ```

4.  Crea un archivo llamado `Dockerfile` y pega el siguiente contenido:

    ```dockerfile
    # syntax=docker/dockerfile:1
    FROM python:3.4-alpine
    ADD . /code
    WORKDIR /code
    RUN pip install -r requirements.txt
    CMD ["python", "app.py"]
    ```

5.  Crea un archivo llamado `compose.yaml` y pega el siguiente contenido:

    ```yaml
      services:
        web:
          image: 127.0.0.1:5000/stackdemo
          build: .
          ports:
            - "8000:8000"
        redis:
          image: redis:alpine
    ```

    La imagen para la aplicación web se construye utilizando el Dockerfile definido anteriormente. También se etiqueta con `127.0.0.1:5000`, que es la dirección del registro creado previamente. Esto es importante al distribuir la aplicación en el swarm.

## Probar la aplicación con Compose

1.  Inicia la aplicación con `docker compose up`. Esto construye la imagen de la aplicación web, descarga la imagen de Redis si aún no la tienes y crea dos contenedores.

    Verás una advertencia indicando que el motor de ejecución está en modo Swarm. Esto se debe a que Compose no aprovecha el modo Swarm y despliega todo en un único nodo. Puedes ignorar esta advertencia.

    ```console
    $ docker compose up -d

    WARNING: The Docker Engine you're using is running in swarm mode.

    Compose does not use swarm mode to deploy services to multiple nodes in
    a swarm. All containers are scheduled on the current node.

    To deploy your application across the swarm, use `docker stack deploy`.

    Creating network "stackdemo_default" with the default driver
    Building web
    ...(build output)...
    Creating stackdemo_redis_1
    Creating stackdemo_web_1
    ```

2.  Verifica que la aplicación se esté ejecutando utilizando `docker compose ps`:

    ```console
    $ docker compose ps

          Name                     Command               State           Ports
    -----------------------------------------------------------------------------------
    stackdemo_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
    stackdemo_web_1     python app.py                    Up      0.0.0.0:8000->8000/tcp
    ```

    Puedes probar la aplicación utilizando `curl`:

    ```console
    $ curl http://localhost:8000
    Hello World! I have been seen 1 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 2 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 3 times.
    ```

3.  Detén y elimina la aplicación:

    ```console
    $ docker compose down --volumes

    Stopping stackdemo_web_1 ... done
    Stopping stackdemo_redis_1 ... done
    Removing stackdemo_web_1 ... done
    Removing stackdemo_redis_1 ... done
    Removing network stackdemo_default
    ```

## Subir la imagen generada al registro

Para distribuir la imagen de la aplicación web por todo el swarm, es necesario subirla al registro que configuraste anteriormente. Con Compose, este proceso es directo:

```console
$ docker compose push

Pushing web (127.0.0.1:5000/stackdemo:latest)...
The push refers to a repository [127.0.0.1:5000/stackdemo]
5b5a49501a76: Pushed
be44185ce609: Pushed
bd7330a79bcf: Pushed
c9fc143a069a: Pushed
011b303988d2: Pushed
latest: digest: sha256:a81840ebf5ac24b42c1c676cbda3b2cb144580ee347c07e1bc80e35e5ca76507 size: 1372
```

La pila (stack) ya está lista para ser desplegada.

## Desplegar la pila al swarm

1.  Crea la pila utilizando el comando `docker stack deploy`:

    ```console
    $ docker stack deploy --compose-file compose.yaml stackdemo

    Ignoring unsupported options: build

    Creating network stackdemo_default
    Creating service stackdemo_web
    Creating service stackdemo_redis
    ```

    El último argumento es el nombre de la pila. Cada red, volumen y nombre de servicio tendrá como prefijo el nombre de la pila.

2.  Comprueba que se esté ejecutando utilizando `docker stack services stackdemo`:

    ```console
    $ docker stack services stackdemo

    ID            NAME             MODE        REPLICAS  IMAGE
    orvjk2263y1p  stackdemo_redis  replicated  1/1       redis:3.2-alpine@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d
    s1nf0xy8t1un  stackdemo_web    replicated  1/1       127.0.0.1:5000/stackdemo@sha256:adb070e0805d04ba2f92c724298370b7a4eb19860222120d43e0f6351ddbc26f
    ```

    Una vez que esté en funcionamiento, deberías ver `1/1` en la columna `REPLICAS` para ambos servicios. Esto puede tardar un poco si tienes un swarm de múltiples nodos, ya que se deben descargar las imágenes.

    Como antes, puedes probar la aplicación con `curl`:

    ```console
    $ curl http://localhost:8000
    Hello World! I have been seen 1 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 2 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 3 times.
    ```

    Con la malla de enrutamiento integrada de Docker, puedes acceder a cualquier nodo del swarm en el puerto `8000` y ser redirigido a la aplicación:

    ```console
    $ curl http://address-of-other-node:8000
    Hello World! I have been seen 4 times.
    ```

3.  Elimina la pila con el comando `docker stack rm`:

    ```console
    $ docker stack rm stackdemo

    Removing service stackdemo_web
    Removing service stackdemo_redis
    Removing network stackdemo_default
    ```

4.  Elimina el registro utilizando el comando `docker service rm`:

    ```console
    $ docker service rm registry
    ```

5.  Si solo estás probando cosas en una máquina local y deseas retirar tu Docker Engine del modo Swarm, utiliza `docker swarm leave`:

    ```console
    $ docker swarm leave --force

    Node left the swarm.
    ```

