# 5.- Creación y ejecución de contenedores Docker.

# Caso práctico

Jonny Goldstein (CC BY)

Juan y Eva habían estado trabajando intensamente para familiarizarse con Docker. Habían aprendido a buscar y descargar imágenes desde Docker Hub y estaban cada vez más cómodos con el concepto de capas que conforman las imágenes de Docker. Ahora se sentían preparados para el siguiente paso: crear y ejecutar contenedores para diversos propósitos.

En la empresa en la que trabajan, la necesidad de crear y gestionar contenedores había aumentado. Los equipos de desarrollo estaban creando aplicaciones más complejas y necesitaban ambientes aislados y reproducibles para pruebas. Además, la empresa había comenzado a explorar la implementación de microservicios, lo que aumentaba aún más la necesidad de contenedores.

Juan se centró en crear contenedores para aplicaciones web. Empezó con imágenes de Nginx y Apache, creando contenedores con configuraciones personalizadas y archivos de sitio web específicos.

Por su parte, Eva se concentró en los contenedores de bases de datos. Experimentó con MySQL, PostgreSQL y MongoDB, aprendiendo a configurar correctamente los contenedores y a administrar los datos.

Con cada contenedor que creaban, Juan y Eva aprendían más sobre Docker y su utilidad. Descubrieron que la creación y gestión de contenedores era una tarea compleja, pero gratificante, que les permitía no solo mejorar su propia eficiencia, sino también la de toda la empresa.

Una vez hemos cubierto conceptos básicos y aprendido a buscar y descargar imágenes de Docker Hub. Ahora, nuestro enfoque se centrará en la creación y construcción de contenedores Docker, y gradualmente aumentaremos la complejidad de nuestros ejercicios.

Anteriormente vimos lo más básico, aprendiendo a crear y ejecutar contenedores simples utilizando imágenes predeterminadas. Ahora, iremos agregando capas de complejidad a medida que aprendamos a personalizar nuestros contenedores, montando volúmenes y exponiendo puertos. De este modo obtendrás una comprensión sólida y práctica de Docker.

#### Ejemplo 1. Creación de un contendedor con Apache y PHP (en segundo plano)

Para este ejemplo vamos a utilizar la imagen oficial php:8.1.19-apache. Esta imagen viene configurada para servir el contenido que se encuentre dentro del directorio /var/www/html del contenedor

## Paso 1. Creamos una carpeta para nuestro proyecto

Creamos y navegamos hacia la carpeta de nuestro proyecto.

Manuel J. Rodríguez. Navegación al proyecto (Dominio público)

## Paso 2. Arrancamos nuestro contenedor

Ejecutamos el siguiente comando en nuestra terminal:

    docker run -d \
    --rm \
    --name apache_php \
    -p 8080:80 \
    -v "$PWD":/var/www/html \
    php:8.1.19-apache

A continuación se detalla lo que realiza cada parte del comando que acabamos de ejecutar:

- docker run: Este es el comando básico para iniciar un nuevo contenedor Docker.
- -d: Esta opción hace que el contenedor se ejecute en modo "detach" o "background", lo que significa que el contenedor se ejecutará en segundo plano y no ocupará la terminal desde la que se inició.
- --rm: Con esta opción, Docker eliminará automáticamente el contenedor cuando se detenga. Esto es útil para mantener limpio el sistema, especialmente cuando se crean y detienen contenedores con frecuencia.
- --name apache_php: Esta opción asigna un nombre personalizado al contenedor. En este caso, el contenedor se llamará "apache_php". Si no se especifica un nombre, Docker generará uno aleatorio.
- -p 8080:80: Esta opción asigna el puerto 8080 del host al puerto 80 del contenedor. Cualquier tráfico que llegue al puerto 8080 del host se reenviará al puerto 80 del contenedor.
- -v "$PWD":/var/www/html: Esta opción monta el directorio actual ($PWD) del host en la ruta /var/www/html dentro del contenedor. Esto es útil para el desarrollo, ya que cualquier cambio que hagas en el directorio local se reflejará inmediatamente dentro del contenedor.
- php:8.1.19-apache: Esta es la imagen que Docker usará para crear el contenedor. En este caso, se trata de la imagen de PHP con Apache incluido, con la versión especificada (8.1.19).

