Objetivos

Al finalizar el tutorial el estudiante estará en capacidad de:

Requisitos para desarrollar el tutorial

Docker compose ya está incluido con la instalación de Docker desktop para los sistemas operativos Mac y Windows, si siguió el primer tutorial de "hello docker" de la semana 1 usted ya debería contar con dicha instalación, para validarlo ejecute el siguiente comando:

user@192 ~ % docker-compose --version
Docker Compose version v2.5.0

Podrá ver la versión correspondiente a docker compose en su sistema.

A diferencia de Mac y Windows, donde docker compose ya viene instalado por defecto al descargar docker desktop, linux requiere unos pasos adicionales.

Para instalar docker compose en linux siga los siguientes pasos:

  1. Descargue la última versión estable:
user@192 ~ % sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  1. Dar permisos de ejecución:
user@192 ~ % sudo chmod +x /usr/local/bin/docker-compose

Una vez termine los pasos enunciados anteriormente, si en consola ejecuta:

user@192 ~ % docker-compose --version
Docker Compose version v2.5.0

Podrá ver la versión correspondiente a docker compose en su sistema.

Docker compose permite ejecutar varios contenedores al mismo tiempo, denominandolos servicios. Con su ayuda, se pueden configurar volúmenes compartidos, redes, variables y gestionar la ejecución de todo el grupo; aplicaciones multicontenedor. Para entender cómo funciona, usaremos el proyecto de trabajo de calculadora-numeros, navegue dentro del repositorio al tag vSumaMultiplicacion, puede cambiar de rama a este tag desde una terminal ubicándose en la carpeta del proyecto mediante el comando:

user@192 ~ % git checkout vSumaMultiplicacion

Si analiza el código con detenimiento, notará una nueva carpeta llamada "multiplicación" presente en el directorio, esta corresponde a un nuevo API cuya función es multiplicar dos números y devolver su resultado. De igual manera podrá ver el microservicio de suma y un archivo nuevo llamado docker-compose.yml. Este archivo YAML se usa para configurar los servicios de la aplicación, luego mediante un solo comando se crean e inicializan los servicios allí descritos. Para el caso del ejemplo, se muestran campos tales como:

version: "3.7"
services:
  multiplicacion:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1
    ports:
      - 4000:4000
    environment:
      user_name: Estudiante

  suma:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1
    ports:
      - 5001:4000
    environment:
      user_name: Estudiante

Fíjese como en este archivo estamos definiendo dos servicios.

Docker compose up permite ejecutar el archivo YML y poner en marcha los servicios allí descritos. Recuerde que el archivo YML funciona como un set de instrucciones para levantar varias imágenes en contenedores a la vez. Para ejecutar el archivo ejecute el siguiente comando:

user@192 ~ % docker compose up -d

Luego de ejecutarlo podrá ver cómo se ejecutan dos imágenes del repositorio remoto en el contenedores separados.

user@192 ~ % docker compose up -d
[+] Running 2/2
 ⠿ Container calculadora-numeros-multiplicacion-1  Started                                                                                                                                                       0.4s
 ⠿ Container calculadora-numeros-suma-1            Started

Para comprobar que evidentemente los contenedores están corriendo ejecute docker ps:

user@192 ~ % docker ps
CONTAINER ID   IMAGE                                                                                       COMMAND            CREATED         STATUS         PORTS                    NAMES
cd9544e01bb9   ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1             "python view.py"   5 minutes ago   Up 5 minutes   0.0.0.0:5001->4000/tcp   calculadora-numeros-suma-1
9df5b4677e53   ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1   "python view.py"   5 minutes ago   Up 5 minutes   0.0.0.0:4000->4000/tcp   calculadora-numeros-multiplicacion-1

En este punto del tutorial, en su máquina local está corriendo dos contenedores con el código asociado al API de calculadora (suma y multiplicación), para probar su correcta ejecución utilice la plataforma de API con la que se sienta más cómodo (e.i Postman) o por medio de curl:

user@192 ~ % curl --location --request POST 'http://localhost:5001/suma' \
--header 'Content-Type: application/json' \
--data-raw '{    
    "num_1" : 2,
    "num_2": 3
}'

Note como estamos consumiendo el servicio /suma ejecutándose en el puerto 5001 (De nuestra máquina local y 4000 de la contenedora respectivamente gracias al binding de puertos), para sumar los números 2 y 3. Al ejecutar la consulta anteriormente expuesta podrá ver lo siguiente:

