Docker Engine y Docker Desktop

Docker Desktop es una aplicación de escritorio que incluye Docker Engine y herramientas adicionales como una interfaz gráfica, la opción de desplegar Kubernetes, plugins, entre otras funciones, como espacios de trabajo colaborativos y más espacios privados en Docker Hub, entre otros.
Es gratuita para empresas con menos de 250 empleados y menos de 10 millones de dólares de facturación anual.

Docker Engine es el componente central de Docker, concretamente el software que permite crear y ejecutar contenedores. Docker Engine es totalmente gratuito y no tiene restricciones de uso.
Solo se puede instalar en sistemas Linux y se utiliza a través de la línea de comandos (CLI).

Lo más habitual es usar Docker Desktop en entornos de desarrollo, y Docker Engine directamente en servidores de desarrollo o producción. Su principal ventaja es que el rendimiento es nativo, lo que lo hace mucho mas limpio y eficiente.

Ya hemos hablado sobre la instalación de Docker en un post anterior.

Para instalar Docker Desktop, simplemente visitamos la página web oficial, descargamos el instalador, seguimos los pasos (“siguiente, siguiente, siguiente”) ¡y listo! No tiene mayor complicación.
https://www.docker.com/products/docker-desktop/

Para la instalación de Docker Engine en Linux nos vamos a la pagina web oficial.
Por ejemplo nos vamos a las opcion de Ubuntu
https://docs.docker.com/engine/install/ubuntu/
Y bajamos hasta la seccion que dice
Install using the apt repository
Y seguimos las instrucciones
Comprobamos la version.

docker --version
docker compose version

Repasa algunos de los conceptos mas importantes en el siguiente link
https://richardaguirre.cloud/un-poco-de-docker/

Algunos parámetros:
docker run nombre_de_la_imagen
docker run nginx
Al ejecutar docker run nginx lo primero que hace es verificar si la imagen existe en local, si no existe, hace un pull de la imagen y la descarga.
docker run implica hacer un docker pull, descarga la imagen y automáticamente ejecuta la imagen de nginx.
Nota: con ese comando el servidor web se queda escuchando indefinidamente y nos coloca el proceso principal del contenedor. Para salir o hacer un kill presionamos Ctrl + C y matamos el proceso.
En ese momento el contenedor se detiene.
Si hacemos un docker ps no nos aparecerá listado, pero no eliminado.
Lo podemos comprobar con docker ps -a.

Opciones mas comunes en el arranque de Docker:
-d Arranca el contenedor en segundo plano.
-p Mapea un puerto del contenedor al puerto del host.
-v Mapea un volumen del host al contenedor.
–name Asigna un nombre al contenedor
-rm Elimina el contenedor al pararlo.
-e Define una variable de entorno.
–env-file Define un archivo de variables de entorno.

Ejemplos:
docker run -d nginx
Este comando ejecuta un contenedor con la imagen de nginx en modo detach (-d), es decir, en segundo plano, sin quedar asociado al terminal.
El modo “detach” permite que el contenedor se ejecute en segundo plano, lo que te permite seguir utilizando la terminal para otros comandos mientras el contenedor sigue activo.

Luego nos muestra un hash completo del contenedor, y si hacemos un docker ps, podemos ver que el hash es una parte del Id del contenedor y podemos ver el estado de ejecución.

Para saber qué está pasando dentro del contenedor, podemos usar el comando docker logs junto con el ID del contenedor:
docker logs a12233ffjj22
Este comando muestra los logs de salida estándar de ese contenedor específico, hasta el momento en que se ejecuta el comando.

Si queremos ver los logs en tiempo real, agregamos el parámetro -f (follow):
docker logs -f a12233ffjj22
Esto permite ver los logs en vivo, sin necesidad de interactuar con el contenedor.

También podríamos usar el comando attach para conectarnos directamente a la terminal del contenedor:
docker attach a12233ffjj22
Sin embargo, al usar attach, no veremos el historial de logs como con logs -f, pero podremos interactuar con el contenedor si está configurado para aceptar entrada.

