Se revela el concepto, la estructura y los principios de funcionamiento de Docker, y comparte ejercicios que te ayudarán a dominar la herramienta.

La contenerización es una nueva ideología en IT. En la literatura se dan muchas analogías, donde los proveedores, es decir, los desarrolladores, empaquetan todo en un solo contenedor, como la carga en un puerto. Esta es una muy buena analogía. Después de todo, un contenedor digital se transporta y desempaqueta de la misma manera en un producto terminado.

La herramienta principal de contenerización es Docker, sobre la cual incluso se construye una infraestructura de servicio interna. Docker se utiliza en combinación con orquestadores como Kubernetes y OpenShift. Estos servicios marcan la transición de las máquinas virtuales clásicas a la infraestructura en la nube. Con su ayuda, puedes gestionar los recursos de forma más flexible, rápida y dinámica.

¿Qué es Docker?

El logotipo de Docker, una ballena azul con contenedores encima, mostrado en un cartel en la oficina de la empresa.
Docker en su sede.

Docker es una plataforma que permite empaquetar una aplicación con todo su entorno y dependencias en un contenedor, y luego entregarla e iniciarla en un sistema de destino.

Una aplicación empaquetada en un contenedor está aislada del sistema operativo y de otras aplicaciones. Por lo tanto, los desarrolladores no tienen que preocuparse por el entorno en el que funcionará su aplicación, y los ingenieros de operaciones pueden iniciar las aplicaciones de forma uniforme y preocuparse menos por las dependencias del sistema.

Docker se desarrolló en 2008. Inicialmente era un proyecto interno de la empresa dotCloud, que posteriormente pasó a llamarse Docker Inc. En 2013, dotCloud abrió el código fuente de Docker a la comunidad.

💪
Las versiones anteriores de Docker eran una envoltura mejorada de LXC, y a partir de 2015, Docker ya utilizaba su propia biblioteca libcontainer, que abstrae las capacidades de virtualización del núcleo de Linux. Así se convirtió en una tecnología independiente. La plataforma no cambió accidentalmente a libcontainer: la flexibilidad y la capacidad de gestión de los contenedores LXC dejaban mucho que desear.

La popularidad de Docker continúa creciendo porque cuenta con el apoyo de una gran comunidad. La plataforma se convirtió en tendencia con la popularidad de DevOps, los rápidos conductos de entrega y la automatización.

Estructura y principio de funcionamiento de Docker

La virtualización en Docker se implementa a nivel del sistema operativo. El entorno virtual se inicia directamente desde el núcleo del sistema operativo principal y utiliza sus recursos.

El suministro de Docker incluye los siguientes componentes:

  • Docker host: Es el sistema operativo en el que se instala y ejecuta Docker.
  • Docker daemon: Un servicio que gestiona los objetos Docker: redes, almacenamientos, imágenes y contenedores.
  • Docker client: Un cliente de consola mediante el cual los usuarios interactúan con el demonio Docker y le envían comandos, crean contenedores y los gestionan.
  • Docker image: Una imagen inmutable a partir de la cual se despliega un contenedor.
  • Docker container: Una aplicación desplegada e iniciada.
  • Docker Registry: Un repositorio donde se almacenan las imágenes.
  • Dockerfile: Un archivo de instrucciones para construir una imagen.
  • Docker Compose: Una herramienta para gestionar varios contenedores. Permite crear contenedores y definir su configuración.
  • Docker Desktop: Un cliente GUI que se distribuye bajo la GPL. La versión gratuita funciona en Windows, macOS y, desde hace poco, en Linux. Es un cliente muy cómodo que muestra todas las entidades de Docker y permite iniciar un Kubernetes mononodo para el ordenador.
Diagrama que muestra la arquitectura de Docker, incluyendo el cliente, el daemon, las imágenes, los contenedores y el registro.
Flujo de trabajo de Docker.

Docker se creó inicialmente para Linux. Por lo tanto, en Windows y macOS se ejecuta una máquina virtual con Linux, y encima de ella, Docker. En macOS se utiliza VirtualBox, y en Windows, Hyper-V.

