Saltar al contenido principal

Introducción a Docker

Documento escrito por: Fernando Lucendo García

Puedes ver todos los documentos de este autor aquí.

¿Qué es Docker?

Docker es un software que permite la virtualización a nivel de sistema operativo, a diferencia de otros programs de virtualizaciones tiene una gran ventaja y es su función de contenedores. Es conveniente que comprendamos cuales son los Fundamentos de Orquestación y Operaciones IT que se realizan en la automatización y a la hora de lanzar servicios IT, para ello puedes visitar el enlace de un artículo anterior sobre estos conceptos aquí.

De esta manera Docker permite aislar en estos contenedores como si fuesen programas independientes dentro del mismo sistema operativo, aislando los recursos a nivel de kernel.

Usando:

  • cgroups
  • namespaces

Así pues, desde el propio sistema anfitrión se podrán acceder a los ficheros del sistema virtualizado pero no se podrán ver los ficheros del anfitrión desde el sistema virtualizado.

Los contenedores compartirán kernel y librerías que consumirán muy pocos recursos del sistema anfitrión.

Los sistemas operativos que se podrán lanzar deben ser Linux.

Este sistema es muy flexible y portable, ya que se podrá migrar fácilmente un sistema previamente configurado a cualquier otra máquina en pocos muy pocos minutos o incluso segundos.

Instalando Docker

  1. Necesitaremos un sistema operativo de 64 bits.
  2. Debemos leer detenidamente los pasos de instalación según nuestra distribución del sistema operativo, ya que cada uno necesitará unos comandos específicos. Puedes consultar la instalación para tu sistema operativo en este enlace.

En mi caso, mi distribución el Kali Linux por lo que debo seguir los pasos de instalación de Docker para una distribución basada en Debian. Para mi distribución los comandos a seguir serán los siguientes:

  1. Actualizamos la lista de paquetes disponibles y sus versiones, pero no instala o actualiza ningún paquete. Esta lista la coge de los servidores con repositorios que tenemos definidos en el sources.list.

    sudo apt update
  2. Instalaremos la aplicación docker.io en el sistema, la opción -y sirve para confirmar la instalación de forma automática.

    sudo apt install -y docker.io
  3. Habilitaremos el proceso docker con esta orden:

    sudo systemctl enable docker --now
  4. Podemos consultar el estado de docker para comprobar su correcta instalación:

    sudo service docker status

    version_docker

  5. Comprobamos la versión instalada de docker en nuestro sistema:

    sudo docker version

    version_docker

Componentes Docker-Engine

Docker-engine es una aplicación basada en la arquitectura cliente-servidor y se compone de:

  • El demonio de Docker, que será el que se ejecuta en 2º plano en nuestro sistema operativo, que ejecutará los contenedores.
  • REST API, que permitirá la comunicación con el demonio de Docker.
  • Interfaz de línea de comandos o CLI donde se ejecutarán los comandos Docker.

Docker registry

Este registro de Docker es un servicio que permitirá almacenar imágenes para poder transformar estas imágenes.

  • El registro puede ser público o privado.
  • El registro oficial de Docker donde se almacenan las imágenes oficiales está aquí.

Imágenes

Una imagen es una plantilla de solo lectura compuesta por un sistema de ficheros y parámetros listos para su ejecución. Estas imágenes están basadas en sistemas operativos Linux.

Una imagen sirve como un sistema operativo con una configuración preestablecida previamente que está lista para su ejecución. La plantilla no se ejecuta, si no que guardará la información del sistema operativo y su configuración, por lo tanto Docker no ejecutará la plantilla, si no que creará una instancia en una máquina virtual.

Gestión de imágenes

Mostrar las imágenes instaladas actualmente en nuestro sistema:

docker images 

Mostrar el historial de cambios realizados en una imagen hasta el estado en el que se encuentra:

docker history id_imagen

Mostrar la descripción detallada de las características de la imagen:

docker inspect id_imagen

Guardar una imagen en nuestro sistema:

docker save tag_imagen

Cargar una imagen en nuestro sistema:

docker load tag_imagen

Borrar una imagen de nuestro sistema:

docker images id_imagen

Contenedores

Un contenedor es una instancia de una imagen. El sistema de ficheros del contenedor se encuentra dentro del propio sistema anfitrión, este sistema es similar a los jail root de Linux, aislando una porción del sistema operativo para la máquina virtual. Estos contenedores son máquinas virtuales que se podrán ejecutar, reiniciar, parar, etc.

