En el anterior post sobre Docker, vimos qué es, qué papel cumple y un poco su historia. Ahora en este post podemos dar el siguiente paso y empezar a lanzar nuestros primeros contenedores.

Importante Docker 101

Este post forma parte de una serie de publicaciones formativas respecto a Docker, echa un ojo al resto aquí:

Docker 101
Como la mayoría de aplicaciones que cubrimos en los vídeos y posts funcionan en contenedores Docker, he decidido hacer una serie de publicaciones enseñando lo que sé sobre Docker de forma instructiva, para que aprendáis lo que es, cómo funciona y a utlizar esta herramienta tan comoda. A continuación os

Requisitos

Para seguir cómodamente este post, recomiendo lo siguiente:

ℹ️
Durante este post verás otros comandos de docker (como docker container ls, o docker stop) que serán explicados en futuros posts, pero son necesarios para poder ejecutar el ejemplo de este post.

No son necesarios conocerlos en profundidad, pero como acabo de indicar, no tienes por qué preocuparte que los veremos más en detalle en el siguiente Docker 101.

¿Qué es un contenedor?

Por ampliar un poco más lo que hemos aprendido hasta ahora, veremos algo más en detalle lo que es un contenedor en si.

Se trata de un proceso aislado para cada uno de los componentes de una aplicación. Por ejemplo: Si tenemos una aplicación web, podríamos tener un contenedor por cada uno de estos elementos:

  • Front con React.
  • Back con Java.
  • Base de datos con PostgreSQL.
  • Caché con REDIS.
  • Sistema de colas con Kafka.

Estos recursos estarían individualmente aislados en sus respectivos contenedores, de forma que podamos gestionarlos de forma independiente, sin afectar a nivel de dependencias al resto de contenedores.

Esto facilita mucho los despliegues y la gestión de aplicaciones, con una mayor comodidad de actualización, seguridad y control.

Y sin contar con que al funcionar sobre Docker, como hablamos en el post anterior, no dependeremos de un sistema operativo anfitrión concreto, y consumiremos muchos menos recursos que con máquinas virtuales tradicionales.

Lanzar un contenedor

Para ello, haremos uso de uno de los comandos más básicos: docker run.

Si habéis seguido la guía de instalación que os recomiendo del punto anterior, ya habréis lanzado uno de prueba, el clásico Hello World de Docker, pero ese comando es demasiado simple para servir de ejemplo real, así que haré uso de una de las aplicaciones que ya tenemos cubiertas en este blog: IT Tools.

Ejemplo de docker run

Os dejo el comando que deberíamos ejecutar para desplegar esta aplicación, y luego veremos más en detalle los diferentes parámetros que se han usado:

sudo docker run -d --name it-tools --restart unless-stopped -p 8080:80 corentinth/it-tools:latest

Si lo lanzamos tal cual, nos saldrá lo siguiente en nuestra terminal:

Podemos ver que está activo con este comando (que lo veremos más adelante con más detalle junto a otros comandos de utilidad):

sudo docker container ls -a

Obtendremos esta salida en pantalla:

Y si accedemos a la URL correspondiente, veremos que IT Tools está lanzado sin problemas.

Vamos a parar nuestro contenedor con otro comando de utilidad, stop, junto al comando rm para eliminarlo. Ambos los detallaremos en el próximo post, pero que por ahora nos basta con poder ejecutarlos:

sudo docker container stop it-tools
sudo docker container rm it-tools

Lo comprobamos ejecutando nuevamente:

sudo docker container ls -a

Y veremos que no hay rastro, ya que se ha eliminado.

Parámetros del ejemplo

Ahora, si nos fijamos en el comando en sí, veremos que es algo extenso y tiene unos cuantos parámetros:

  • -d
  • --name it-tools
  • --restart unless-stopped
  • -p 8080:80
  • corentinth/it-tools:latest
ℹ️
Adicionalmente veremos el comando --rm.

Así que vamos a ir viendo uno a uno qué son y para qué sirven, y así hacernos una idea general del funcionamiento del comando docker run.

Parámetro --rm

Aunque no sale en el comando inicial debido a incompatibilidad con --restartsu funcionalidad es muy sencilla: Elimina el contenedor automáticamente si este es parado.

Viene de remove, como se puede intuir, y resulta muy práctico para las pruebas, pero no es habitual ejecutarlo en las aplicaciones.

Lo verás en próximos ejemplos ya que es muy conveniente para poder mostrar y ejecutar cómodamente las diferentes versiones del comando docker run a lo largo de este post.

Ejemplo parámetro --rm

Ejecutamos lo siguiente:

sudo docker run --rm -d --name it-tools-rm corentinth/it-tools:latest