Diagrama de flujo que ilustra la arquitectura de Docker, mostrando la interacción entre el cliente, el daemon, el repositorio y los contenedores.
Arquitectura de Docker.

Trabajar sobre máquinas virtuales aumenta el consumo de recursos. Por lo tanto, Docker en macOS y Windows funciona más lentamente y con una serie de limitaciones. Para el desarrollo esto es aceptable, pero en producción nadie lo hará así. En todas las plataformas populares en producción se utiliza Linux.

Diferencias entre virtualización y contenerización

Los contenedores y las máquinas virtuales son formas diferentes de virtualización. Sólo la máquina virtual la implementa a nivel de hardware, mientras que Docker lo hace a nivel del sistema operativo.

Una máquina virtual funciona como un ordenador independiente con su propio hardware y sistema operativo. Una práctica común es comprar un servidor grande e instalar en él un hipervisor, una base para las máquinas virtuales. El servidor se «divide» en muchos ordenadores virtuales, lo que nos evita tener que comprarlos por separado.

Los ordenadores virtuales son completamente funcionales. En ellos puedes instalar un sistema operativo de cualquier familia y trabajar en él, por ejemplo, a través de una interfaz gráfica en modo multiusuario, instalando e iniciando muchas aplicaciones y servicios.

Si el objetivo de una máquina virtual es reproducir completamente el dispositivo de un ordenador, el objetivo principal de Docker es crear un entorno para una sola aplicación. El entorno virtual de un contenedor se inicia dentro del sistema operativo. No necesita virtualizar el hardware, lo utiliza a través del sistema operativo. Por lo tanto, los contenedores Docker consumen menos recursos, se despliegan más rápidamente, se escalan más fácilmente y pesan menos.

💡
Asignar a una aplicación una máquina virtual completa, instalar y configurar un sistema operativo, distribuir los derechos de acceso, es demasiado caro. En la mayoría de los casos, basta con un entorno simple en el que se pueda ejecutar la aplicación. Para ello es ideal un contenedor, que contiene una aplicación principal.

Ambos métodos aíslan la aplicación del sistema operativo principal, pero si en una máquina virtual puedes instalar cualquier sistema operativo, Docker está orientado al núcleo de Linux. Recientemente se añadió la posibilidad de ejecutar Windows, pero aún no lo he probado.

Docker y las máquinas virtuales no se combinan muy bien. Sí, a veces en producción el servidor se divide en máquinas virtuales y en ellas se ejecutan contenedores. Pero este esquema, con doble virtualización, conduce a un consumo excesivo de recursos. A menudo se critica, y hay que reconocer que con razón. Si en la empresa se ha establecido esta práctica, en lugar de un hipervisor se puede instalar Kubernetes, que instalará las aplicaciones directamente en el hardware.

💡
Normalmente, en las grandes empresas se trabaja con máquinas virtuales, que se despliegan en máquinas físicas en los centros de datos. Los ingenieros de infraestructura crean ordenadores virtuales y construyen sobre ellos la infraestructura. Con la ayuda de orquestadores, se puede eliminar esta «capa» adicional.

Si tienes muchos recursos, puedes instalar Docker en una máquina virtual para aislar las aplicaciones entre sí.

Entidades de Docker

Docker trabaja con varias entidades.

  • Docker image (imagen): Es una plantilla con la que se crean los contenedores. A menudo se compara con un pastel de capas: colocamos una capa del sistema de archivos sobre una capa de la imagen base y obtenemos una imagen inmutable. En ella se puede instalar una aplicación, configuraciones y dependencias. Otras imágenes pueden heredarse, por lo que si colocamos una capa de archivos encima y la confirmamos, obtendremos otra imagen inmutable.