{
    "message": "Estudiante la suma de los dos números es: 5",
    "result": 5
}

Como es esperado, se ve el resultado de la suma con un valor igual a 5, repita el mismo proceso con el de multiplicación (Nota: recuerde que el microservicio de suma corre en el puerto 5001, al ocupar este puerto, no podemos levantar el de multiplicación en el mismo, por lo que si se fija en el archivo YML del docker compose, el microservicio de multiplicación correrá en el puerto 4000). Para probar la correcta ejecución del microservicio de multiplicación ejecute el siguiente curl:

user@192 ~ % curl --location --request POST 'http://localhost:4000/multiplicar' \
--header 'Content-Type: application/json' \
--data-raw '{    
    "num_1" : 2,
    "num_2": 3
}'

Al ejecutar la consulta anteriormente expuesta podrá ver lo siguiente:

{
    "message": "Estudiante la multiplicación de los dos números es: 6",
    "result": 6
}

Experimente un poco el endpoint y pruebe con otros números de su interés.

(Si desea leer mas al respecto de docker compose up diríjase a este link )

Una vez termine de probar los dos endpoints, para liberar los recursos usados por los contenedores y detenerlos, el comando docker compose stop hace la tarea. Ejecute en su terminal el comando docker ps:

user@192 ~ % docker ps
CONTAINER ID   IMAGE                                                                                       COMMAND            CREATED         STATUS         PORTS                    NAMES
cd9544e01bb9   ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1             "python view.py"   5 minutes ago   Up 5 minutes   0.0.0.0:5001->4000/tcp   calculadora-numeros-suma-1
9df5b4677e53   ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1   "python view.py"   5 minutes ago   Up 5 minutes   0.0.0.0:4000->4000/tcp   calculadora-numeros-multiplicacion-1

Al ejecutarlo puede ver que los contenedores están en status "Up", ahora los vamos a detener mediante el comando docker-compose stop, puede esperar lo siguiente:

user@192 ~ % docker-compose stop
[+] Running 2/2
 ⠿ Container calculadora-numeros-suma-1            Stopped                                                                                                                                                       0.2s
 ⠿ Container calculadora-numeros-multiplicacion-1  Stopped 

Fíjese cómo se detienen ambas contenedoras en simultáneo, esto facilita que no tengamos que detener una por una con el id de la contenedora. Este comando es necesario cuando los contenedores no estén en uso, ya que libera recursos de memoria, CPU y red.

(Si desea leer mas al respecto de docker compose stop diríjase a este link )

Recuerde que al ejecutar el comando docker-compose stop solo detuvo las contenedoras, esto quiere decir que estas aún viven en su computadora, si quisiera iniciarlas nuevamente ejecute el comando docker-compose start sobre la raíz del proyecto:

user@192 ~ % docker-compose start

Podrá esperar lo siguiente en su terminal:

user@192 ~ % docker-compose start
[+] Running 2/2                                                                                                                                                   0.4s
 ⠿ Container calculadora-numeros-multiplicacion-1  Started                                                                                                                                                       0.3s
 ⠿ Container calculadora-numeros-suma-1            Started                                              

Como puede notar, las contenedoras pasan de un estado Stopped a un estado Started, esto facilita el reciclaje de componentes para no tener que crear un duplicado compilando el archivo docker-compose.yml nuevamente.

(Si desea leer mas al respecto de docker compose start diríjase a este link )

Si observa en el código la línea 13, se captura una variable de entorno con el nombre de "user_name", el valor de esta es pasado a la respuesta de la operación, por defecto el docker-compose.yml tiene declarado el valor por defecto "Estudiante". Para pasar una variable de entorno desde el archivo docker-compose.yml a la contenedora que se va a ejecutar debe considerar los siguientes campos:

environment:
      <NOMBRE_VARIABLE_ENTORNO>: <VALOR_VARIABLE>

Para cambiar el valor de de la variable user_name e imprimir su nombre, diríjase al archivo docker-compose.yml, allí cambie el valor de Estudiante por su nombre, para ambos servicios allí declarados,el archivo se debe ver de la siguiente manera:

version: "3.7"
services:
  multiplicacion:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1
    ports:
      - 4000:4000
    environment:
      user_name: Andrés


  suma:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1
    ports:
      - 5001:4000
    environment:
      user_name: Andrés