En resumen, un contenedor no es más que un proceso en el que se ejecuta una aplicación. En este caso, por ejemplo, el servidor web Nginx, pero también podría ser una aplicación en Node.js o cualquier otra que se pueda ejecutar en un entorno Unix.
Los contenedores pueden ser detenidos, iniciados, gestionados, monitoreados, e incluso se puede interactuar con ellos, de forma muy similar a como se gestionan procesos en Unix, pero todo está empaquetado en contenedores.

La idea principal es poder lanzar una aplicación de forma rápida y sencilla, sin necesidad de instalar manualmente dependencias con comandos como apt install nginx, ni realizar configuraciones complejas.
Todo viene preconfigurado dentro de una imagen, se lanza un contenedor a partir de ella, ¡y listo! La aplicación ya está funcionando.

Ahora, ¿Qué pasaría si este contenedor falla?
¡Puede reiniciarse o relanzarse automáticamente?
Si se puede, se hace con las políticas de reinicio.
Estas se definen en el comando –restart y tiene varios parámetros:
no: No reinicia el contenedor.
always: Reinicia el contenedor siempre.
unless-stopped: Reinicia el contenedor siempre que se detenga.
on-failure: Reinicia el contenedor solo si falla.
on-failure:<n> Reinicia el contenedor solo si falla n veces.

Las mas usadas son always y unless-stopped

Como usarlos:
docker run -d –restart=always nginx
Si reiniciamos el equipo donde estamos o si fuera un servidor, automáticamente docker ejecutaría todos los contenedores que estuvieran con esta política. Es muy útil activar estas políticas en los servidores.

Mapeo de Puertos:
Los servidores web (que representan la mayoría de los servicios que ejecutamos en contenedores) necesitan, por defecto, un puerto para comunicarse con los clientes y, por ejemplo, compartir información.

El mapeo de puertos permite que un puerto de nuestro equipo anfitrión (host) redirija el tráfico hacia un puerto específico dentro del contenedor, funcionando como un tipo de NAT (Network Address Translation).

En el ejemplo que venimos utilizando, Nginx escucha por defecto en el puerto 80 dentro del contenedor.

Con el siguiente comando, podemos hacer el mapeo:
docker run -d -p puerto_local:puerto_contenedor nginx
Por ejemplo, si queremos acceder al servidor Nginx a través del puerto 8080 en nuestro equipo, y que este se redirija al puerto 80 dentro del contenedor, usaríamos:

docker run -d -p 8080:80 nginx

Esto permite acceder al servidor web ejecutado dentro del contenedor simplemente visitando http://localhost:8080 desde el navegador.

¿Y si necesitamos múltiples puertos o rangos completos?
Podemos hacerlo de la siguiente forma:
docker run -d -p 8080:80 -p 8081:81 nginx
Podemos usar el parámetro -p tantas veces como puertos necesitemos mapear.

Si queremos mapear un rango de puertos, también es posible. Por ejemplo:
docker run -d -p 8080-8090:80-90 nginx
En este caso, estamos mapeando el rango de puertos 8080 a 8090 en el host hacia el rango 80 a 90 en el contenedor, haciendo coincidir cada puerto uno a uno.

Es importante destacar que no tendría mucho sentido redirigir un rango grande de puertos del host hacia un único puerto del contenedor, por ejemplo:
docker run -d -p 8080-9000:80 nginx
Esto no es válido, ya que no se puede mapear múltiples puertos del host hacia un solo puerto del contenedor. El mapeo debe ser uno a uno si usamos rangos, tanto en el host como en el contenedor.

Gestión de Contenedores
¿Como podemos hacer para meternos dentro del contenedor de Docker? ¿Es posible?
Pos sí. El comando docker exec se usa para ejecutar comandos dentro de un contenedor que ya está en ejecución.
Su sintaxis:
docker exec [opciones]