Captura de pantalla del panel de Docker Hub que muestra información detallada de una imagen Docker, incluyendo su historial de creación y comandos.
Ejemplo de imagen Docker en Docker Hub.
  • Dockerfile: Si la imagen de Docker es un pastel, el Dockerfile es la receta para prepararlo. Este archivo describe las instrucciones básicas para construir la imagen: qué imagen base tomar, de dónde y adónde colocar los archivos, etc.
  • Contenedor: Es una entidad de tiempo de ejecución basada en una imagen, la aplicación que hemos desplegado con Docker. Se puede hacer la siguiente analogía: la imagen es el instalador del programa, y el contenedor es el programa ya ejecutado.

Al desplegar un contenedor sobre el sistema de archivos, se crea otra capa modificable. La aplicación dentro del contenedor puede escribir o editar datos allí. Después de eliminar el contenedor, los datos se borran, pero se pueden guardar con volúmenes.

  • Docker Registry: Es un repositorio donde se almacenan las imágenes de Docker. Puede ser local o público. Los repositorios se crean en plataformas como Docker Hub y GitLab y en ellos se alojan imágenes con descripciones, diferentes versiones y etiquetas.

Cómo ayuda Docker en la práctica

Aquí tienes algunos ejemplos del uso de Docker que ilustran bien sus ventajas.

Desarrollo de aplicaciones con dependencias

Normalmente, para instalar una biblioteca o una base de datos, el desarrollador debe leer las instrucciones del sitio web. Lo descarga, lo instala, lo configura y lo inicia. Y cuando necesita cambiar a otra dependencia, la elimina. Y así tiene que trabajar con cada dependencia.

Docker ofrece una vía alternativa. Los proveedores de bibliotecas, frameworks y bases de datos publican prácticamente a diario su software en Docker Hub en forma de imagen de Docker. La imagen se puede descargar e implementar a través de Docker, trabajar con ella, realizar un push y luego detenerla o eliminarla, y en el sistema operativo no quedará ningún rastro.

Una interfaz de gestión unificada elimina la necesidad de comandos individuales. Basta con aprender los comandos de Docker: cómo descargar imágenes, ejecutar contenedores, reenviar, detener y eliminar puertos. Con Docker puedes ejecutar tantas bases de datos iguales como quieras dentro de un mismo sistema operativo. Gracias al aislamiento, si algo sale mal, los errores no afectarán al sistema operativo y nada se estropeará.

Automatización de pruebas

Para ejecutar pruebas automáticas, se necesitan ciertas dependencias, como bases de datos, brokers de mensajes, etc. Deben instalarse y configurarse previamente en el servidor de compilación. En este punto a veces surgen problemas: si se omite algún detalle en la configuración, se pueden dañar los datos o romper algo. Es mucho más seguro implementar automáticamente las dependencias en forma de contenedor directamente en el servidor. Esto permite ejecutar las pruebas rápidamente y luego eliminar los contenedores sin dejar rastro.

Incluso si las pruebas «rompen» algunos datos, estos se eliminarán junto con el contenedor. Además, el propio servidor con Docker, en el que se ejecutan las pruebas automáticas, se volverá universal. Después de todo, gracias a la contenerización, se podrá ejecutar cualquier cosa en él. Esto significa que ahorrarás en hardware y en la configuración del sistema.

Publicación de aplicaciones

Después de las pruebas, el proyecto se empaqueta en una imagen y se publica, se entrega a los clientes o a los ingenieros de infraestructura.

Docker simplifica el posterior despliegue de la aplicación. Los SRE no tienen que pensar qué dependencias instalar, ya que todo está empaquetado en la imagen. Para ellos es una caja negra que actualizan de forma uniforme y automática mediante los mismos comandos.

El entorno de despliegue también se vuelve universal, ya que siempre trabaja sólo con contenedores. Hoy se despliega un contenedor, mañana otro. Y en los contenedores se pueden empaquetar aplicaciones totalmente diferentes.

Contras de Docker