Gestión de contenedores

Cuando hay un contenedor activo podemos agregarnos a ese contenedor con:

docker attach

Ejecutamos un comando en un contenedor:

docker exec

Inspeccionar las características detalladas de un contenedor:

docker inspect

Matar un contenedor:

docker kill

Ver el registro de los ficheros log de un contenedor:

docker log

Pausar un contenedor (pausamos la máquina virtual):

docker pause

Continuar un contenedor (continuamos la máquina virtual):

docker unpause

Establecemos un puerto para entrar en un contenedor:

docker port

Ver los contenedores activos en nuestro sistema, es decir, aquellos que estén corriendo:

docker ps

Renombrar un contenedor:

docker rename

Podremos gestionar la máquina virtual, iniciandola, parandola o reiniciandola:

docker start
docker stop
docker restart

Borrar un contenedor

docker rm
Atención

Para poder borrar un contenedor este debe estar parado previamente.

Ejecuta o instancia un contenedor a partir de una imagen, este comando será muy importante.

docker run

Ver el estado del contenedor:

docker stats

Ver la monitorización de un contenedor, su uso, rendimiento, etc.:

docker top

Actualizaremos un contenedor con respecto a su imagen:

docker update

Practicando la gestión de contenedores

Cuando vamos a lanzar una imagen, Docker buscará dicha imagen en nuestro sistema de forma local, al no encontrar la imagen hará un pull a un Docker registry en este caso Docker Hub y descargará la imagen de Ubuntu. Normalmente Ubuntu trabaja con un sistema de ficheros en el que la imagen principal puede considerarse una imagen base, como una primera instantanea del sistema operativo.

Conforme se vayan ejecutando comandos se agregarán capas adicionales sobre esa imagen base,

Corriendo_imagen

Ahora bien, habiendo descargado nuestra primera imagen podremos observar como al ejecutar el siguiente comando sudo docker images aparecerán las imágenes disponibles en nuestro sistema. En mi caso como solo he descargado la de Ubuntu, sólo aparecerá esa.

docker_images

Con esta información podremos consultar el historial de modificaciones realizadas sobre alguna imagen específica:

docker_history

Podemos observar cómo sobre la imágen que hemos descargado de Ubuntu se han añadido algunas modificaciones y ficheros adicionales que quedarán refleados en el historial.

Deberías saber

Cuando se necesita consultar cualquier dato sobre una imágen podemos hacerlo usando su IMAGE ID o su REPOSITORY, y en el caso de usar la primera opción, no es necesario escribir todo el ID completo, basta con introducir los 4 o 5 primeros dígitos de este ID, ya que serán suficientes para diferenciarlos del resto.

También podemos ejecutar el comando docker inspect seguido del ID de la imagen que queremos consultar para poder ver la información detallada de esta imagen.

docker_inspect

Ahora, si queremos eliminar una imagen, debemos borrar previamente los contenedores asociados a esta imagen.

Para poder verlos escribiremos sudo docker ps -a, que nos mostrará todos los contenedores, tanto los activos como los que están parados. docker_ps-a

Una vez tenemos el CONTAINER ID del contenedor que deseamos eliminar podemos hacerlo con el comando sudo docker rm id_contenedor, de igual forma que en casos anteriores, con introducir los primeros 4 o 5 dígitos del ID será suficiente.

borrar_contenedor

Cuando hayamos borrado el contenedor, podremos borrar también la imagen usando el comando sudo docker rmi, en este caso en vez de usar el ID de la imagen he usado la otra opción, el repositorio.

borrar_imagen

Manejo de puertos

En Docker podemos "enlazar los puertos" de nuestra máquina física con el puerto que se especifique en para la máquina virtual de Docker".

Vamos a lanzar una imagen con el parámetro -d para que se quede en 2º plano y en modo escucha y con el parámetro -p o --port, donde indicaremos el puerto donde escuchará en nuestra máquina, y seguidamente el puerto donde se redirigirá en el contenedor. Por último el comando python app.py ejecutará la aplicación web que se abrirá dentro del contenedor de webpapp.

puertos_docker

Una vez hecho esto, podremos comprobar que se ha creado el contenedor y su estado así como los puertos que usará con el comando docker ps -l:

puertos_comprobacion