docker exec a12233ffjj22 ls
Este nos mostraría el contenido de la raíz de un UNIX (/boot, /bin, /var, etc).
Y mostraría el archivo docker-entrypoint.sh que suele ser un script de shell que actúa como punto de entrada (entrypoint) para el contenedor y se ejecuta automáticamente cuando el contenedor se inicia, antes del comando principal que se especifique (por ejemplo, nginx, node, mysqld, etc.).

Si nos hemos percatado de algo importante, al ejecutar docker image ls veremos que la imagen de Nginx pesa aproximadamente 50 MB.
Esto contrasta fuertemente con un servidor tradicional, donde el mismo servicio podría ocupar entre 3 y 4 GB, considerando el sistema operativo, dependencias y configuraciones adicionales.

Si queremos abrir una terminal en el servidor dentro del contenedor, simplemente usamos el comando
docker exec -it a12233ffjj22 bash -> la i es de interactivo y la t de terminal. Y el bash depende de la distribucion. Podria ser sh o zsh u otros interpretes de comandos.
Esto permite abrir un terminal interactivo con el servidor.
Si hacemos un ls podriamos ver el directorio docker-entrypoint.d y dentro ver todos los .sh que utiliza para poner en marcha el servicio y tambien podemos explorar el sistema de archivos libremente.
Para salir escribimos exit -> enter. Y volvemos a nuestro terminal.

¿Como le damos un nombre personalizado a un contenedor?
Lo hacemos con el comando.
docker run –name mi_contenedor nginx
docker run –name web1 -p 8081:81 nginx

Docker suele asignar un nombre aleatorio a los contenedores si no se lo declaramos explictamente con el parametro –name
Para esto se debe tener algunas consideraciones:
El nombre no debe existir, debe ser único. Si ya existe docker mostrará error.
Usa solo letras, números, guiones (-) y guiones bajos (_).
No uses espacios, acentos ni símbolos especiales.
Usa nombres cortos y descriptivos. webserver, nginx_frontend, db_mysql, api-backend ayudan a identificar el propósito del contenedor fácilmente. Evita los nombres genericos.

Esto facilita tareas como:
Verificar su estado con docker ps
Ver logs: docker logs mi_contenedor
Ejecutar comandos dentro del contenedor: docker exec -it mi_contenedor bash
Detener, iniciarlo o eliminarlo fácilmente: docker stop mi_contenedor, docker rm mi_contenedor

También, ten en cuenta los puertos que ya estén asignados a otro contenedor, ya que tampoco podrás asignar el mismo puerto a dos contenedores.
Y aunque hagamos el docker ps y no nos muestre el contenedor, este sigue allí, hasta que no lo borremos.

Si bien, ejecutamos el comando docker run –name web1 -p 8081:81 nginx, y tengamos un error en pantalla y el puerto estaba ocupado, el contenedor se va a crear igualmente. Y aunque el contenedor no está en ejecución, está allí, creado y definido. Deberás eliminarlo con el comando docker rm web1 si queremos volver a recrearlo en otro puerto.
Aquí es donde es útil que tengamos el nombre definido del contenedor para no tener que buscar su hash que es mucho mas largo.

Podríamos probar lanzando 100 contenedores, cada uno con su nombre único y cada uno con su puerto.

docker run –name web1 -p 8081:81 nginx
docker run –name web2 -p 8082:82 nginx
docker run –name web3 -p 8083:83 nginx

….

docker run –name web1 -p 9091:11 nginx

Tendríamos muy fácilmente 100 servidores webs corriendo al mismo tiempo y todos ellos responden independientemente en puertos distintos.
Este es el poder de Docker. La facilidad de lanzar cientos u incluso miles de contenedores.

Pasando al tema de borrado de contendedores. Podemos forzar el borrado con el comando:
docker rm -f web1
Y el comando docker container prune lo que hace es borrar todos los contenedores que estén en stop. Requiere confirmación en consola.

Hasta aquí el resumen. Continuaremos en otra ocasión con mas de Docker.

Agregar un comentario

Tu dirección de correo electrónico no será publicada. Los campos requeridos están marcados *