Al generar este cambio, es necesario recompilar el archivo docker-compose.yml, para esto guíese de los pasos anteriores y ejecute el comando docker-compose up. Una vez levantados los nuevos contenedores, consuma nuevamente los microservicios, debería obtener una respuesta a las operaciones con su nombre en esta. Para el caso de la multiplicación:

user@192 ~ % curl --location --request POST 'http://localhost:4000/multiplicar' \
--header 'Content-Type: application/json' \
--data-raw '{    
    "num_1" : 2,
    "num_2": 3
}'
{
    "message": "Andrés la multiplicación de los dos números es: 6",
    "result": 6
}

(Si desea leer mas al respecto de variables de entorno diríjase a este link )

En este tutorial crearemos una red de tipo "bridge" que será compartida entre las contenedoras, para crearla ejecute el comando:

user@192 ~ % docker network create -d bridge <NOMBRE_RED>

Para el ejemplo crearemos la red llamada COMPOSE_01, en consola se verá de la siguiente manera:

user@192 ~ % docker network create -d bridge COMPOSE_01
777d2e29061cba0355245dcfc3ee1ff5dbb14bf1acc6cdb5bfa398cf26bb9406

Como resultado obtendrá un hash asociado al id de la red creada. Para validar su correcta creación, ejecute:

user@192 ~ % docker network ls

Obtendrá el siguiente resultado:

user@192 ~ % docker network ls
NETWORK ID     NAME                             DRIVER    SCOPE
777d2e29061c   COMPOSE_01                       bridge    local

Si desea ver más detalles de la red puede ejecutar:

user@192 ~ % docker network inspect <NOMBRE_RED>

Para el ejemplo obtendrá el siguiente resultado:

user@192 ~ % docker network inspect COMPOSE_01
[
    {
        "Name": "COMPOSE_01",
        "Id": "777d2e29061cba0355245dcfc3ee1ff5dbb14bf1acc6cdb5bfa398cf26bb9406",
        "Created": "2022-10-21T22:27:03.477940544Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
...

Observe cómo este comando arroja propiedades tales como el ID de la red, la fecha de creación, el tipo de red (Correspondiente a bridge), la subnet y el gateway asociado a esta.

Para asociarla al arranque de los contenedores en simultáneo, en el archivo docker-compose.yml, las redes se agregan de la siguiente manera:

networks:
-<NOMBRE_RED>

Para el ejemplo asociaremos la red COMPOSE_01, creada recientemente, por lo que la sección anterior debe verse de la siguiente forma para ambos microservicios declarados:

networks:
- COMPOSE_01

Agregue al final del archivo un apartado networks con el respectivo driver de la red, en este caso corresponde a una red de tipo bridge:

networks:
  COMPOSE_01:
    driver: bridge

El archivo docker-compose.yml debe verse de la siguiente manera luego de agregar la nueva red:

version: "3.7"

services:
  multiplicacion:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1
    ports:
      - 4000:4000
    environment:
      user_name: Andrés
    networks:
      -  COMPOSE_01


  suma:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1
    ports:
      - 5001:4000
    environment:
      user_name: Andrés
    networks:
      -  COMPOSE_01
    
networks:
  COMPOSE_01:
    driver: bridge

Recompile nuevamente los contenedores mediante docker compose up para que se creen nuevas instancias con la red agregada.

En este punto, tiene nuevamente los contenedores ejecutándose en background con la red COMPOSE_01, para validar que quedarán asociados con éxito al momento de levantarse las instancias, ejecute docker ps para capturar el id de alguno de los dos contenedores (suma y/o multiplicación).

user@192 ~ % docker ps
CONTAINER ID   IMAGE                                                                                       COMMAND            CREATED         STATUS         PORTS                    NAMES
a9167e7cbe96   ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1   "python view.py"   9 minutes ago   Up 9 minutes   0.0.0.0:4000->4000/tcp   calculadora-numeros-multiplicacion-1
84a5ba401f1d   ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1             "python view.py"   9 minutes ago   Up 9 minutes   0.0.0.0:5001->4000/tcp   calculadora-numeros-suma-1

Tome el id de alguno de los contenedores y ejecute el comando:

user@192 ~ % docker inspect <ID_CONTENEDOR>

Para el caso del ejemplo podrá esperar lo siguiente (Recuerde que el id de los contenedores no es el mismo que en su máquina local, por ende debe consultar el suyo):

user@192 ~ % docker inspect a9167e7cbe96
...
"Networks": {
                "calculadora-numeros_COMPOSE_01": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "calculadora-numeros-multiplicacion-1",
                        "multiplicacion",
                        "a9167e7cbe96"
                    ],
                    "NetworkID": "e217cb5e36eaa16d983c82d17a5a73a06fd8011079f0e9bd3ac536026def2a92",
                    "EndpointID": "d159fb5a5949adb236cfe06d1a5a64e31223883e8382e018c31fe7062fb5997a",
                    "Gateway": "172.22.0.1",
                    "IPAddress": "172.22.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:16:00:03",
                    "DriverOpts": null
                }
            }