Manuel J. Rodríguez (Elaboración propia). Docker run (Dominio público)

## Paso 3. Añadimos contenido

Creamos un archivo info.php en nuestro directorio de trabajo actual con el siguiente contenido:

    <?php
    phpinfo();
    ?>

Manuel J. Rodríguez (Elaboración propia). Creación info.php (Dominio público)

## Paso 4. Comprobación de funcionamiento

Podemos conectarnos a un terminal del contenedor para comprobar que el volumen se ha montado correctamente:

    docker exec -it apache_php /bin/bash

Y también podemos abrir un navegador y acceder a la URL http://localhost:8080/info.php o si usas un equipo remoto como es el caso del ejemplo http://ip_remota:8080/info.php.

Tambien se puede hacer la comprobación desde línea de comando con curl

Manuel J. Rodríguez (Elaboración propia). Docker exec (Dominio público)
Manuel J. Rodríguez (Elaboración propia). Comprobación web (Dominio público)

#### Ejemplo 2. Creación de un contenedor con MySQL sin persistencia de datos (en segundo plano)

Para este ejemplo vamos a utilizar la imagen oficial mysql/mysql-server:8.0.

## Paso 1. Arracamos nuestro contenedor

    docker run -d \
    --rm \
    --name mysql-container \
    -e MYSQL_ROOT_PASSWORD=root \
    -p 3306:3306 \
    mysql/mysql-server:8.0

Manuel J. Rodríguez. Arranque de mysql (Dominio público)

A continuación se detalla lo que realiza cada parte del comando que acabamos de ejecutar. Este comando tiene varias opciones, cada una de las cuales juega un papel específico:

- docker run: Este es el comando principal que se utiliza para crear y ejecutar un nuevo contenedor Docker.
- -d: Esta opción hace que el contenedor se ejecute en segundo plano, lo que significa que no ocupará la terminal desde la que se ejecutó el comando.
- --rm: Esta opción hará que Docker elimine automáticamente el contenedor cuando se detenga. Esto es útil para mantener limpio tu entorno de Docker, ya que los contenedores detenidos pueden ocupar espacio en disco.
- --name mysql-container: Esta opción asigna un nombre al contenedor que se va a crear. En este caso, el nombre del contenedor será mysql-container. Esto puede ser útil para identificar y administrar el contenedor más tarde.
- -e MYSQL_ROOT_PASSWORD=root: Esta opción establece una variable de entorno dentro del contenedor. En este caso, está estableciendo la contraseña del usuario root de MySQL en root.
- -p 3306:3306: Esta opción mapea el puerto 3306 del contenedor al puerto 3306 del host. Esto significa que puedes acceder al servicio MySQL en el contenedor a través del puerto 3306 en tu máquina host.
- mysql/mysql-server:8.0: Esta es la imagen que se utilizará para crear el contenedor. En este caso, es la versión 8.0 de la imagen oficial de MySQL Server alojada en Docker Hub.

## Paso 2. Abrimos una terminal en el contenedor para interaccionar con él.

Ejecutamos el siguiente comando en nuestra terminal:

    docker exec -it mysql-container /bin/bash

Una vez dentro podemos conectarnos mediante la consola a la administración del servidor de bases de datos.
Manuel J. Rodríguez (Elaboración propia). Interacción contenedor (Dominio público)

## Paso 3. Creamos una base de datos nueva

Usaremos el contenido de este fichero tienda.sql (sql - 1,59 KB):

Manuel J. Rodríguez (Elaboración propia). Creación BBDD (Dominio público)

## Paso 4. Comprobación de que las tablas existen y contienen datos