Veremos que se nos da un output por pantalla:

Si ahora revisamos los contenedores que tenemos activos:

sudo docker container ls

Tendremos listado nuestro contenedor, funcionando:

Si ahora lo mandamos parar:

sudo docker container stop it-tools-rm

Veremos que el contenedor se para, y podremos comprobar que el contenedor se ha eliminado sin necesidad del docker container rm:

docker container ls -a

No deberíamos obtener el contenedor.

Imagen corentinth/it-tools:latest

Dentro de toda la parametría que se emplea en el comando, la imagen es diría que la más importante, ya que sin esto, no tenemos referencia de qué queremos lanzar, ya que es la manera que tenemos de indicar qué aplicación queremos desplegar en nuestro contenedor.

En este caso, estamos desplegando corentinth/it-tools:latest. Para entenderlo mejor, vamos a dividir sus partes:

  • corentinth: Autor de la imagen.
  • it-tools: Nombre de la imagen.
  • latest: Versión de la imagen.

Siempre lo veremos de esa misma manera: autor/imagen:version.

Estas imágenes son alojadas en repositorios dedicados, como puede ser Docker Hub, aunque hay de otros proveedores, este es de los más extendidos.

Ejemplo de imagen

Para este caso, con la imagen de ejemplo, tenemos lo mínimo indispensable para lanzar el contenedor. Esto no significa ni garantiza que esté lo que se necesita realmente para que nuestra aplicación funcione adecuadamente, pero Docker es capaz de lanzarlo salvo requerimientos de la propia imagen.

sudo docker container run --rm corentinth/it-tools:latest

Veremos que se lanza:

Y que al pulsar CTRL + C el contenedor se para y se elimina, pudiendo comprobarlo mediante:

sudo docker container ls -a

Ejemplo diferentes imágenes

Podemos desplegar una imagen concreta, ya que la latest es asignada por el autor a la versión (usualmente LTS) que considera como estable o última.

En este caso, podríamos elegir desplegar la versión nightly, y para ello ejecutaríamos:

sudo docker container run --rm -d corentinth/it-tools:nightly

Veremos que se lanza, y que ha descargado una nueva imagen:

Ahora si lo listamos, veremos que aparece en ejecución:

sudo docker container ls -a

Si ahora lo paramos mediante este comando, poniendo el nombre del contenedor del listado anterior (recuerda cambiarlo por el que te corresponda):

sudo docker container stop practical_boyd

Veremos que se ha parado y eliminado, listando nuevamente los contenedores:

sudo docker container ls -a

Parámetro -d

Es una abreviatura de detached, y se emplea para indicara a nuestro contenedor que queremos que se ejecute en background.

Es uno de los que más utilizaremos, ya que sirve para dejar una aplicación activa, independientemente de nuestra sesión de terminal, como si de un servicio se tratase, en combinación con otros parámetros como el --restart que veremos más adelante.

Ejemplo parámetro -d

Entonces, aislándolo para este caso, podríamos lanzar por ejemplo:

sudo docker run --rm -d corentinth/it-tools:latest

Veremos que el contenedor se lanza, volviendo a ejecutar lo siguiente:

sudo docker container ls -a

Procedemos a pararlo, y por tanto, al haber indicado -rm, eliminarlo. El nombre deberemos obtenerlo del listado del comando anterior, bajo la columna name:

sudo docker container stop confident_northcutt

Parámetro --name

Bastante auto explicativo. Sirve, como se puede intuir, para asignar el nombre a nuestro contenedor, en este caso it-tools.

Este nombre nos sirve para facilitar el uso de otros comandos de utilidad que veremos en el próximo post y vídeo, como para parar el contenedor, reiniciarlo, lanzarlo nuevamente o revisar sus logs.

También nos permite identificar rápidamente nuestro despliegue sin necesidad de memorizar su ID, ya que este ID es aleatorio.

ℹ️
En caso de no especificarle un nombre, se le asignará uno automáticamente, siguiendo una nomenclatura snake_case.

Ejemplo parámetro --name

Como hemos podido comprobar, si ejecutamos lo siguiente:

sudo docker container run --rm -d --name it-tools corentinth/it-tools:latest

Se nos lanzará el contenedor, que podremos ver ejecutando:

sudo docker container ls -a

Ahora, a diferencia del apartado anterior, podremos pararlo indicando el nombre que le hemos asignado nosotros mismos, y que adicionalmente se elimine ya que lo hemos lanzado como ejemplo:

sudo docker container stop it-tools

Y veremos que si listamos nuevamente, no sale dentro de los contenedores que tenemos:

sudo docker container ls -a

Parámetro --restart

Nos va a permitir configurar la política de reinicio de nuestro contenedor. Esta política es lo que se le indica justo tras el parámetro, siendo en este caso unless-stopped.