...

Después de ejecutar el comando, podrá ver en formato JSON información asociada a la contenedora, si busca la sección de "Networks" podrá ver que la contenedora quedó asociada a una red de tipo "bridge" llamada COMPOSE_01, la cual corresponde a que hemos creado en pasos anteriores.

(Si desea leer mas al respecto de docker-compose network diríjase a este link )

Si observa en el código la línea 27, se captura una variable de entorno con el nombre de "write_result", esta variable se encarga de escribir el resultado de las respectivas operaciones en un directorio llamado data_file dentro de la contenedora. Sin embargo si quisiera generar una copia del archivo resultante en su máquina local (Recuerde que el archivo se escribe dentro de la contenedora y por lo tanto queda aislado, a menos de que entremos a la misma), puede crear un volumen. Algunos beneficios de los volúmenes son:

Primero agregue la variable "write_result" al archivo docker-compose.yml, asignele el valor de "show":

environment:
      write_result: show

Para crear un volumen desde el archivo docker-compose.yml a la contenedora que se va a ejecutar debe considerar los siguientes campos:

volumes:
- <DIRECTORIO_MAQUINA_LOCAL>: <DIRECTORIO_CONTENEDORORA>

Note que el primer parámetro corresponde al directorio local de su máquina, donde quiere almacenar el archivo y el segundo corresponde al directorio de la contenedora donde guardará la respuesta de la operación, en el caso del ejemplo corresponde al directorio data_file, si desea ver más a profundidad en el código como se guarda el archivo puede consultarlo en la siguiente sección.

Para el caso del ejemplo, agregue en el docker-compose.yml la siguientes líneas en los servicios de suma y multiplicación:

 volumes:
      - ./data_file/:/app/data_file

El archivo completo se debe ver de la siguiente manera:

version: "3.7"

services:
  multiplicacion:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vmultiplicacion-0.0.1
    ports:
      - 4000:4000
    environment:
      user_name: Andres
      write_result: show
    networks:
      -  COMPOSE_01
    volumes:
      - ./data_file/:/app/data_file


  suma:
    image: ghcr.io/misw-4301-desarrollo-apps-en-la-nube/s1-calculadora-numeros:vSuma-0.0.1
    ports:
      - 5001:4000
    environment:
      user_name: Andres
      write_result: show
    networks:
      -  COMPOSE_01
    volumes:
      - ./data_file/:/app/data_file

networks:
  COMPOSE_01:
    # Use a custom driver
    driver: bridge

Al generar este cambio, es necesario recompilar el archivo docker-compose.yml, para esto guíese de los pasos anteriores y ejecute el comando docker-compose up. Una vez levantados los nuevos contenedores, consuma nuevamente los microservicios, debería obtener en la ubicación del proyecto un directorio llamado data_file. Si abre el archivo resultados.txt contenido en este directorio, para la operación de la suma, podrá observar la respuesta:

Hola Andrés! Al sumar 2 y 5 se obtiene como resultado 7 

Felicidades, ha creado un sistema de volúmenes para conectar archivos de la contenedora con su máquina local, si desea entrar a la contenedora y validar la creación del archivo resultado.txt, remítase al tutorial de la semana 1 Docker, env, redes.

(Si desea leer mas al respecto de docker-compose volumes diríjase a este link )

Si tiene problemas durante el desarrollo de este tutorial, comuníquese por el canal de slack.

[1] "Docker," Docker Documentation, 29-Sep-2022. [Online]. Available: https://docs.docker.com/engine/reference/commandline/docker/. [Accessed: 30-Sep-2022].

[2] Google docs: Sign-in. [Online]. Available: https://docs.google.com/document/d/1cXfGVZJJHmiD-s3QTlVZrT4zWpDMAaPyNNNEUNylr_c/edit#heading=h.catckqbp3e8n. [Accessed: 30-Sep-2022].