Veamos que la creación e importación de datos se ha realizado correctamente:

Manuel J. Rodríguez. Comprobación de datos (Dominio público)
IMPORTANTE: Una vez que hemos llegado a este punto tendríamos la base de datos almacenada dentro del sistema de archivos del contenedor, de modo que si eliminamos el contenedor y volvemos a crear uno nuevo con el mismo comando, no tendríamos acceso a la base de datos. Esto es debido a que nuestro contenedor no tiene establecida una persistencia de datos como veremos en ejemplos posteriores.

# Reflexiona

Cuando comenzamos a trabajar con contenedores Docker, rápidamente nos damos cuenta de que estos son extremadamente efímeros y aislados por naturaleza. Si bien esto es excelente para garantizar la consistencia y la portabilidad de nuestras aplicaciones, también plantea dos desafíos principales: ¿cómo hacemos que los contenedores se comuniquen entre sí y cómo conservamos los datos generados por nuestros contenedores una vez que se detienen?

# Retroalimentación

En cuanto a la comunicación entre contenedores, es importante recordar que cada contenedor se ejecuta en su propio entorno aislado. Esto significa que, de forma predeterminada, un contenedor no puede interactuar con otros contenedores o con el sistema host, a menos que explícitamente le permitamos hacerlo. Aquí es donde entran en juego las redes de Docker, que nos permiten definir cómo y cuándo los contenedores pueden comunicarse entre sí.

Por otro lado, la efimeridad de los contenedores plantea un desafío con respecto a la persistencia de datos. De forma predeterminada, todos los datos generados por un contenedor se almacenan en su sistema de archivos, que se destruye cuando se detiene el contenedor. Esto significa que cualquier cambio en los datos de una aplicación, como las actualizaciones de la base de datos o los archivos de configuración modificados, se perderán cuando se detenga el contenedor. Aquí es donde entran en juego las opciones de almacenamiento de Docker, que nos permiten persistir los datos más allá del ciclo de vida del contenedor.

En definitiva, para construir aplicaciones robustas y resilientes con Docker, debemos aprender a manejar tanto las redes como el almacenamiento. Ambas son herramientas esenciales en nuestra caja de herramientas de Docker, y nos permitirán llevar nuestras aplicaciones al siguiente nivel de funcionalidad y fiabilidad.

# Autoevaluación

# Pregunta

El siguiente comando está mal escrito: docker run -d --rm --name --e MYSQL_ROOT_PASSWORD=root -p 3306:3306 mysql/mysql-server:8.0

¿Sabrías indicar cual de las opciones sería la correcta para que funcionase?

# Respuestas

Opción 1

docker run -d --rm --name mysql-container -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 mysql/mysql-server:8.0

Opción 2

docker run -d --rm --name --e MYSQL_ROOT_PASSWORD=root -p 3306:3306 --name mysql-container mysql/mysql-server:8.0

Opción 3

docker run -d --rm --name -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 --name mysql-container mysql/mysql-server:8.0

Opción 4

docker run -d --rm --name MYSQL_ROOT_PASSWORD=root -p 3306:3306 mysql/mysql-server:8.0

# Retroalimentación

El problema con el comando erróneo es que después de --name no se especificó ningún nombre para el contenedor. En Docker, el flag --name debe ser seguido por el nombre del contenedor. En las opciones B y C, se ha agregado --name mysql-container después de todos los otros flags y argumentos, lo que no es correcto, ya que --name siempre debe ser seguido directamente por el nombre del contenedor. En la opción D, se ha eliminado --name por completo, lo que significa que Docker asignará un nombre aleatorio al contenedor, pero esto no corrige el comando original que especificaba un nombre de contenedor.

Incorrecto

Incorrecto

Incorrecto

# Solución

1. Opción correcta (Retroalimentación)
2. Incorrecto (Retroalimentación)
3. Incorrecto (Retroalimentación)
4. Incorrecto (Retroalimentación)

Creado con eXeLearning (Ventana nueva)