Hay otras políticas diferentes, que podemos elegir indicando solo una de ellas después del --restart:

Política Descripción
no El contenedor no se reiniciará automáticamente en ningún caso. Es la opción por defecto en caso de no indicar un parámetro --restart.
on-failure[:max-retries] El contenedor se reiniciará si se ha finalizado con algún código de error. Adicionalmente se le puede indicar un número máximo de reintentos como on-failure:3. Si el servidor en sí se reinicia, el contenedor no se reiniciará.
always El contenedor se reinicia en cualquiera de estas circunstancias. Si lo paramos manualmente y reiniciamos el servicio de Docker (o el servidor de Docker en si) el contenedor se volverá a lanzar.
unless-stopped Similar al always, exceptuando que si el contenedor es parado manualmente, no se reiniciará hasta que lo lances nuevamente.

Esto nos viene genial para poder configurar nuestros contenedores para que se reinicien en función de nuestras necesidades, llegando a actuar como si de servicios nativos de Unix se trataran.

Ejemplo parámetro restart unless-stopped

Siguiendo con el ejemplo anterior, ejecutamos:

sudo docker run -d --name it-tools --restart unless-stopped -p 8080:80 corentinth/it-tools:latest

Comprobamos que se ha lanzado mediante:

sudo docker container ls -a

Ahora lo paramos:

sudo docker stop it-tools

Vemos que ha parado:

sudo docker container ls -a

Reiniciamos el servicio de Docker:

sudo service docker restart

Esperamos unos segundos a se haga efectivo el reinicio anterior, y ejecutamos:

sudo docker container ls -a

Podremos apreciar que nuestro contenedor NO se ha reiniciado automáticamente:

Eliminamos nuestro contenedor para dejar el entorno limpio:

sudo docker container rm it-tools

Ejemplo parámetro --restart always

Con esta flag, como se indica en la tabla anterior, nuestro contenedor debería reiniciarse en cualquier circunstancia. Para comprobarlo lanzamos lo siguiente:

sudo docker run -d --name it-tools-restart --restart always corentinth/it-tools:latest

Como con cada paso, comprobamos la ejecución del contenedor:

sudo docker container ls -a

Lo paramos haciendo uso de este comando:

sudo docker stop it-tools-restart

Y comprobamos nuevamente su estado, verificando que se ha parado:

sudo docker container ls -a

Si ahora reiniciamos nuestro servicio de Docker:

sudo service docker restart

Y como antes esperamos a que termine de reiniciarse, y luego listamos nuestros contenedores:

sudo docker container ls -a

Podremos apreciar que nuestro contenedor esta ves SI se ha reiniciado automáticamente:

Lo eliminamos para dejar el entorno limpio:

sudo docker container stop it-tools-restart
sudo docker container rm it-tools-restart

Parámetro -p

Este viene de abreviar el término ports, y es con el que indicaremos el mapeo de puertos que deseamos para nuestro contenedor.

En el ejemplo dado de it-tools estamos señalando que el puerto 8080 de nuestro anfitrión tiene una conexión con el puerto 80 de nuestro contenedor. Están siendo mapeados.

Siempre se sigue el mismo orden, siendo anfitrión:contenedor.

Ejemplo parámetro -p multi puerto

Si tuviéramos que indicar múltiples puertos, tendríamos que concatenar varios comandos -p, por ejemplo:

docker run -d --name it-tools-multiport -p 8080:80 -p 8443:443 corentinth/it-tools:latest

Si ahora ejecutamos lo siguiente:

docker container ls -a

Veremos que nuestro contenedor ahora nos indica que tiene varios puertos abiertos:

Paramos y eliminamos este contenedor:

sudo docker container stop it-tools-multiport
sudo docker container rm it-tools-multiport

Otras configuraciones de puertos

Adicionalmente, podemos indicar IPs concretas de anfitrión, que nos viene genial en caso de tener múltiples interfaces en nuestro servidor; y también los protocolos (TCP/UDP). Por ejemplo (probablemente no te funcione ya que dependes de tener esas mismas IPs):

docker run -d --name it-tools-multiport -p 192.168.10.5:8080:80 -p 192.168.20:5:8443:443 corentinth/it-tools:latest

Con este comando le estaremos indicando lo siguiente:

  • El puerto 80 de nuestro contenedor es accesible desde el puerto 8080 de la IP 192.168.10.5 de nuestro anfitrión.
  • El puerto 443 de nuestro contenedor es accesible desde el puerto 8443 de la IP 192.168.20.5 de nuestro anfitrión.

Referencias

Lista de documentación, vídeos, cursos y referencias utilizadas:

Vídeo