No obstante, podemos comprobar que lo que hemos hecho esté funcionando correctamente en nuestro sistema, para ello vamos a abrir un navegador web, en mi caso he usado Mozilla Firefox que viene por defecto en ya instalado en Kali Linux y pondremos en la barra de búsqueda: localhost:81.

aplicacion_python

Si queremos ver el registro de la actividad que se ha llevado a cabo en el contenedor podemos consultarlo con el comando docker logs seguido del ID del contenedor.

log_contenedor

Construir imágenes

Para poder construir imágenes propias y añadir funcionalidades o modificaciones a la imágenes existentes necesitaremos realizar los siguientes pasos:

  • Crear y configurar un fichero Dockerfile, donde meteremos a partir de una imagen base, algunos comandos o parámetros que modificarán esta imagen final o el comportamiento de la misma.
  • Cuando ya se ha realizado el Dockerfile, el siguiente paso será construir la imagen con el comando docker build.

Practica sobre las imagenes

Vamos a lanzar una imagen que contiene un un servidor apache y php con una terminal asociada usando el parámetro -t y en formato interactivo con el parámetro -i seguido de /bin/bash para poder usar dicha terminal.

lanzar_apachephp

Podemos consultar los apaquetes que trae instalados nuestra nueva imagen usando el comando dpkg -l y podemos filtrar estos paquetes, buscando aquellos que tengan la palabra Apache:

filtrar_paquetes

Mucho ojo con esto

Si vamos a construir una imagen con Docker a partir de otra imagen, cualquier comando que hayamos introducido después de arrancar el contenedor se introducirá junto con la creación de la imagen, algo que no queremos ya que hará que el proceso de ejecución de la imágen lleve más tiempo. Por lo tanto solo debemos introducir los comandos indispensables, ya que cada comando será una capa adicional.

Si por ejemplo queremos añadir algún paquete adicional a una imagen que hemos obtenido nosotros, podremos encadenar comandos para no acumular más "capas" innecesariamente.

concatenar_comandos

Una vez hayamos realizado todos los cambios necesarios y añadido lo que queramos. Saldremos del contenedor con el comando exit. A continuación podemos observar que el contenedor está en nuestro sistema ejecutando el comando sudo docker ps -l

Este comando nos devolverá un listado de los contenedores del sistema, con lo que obtendremos el ID necesario para el siguiente comando.

Con el comando sudo docker commit -m "Paquete passenger añadido" -a "Fernando Lucendo" 27fcbabfbaa1 falcon/apache-php-pack-passenger:latest.

Confirmaremos los cambios (commit) añadiendo un mensaje, normalmente indicando los cambios realizados, (-m "Mensaje") e indicaremos con el parámetro -a "autor" el autor, seguidamente irá el ID del contenedor, un usuario registrado en Docker Hub y después de la / se indicará el nombre que le pondremos a la imágen creada.

concatenar_comandos

Si hemos confirmado los cambios en la imagen, podrmeos consultar la nueva imagen creada con el comando sudo docker images:

concatenar_comandos

Hecho todo lo anterior, ahora podremos lanzar nuestra propia imagen construida por nosotros mismos con las modificaciones realizadas sobre otra imagen. Para esto usaremos el comando de docker run (con los parámetros que necesitemos, en mi caso pondre -t -i) seguido de el repositorio y el tag.

concatenar_comandos

Recuerda

Para comprobar los cambios realizados sobre una imagen en Docker podemos utilizar el comando sudo docker history id_imagen . Como veremos en la siguiente imagen

historial_imagen

Construir imagen con Dockerfile

Todo lo visto anteriormente es una de las formas de construir una imagen, pero normalmente, lo que se suele hacer es editar el fichero Dockerfile ya que a partir de aquí podremos añadir configuraciones y paquetes adicionales sin necesidad de estar dentro del contenedor.

Primero es recomendable crear un directorio (comando mkdir) donde almacenar este fichero, en mi caso he decidido llamarlo docker-prueba, y después nos situamos en ese directorio (comandocd):

historial_imagen

Lo que buscamos hacer en esta opción es construir una imagen de Docker a través de un fichero Dockerfile, todo lo que hemos hecho en el caso anterior por comandos, pero ahora indicado en el Dockerfile, para ello crearemos un fichero nuevo con nuestro editor de texto favorito en Linux, en mi caso usaré nano:

sudo nano Dockerfile