Como se sabe, por el placer hay que pagar. Y Docker no es una excepción.

  • Alto consumo de recursos: Docker crea una capa lógica adicional y consume recursos adicionales. Por lo tanto, debes determinar qué es más importante para ti: los recursos o la comodidad. Si tienes recursos de sobra, puedes instalar Docker sin problemas: podrás actualizar y versionar las aplicaciones cómodamente, sin temor a estropear el sistema operativo. Si los recursos son escasos, es mejor utilizar el esquema clásico de instalación de aplicaciones.
  • Para aplicaciones grandes se necesita un orquestador: Docker es adecuado para ejecutar varios contenedores. En la entrega estándar de Docker Compose hay un mecanismo que permite gestionar su lanzamiento mediante un archivo de configuración YAML. Pero este mecanismo es simple, no soportará una aplicación que incluya 50-100 servicios. Docker no tendrá suficientes mecanismos de gestión y distribución de recursos, reserva y tolerancia a fallos para implementar diferentes esquemas de actualización de contenedores.

En las aplicaciones grandes con arquitectura de microservicios se utilizan orquestadores como Kubernetes u OpenShift. La unidad de gestión en Kubernetes es un contenedor Docker, pero en Docker puro prácticamente nadie lo mantiene en producción.

Kubernetes es una potente capa de abstracción sobre el hardware, una alternativa a los hipervisores de las máquinas virtuales. Permite configurar políticas de seguridad, implementa diferentes esquemas de actualización y permite gestionar los recursos de forma flexible.

  • Problemas con la instalación en Windows y macOS: Como he dicho antes, Docker se creó para Linux. En otros sistemas operativos no admite algunos tipos de redes. En la mayoría de los casos nadie lo notará, pero hay que tener en cuenta esta limitación. También en algunos dispositivos se produce un conflicto con Virtual Box al instalar Docker en Windows.

Cómo aprender Docker

Recomiendo aprender Docker con libros, sitios web y consolidar lo aprendido en la práctica.

  • Libros: Hay dos buenos libros: «Using Docker» y «Docker in Action«. Es cierto que están un poco desactualizados (publicados en 2018-2019), por lo que puede haber información no actualizada. Espero que pronto haya una reedición.
  • Sitio web docker.com: El sitio web principal de Docker. En él hay manuales y referencias sobre Docker, archivos Docker, imágenes y Docker Compose. Lees un libro, compruebas la actualidad de los comandos en el sitio web y estudias los ejemplos.
  • Ejercicios: Imparto cursos de formación y formación interna en equipos. Normalmente recomiendo estos ejercicios:
    1. Instala Docker en tu ordenador. Toma una imagen de Docker preparada de Docker Hub con una base de datos e inicia un contenedor basándote en ella. Esto se puede hacer siguiendo las instrucciones que el fabricante de la imagen publica en Docker Hub. A continuación, conéctate a la base de datos iniciada con algún cliente y comprueba que todo funciona.
    2. Escribe un servicio REST API sencillo y un archivo Docker para empaquetar el servicio en una imagen, echando un vistazo a las referencias o al libro. Tu tarea es entender la teoría, obtener una imagen de Docker y poner etiquetas.
    3. Crea e inicia un contenedor a partir de la imagen obtenida anteriormente. Tendrás que entender los parámetros del comando Docker run, la configuración de los puertos, la transmisión de variables al entorno, el montaje y los parámetros principales. También deberías aprender a conectarte al contenedor, ejecutar comandos bash y ver los registros de la aplicación.
    4. Complejiza el servicio de prueba, enseñándole a trabajar con la base de datos. A continuación, despliega los contenedores con el servicio y la base de datos y conéctalos con una red interna. Un ejercicio sencillo y a la vez muy útil, en el que muy a menudo surgen dificultades en las entrevistas de trabajo.
    5. Pasa a Docker Compose. Mira cómo escribir YAML y crear un grupo de contenedores, cómo conectarlos a la red y trabajar con montajes.
    6. Publica tu imagen de Docker en Docker Hub. En una cuenta se puede publicar gratuitamente sólo una imagen, pero existe GitLab, donde no hay tales limitaciones. Es cierto que es un poco más complicado, un principiante puede confundirse. También en el mismo GitLab se puede crear un modo de registro privado y publicar proyectos sin limitaciones.

Categorizado en:

Fundamentos,