Ahora podremos añadir las líneas que necesitamos para construir la imagen a partir de este fichero, en mi caso he añadido unos comentarios (#comentario) en el propio fichero que explican que hace cada una de las líneas añadidas.

Cuidado

Es muy importante que a la hora de realizar una imagen a través de un fichero Dockerfile tengamos mucho cuidado con los comandos que metemos, ya que si son comandos interectivos, creación de la imagen se quedará colgada esperando una interacción, como por ejemplo, el uso del comando apt-get install. Cuando usamos este comando la propia terminal nos pide una confirmación para la instalación, este paso lo podemos ahorrar introduciendo el parámetro -y en el propio comando, quedando de la siguiente forma: apt-get install -y.

dockerfile

Cuando hayamos elaborado el fichero Dockerfile lo guardaremos y podremos lanzarlo con el comando:

sudo docker build -t falcon/apache-php-passenger:latest .

El punto al final del comando anterior indica que el Dockerfile se encuentra en el directorio actual donde nosotros nos encontramos.

lanzar_dockerfile

Finalmente si la imagen se lanzo y ejecutó correctamente, podremos visualizarla usando el comando visto en anteriores ocasiones: sudo docker images

comprobar_imagen_dockerfile

Y de igual forma podremos ejecutar un nuevo contenedor con esta imagen como hicimos en el caso anterior, con el comando:

sudo docker run -t -i falcon/apache-php-pack-passenger:latest /bin/bash

DockerHub

Creando una cuenta en Docker Hub podremos subir nuestros propios repositorios la plataforma de Docker.

Los pasos a seguir para realizar esto son:

  1. Tener creada una cuenta en Docker Hub

  2. Para crear un repositorio:

    • Iremos a Create repository.
    • Rellenaremos nuestros datos (nombre, descripción, etc.)
    • Escogeremos la visibilidad. En privada nos permitirá crear un solo repositorio con la cuenta Free.
    • Le daremos a Create.
  3. Para subir la imagen al repositorio:

    • Crear un tag de la imagen.

      sudo docker tag id_imagen tag_imagen
    • Logearnos en Docker Hub a través de la terminal.

      sudo docker login

      Esto nos pedirá el nombre de usuario como Username y la contraseña como Password. Si el logueo se completa correctamente nos devolverá el mensaje Login Succeeded.

    • Subir la imagen.

      sudo docker push nombre_repositorio_imagen

De esta forma habremos subido nuestras imagenes modificadas a nuestro perfil de Docker Hub y si están subidas de forma pública, cualquier persona podría ver, descargar y usar nuestras imágenes en sus contenedores.

Redes en Docker

Al instalar Docker, este creará por defecto 3 redes distintas:

  • Bridge. También conocida como interfaz puente, es la que se establece por defecto.

    Esta red está representada en docker mediante la interfaz docker0. Podemos comprobar cómo se encuentra esta interfaz en nuestro equipo con el comando ifconfig

    docker0

    Sus principales características son:

    • Aislan segmentos de red, por ejemplo, podemos crear una red bridge que tenga varios contenedores que se comuniquen entre sí, pero queden aislados del resto que no estén en esa red.

    • Se podrán añadir o eliminar contenedores de este segmento de red.

    • Los contenedores tienen comunicación entre sí si están en la misma red Bridge, pero no con otras redes.

    • Si un contenedor es añadido a varias redes Bridge se podrá comunicar con los miembros de las redes en las que esté.

    • Si un contenedor tiene varias redes brigde, podrá salir al exterior con la primera red no interna que encuentre en sus interfaces.

      Una de las características especiales de las redes bridge es que permite hacer Link entre contenedores. De tal forma que:

    • No hace falta exponer los puertos de cada contenedor para que puedan contectarse entre si.

    • Gracias a Links los contenedores "descubren" los servicios de cada contenedor manteniendo una conexión segura.

    • Se necesita el uso de los nombres en los contenedores.

    • Se usarán unas variables de entorno para almacenar los datos recogidos.

  • Host. Usada para enlazar distintos contenedores en un mismo Host.

  • None. Usada para aislar al contenedor y dejarlo sin red.

Podemos ver las redes que tenemos en Docker usando el comando sudo docker network ls :

comprobar_redes

Comandos para la gestión de red en Docker

Conectar un contenedor a una red:

sudo docker network connect

Desconectar un contenedor a una red:

sudo docker network disconnect

Crear una red nueva:

sudo docker network create

Inspeccionar las redes:

sudo docker network inspect

Listar las redes existentes:

sudo docker network ls

Borrar una red:

sudo docker network rm

Practicando con las redes de Docker

Vamos a crear una red de prueba de tipo bridge en nuestro equipo con el comando sudo docker create -d bridge network redprueba siendo -d brige el tipo de red que queremos y red prueba el nombre asignado para esta red.

crear_red

Ahora podremos comprobar que hemos añadido una nueva red usando el comando sudo docker network ls

ver_red

Seguidamente podemos inspeccionar la red que acabamos de crear con el comando sudo docker inspect redprueba. Veremos que se ha añadido una subred y puerta de enlace a esta red.

inspeccionar_red

Es importante también ver como, de forma local en nuestro equipo se ha añadido una nueva interfaz de red que hace referencia a la nueva red añadida en Docker, que además ocupa el primer lugar en la lista de nuestras interfaces de red.

ver_interfaces

Con la nueva red creada, podemos añadirle esta nueva red junto a una de las imagenes que ya tenemos guardadas para así crear un contenedor con esta nueva red, para ello haremos lo siguiente:

contenedor_red

Y podremos ver si el contenedor ha obtenido la red creada anteriormente inspeccionando dicho contenedor, si la dirección que ha obtenido y la puerta de enlace pertenecen a la red de redprueba siendo una red del tipo 172.18.0.0 entonces se habrá creado el contenedor con la nueva red correctamente

Primero debemos obtener el ID del contenedor con el comando sudo docker ps, que listará todos los contenedores activos. Y después con el comando sudo docker inspect id_contenedor veremos la red que se le ha asignado a nuestro nuevo contenedor.

inspeccionar_contenedor

Ahora vamos a crear un 2º contenedor llamado web2 pero en este caso sin asignarlo a la misma red que web1.

contenedor_sinred

Atención

Al no añadir este contenedor llamado web2 a la red creada anteriormente redprueba, no deberían tener conexión entre ellos, esto es algo que vamos a comprobar.

Si ahora ejecutamos el contenedor recién creado web2 podremos comprobar mediante un ping que efectivamente no tendremos conectividad con el primer contenedor llamado web1 cuya dirección IP es 172.18.0.2.

noping

Para poder tener conectividad y que ambos contenedores sean visibles entre si necesitamos que estén en la misma red, por lo que vamos a usar el comando visto al principio en el apartado de redes en Docker, sudo docker network connect redprueba web2. Este comando añadirá al contenedor web2 la red que necesitamos (redprueba) para establecer la conexión entre ambos contenedores.

noping

Almacenamiento en Docker

El almacenamiento en Docker se puede realizar de dos formas distintas:

Contenedor volumen de datos

Un contenedor volumen de datos es un tipo especial de volumen de datos que se crea y se gestiona dentro del contenedor en sí mismo. En lugar de persistir los datos en un host externo, los datos se almacenan en una ubicación dentro del contenedor. Esto significa que los datos solo están disponibles para el contenedor en el que se crearon y que se perderán cuando se elimine el contenedor.

Volumen de datos

Un volumen de datos es un mecanismo que permite a un contenedor acceder y almacenar datos fuera de su sistema de archivos raíz. Los volúmenes de datos se utilizan para persistir datos generados por un contenedor y compartirlos con otros contenedores, incluso si el contenedor original ya no existe.

Comandos para la gestión de Volumen de datos

Crear un nuevo volumen de datos:

sudo docker volume create

Inspeccionar un volumen de datos:

sudo docker volume inspect

Listar un volumen de datos:

sudo docker volume ls

Eliminar un volumen de datos:

sudo docker volume rm
Importante

Es importante revisar que no tengamos ningún volumen de datos ocupando espacio innecesariamente, cuando creamos contenedores se les asocia un volumen de datos que debe ser eliminado si no vamos a usar más ese contenedor.

Practicando con volumenes en Docker

En este apartado vamos a crear un nuevo contenedor usando el comando visto en las anteriores prácticas, con el parámetro -P para exponer sus puertos, con nombre web3 y le asignaremos un volumen con el parámetro -v /volweb3 siendo /volweb3 el nombre del volumen asignado.

contenedor_volumen

Una vez creado el nuevo volumen con su contenedor correspondiente podremos inspeccionar este contenedor y ver si efectivamente ha obtenido el volumen indicado.

Para ello usaremos el comando sudo docker inspect web3

inspeccionar_vol_contenedor

También podemos comprobar que efectivamente el ID hexadecimal que nos ofrece el comando anterior es exactamente el mismo que nos devuelve la ejecución del comando sudo docker volume ls, por lo que podemos ver que se creó el volumen de forma exitosa.

inspeccionar_vol_contenedor

Practicando la compartición de directorios con contenedores Docker

La siguiente práctica será, compartir un directorio de nuestra máquina física (el anfitrión) con un contenedor.

¿Para qué puede ser útil?

Imaginemos que tenemos unos contenedores que usan un servidor web de NGINX y necesitamos tener una copia de los logs de estos contenedores para su posterior análisis.

En primer lugar vamos a crear un directorio en nuestro equipo anfitrión donde queremos que se copien estos ficheros de log.

sudo mkdir ~/logs_nginx

Usando el comando anterior se creará un directorio llamado logs_nginx en el directorio de inicio del usuario actual sin necesidad de especificar la ruta completa al directorio de inicio gracias al ~/.

Entonces, ahora, podemos crear un nuevo contenedor asociandole como volumen el nuevo directorio creado llamado logs_nginx donde guardará una copia de los ficheros de log del servidor web NGINX. Aparte le hemos indicado con el parámetro -p 6000:80 que el puerto de nuestra máquina física 6000 se corresponda con el puerto 80 del contenedor.

compartir_vol

Si se ha creado el nuevo contenedor correctamente, podremos ver cómo de primeras, ya sin hacer nada, el contenedor ha metido sus primeros ficheros logs en nuestro directorio local.

comprobar_log

Pero no contentos con esto, queremos ver que efectivamente la máquina física guarda el contenido de los ficheros log. Para ello vamos a ejecutar el siguiente comando curl localhost:6000

Este comando hace una solicitud HTTP utilizando la herramienta de línea de comandos "curl" para hacer una solicitud GET al servidor local en el puerto 6000, que abrimos previamente para enlazarlo con el 80 del contenedor de NGINX.

peticion_nginx

El comando nos devuelve la página de inicio que tiene este servidor NGINX por defecto, y a continuación debería verse esta solicitud reflejada en el fichero log de nuestra máquina física.

ver_access

Usando contenedores como almacenamiento

Crearemos un contenedor con un volumen llamado /tmp y cuyo nombre será contenedor_datos y usará la imagen de Ubuntu.

contenedor_ubuntu

Toma nota

Recuerda que el comando sudo docker create creará un contenedor a partir de una imagen, pero NO la ejecutará, mientras que el comando sudo docker run hará lo mismo que el comando anterior pero este SI ejecutará el contenedor.

Dentro de este contenedor recién creado, (primero debemos lanzarlo) vamos a crear un archivo de prueba para comprobar que efectivamente los contenedores que se asocien a este volumen de almacenamiento tendrán los mismos ficheros. Para esto vamos a usar el comando ya visto sudo docker run -t -i --volumes-from contenedor_datos ubuntu /bin/bash, con este comando ejecutaremos el contenedor ya creado con el volumen indicado.

crear_fichero

Nuestro fichero de prueba se llama ficheroprueba y contiene el texto Hola ZonaBit.

Ahora haremos un nuevo contenedor con la etiqueta --volumes-from contenedor_datos que lo que hará será tomar el volumen que esté en otro contenedor, en este caso, el contenedor creado anteriormente llamado contenedor_datos.

nuevo_contenedor_datos

Una vez hecho esto podemos comprobar que efectivamente los dos contenedores creados comparten el mismo volumen de datos.

Conclusión

En conclusión, Docker ha revolucionado la forma en que se gestionan las aplicaciones y los servicios en la nube, gracias a su capacidad de virtualizar a nivel de sistema operativo y su función de contenedores.

A través de su enfoque en la modularidad, la portabilidad y la escalabilidad, Docker ha permitido a los desarrolladores, administradores de sistemas y empresas de todos los tamaños crear y ejecutar aplicaciones y servicios de manera más rápida y eficiente. Además, la comunidad de Docker ha creado una gran cantidad de herramientas y recursos que permiten a los usuarios aprovechar al máximo esta tecnología innovadora.

En resumen, Docker ha cambiado la forma en que pensamos sobre la virtualización y la gestión de aplicaciones, y es una herramienta indispensable en el arsenal de cualquier profesional de TI que busque mejorar la eficiencia y la productividad en sus proyectos.