Docker es una te­c­no­lo­gía para la vi­r­tua­li­za­ción de apli­ca­cio­nes de software basada en co­n­te­ne­do­res. El enfoque principal de Docker basado en co­n­te­ne­do­res ha tra­n­s­fo­r­ma­do el de­sa­rro­llo de apli­ca­cio­nes en los últimos años. Ha afectado a di­fe­re­n­tes áreas del de­sa­rro­llo, in­clu­ye­n­do cómo se co­n­s­tru­yen las apli­ca­cio­nes y los co­m­po­ne­n­tes, cómo se di­s­tri­bu­yen los servicios de software y cómo se trasladan del de­sa­rro­llo a la pro­du­c­ción. Con Docker, todos estos procesos se ejecutan de forma diferente a como lo hacían antes.

Pero no solo han cambiado los procesos de de­sa­rro­llo, sino también la ar­qui­te­c­tu­ra del software. Se ha alejado de las so­lu­cio­nes globales mo­no­lí­ti­cas y se ha acercado a los co­n­glo­me­ra­dos de software ligero acoplado en “mi­cro­se­r­vi­cios”. Esto, a su vez, ha hecho que los sistemas globales re­su­l­ta­n­tes sean más complejos. En los últimos años, se ha es­ta­ble­ci­do un software como Ku­be­r­ne­tes para gestionar apli­ca­cio­nes mu­l­ti­co­n­te­ne­dor.

El de­sa­rro­llo de la vi­r­tua­li­za­ción basada en co­n­te­ne­do­res está lejos de haber terminado, por lo que sigue siendo un campo apa­sio­na­n­te. En este artículo, ex­pli­ca­re­mos cómo funciona Docker como te­c­no­lo­gía su­b­ya­ce­n­te. Además, veremos qué motivó el de­sa­rro­llo de Docker.

Nota

El nombre “Docker” tiene varios si­g­ni­fi­ca­dos. Se utiliza como sinónimo del propio software, para designar el proyecto de código abierto en el que se basa, y para designar a una empresa es­ta­dou­ni­de­n­se que explota co­me­r­cia­l­me­n­te varios productos y servicios.

Una breve historia de Docker

El software publicado ori­gi­na­l­me­n­te con el nombre de “Docker” se basó en la te­c­no­lo­gía de co­n­te­ne­do­res de Linux (LXC). LXC fue su­s­ti­tui­do po­s­te­rio­r­me­n­te por la propia li­b­co­n­tai­ner de Docker. Se han añadido nuevos co­m­po­ne­n­tes de software a medida que Docker ha seguido creciendo y se ha co­n­ve­r­ti­do en el estándar de la vi­r­tua­li­za­ción basada en co­n­te­ne­do­res. Del de­sa­rro­llo de Docker han surgido conceptos como co­n­tai­ne­rd, un tiempo de ejecución de co­n­te­ne­do­res con la im­ple­me­n­ta­ción por defecto runC. En la ac­tua­li­dad, ambos proyectos están ge­s­tio­na­dos por la Cloud Native Computing Fou­n­da­tion (CNCF) y la Open Container Ini­tia­ti­ve (OCI).

Además del equipo de Docker, empresas te­c­no­ló­gi­cas líderes como Cisco, Google, Huawei, IBM, Microsoft y Red Hat pa­r­ti­ci­pan en el de­sa­rro­llo de Docker y las te­c­no­lo­gías re­la­cio­na­das. Un avance más reciente es que ahora también se utiliza Windows como entorno nativo para los co­n­te­ne­do­res Docker, además del núcleo de Linux. Estos son algunos de los pri­n­ci­pa­les hitos en la historia evolutiva de Docker:

Año Hitos del de­sa­rro­llo de Docker
2007 Te­c­no­lo­gía cgroups integrada en el núcleo de Linux
2008 La­n­za­mie­n­to de LXC; construye sobre cgroups y sobre espacios de nombres de Linux como hizo Docker más tarde
2013 Docker liberado como código abierto
2014 Docker di­s­po­ni­ble en Amazon EC2
2015 Ku­be­r­ne­tes liberado
2016 Docker di­s­po­ni­ble en Windows 10 Pro a través de Hyper-V
2019
Consejo

Al final del artículo, en­tra­re­mos en detalle sobre lo que motivó el de­sa­rro­llo de Docker y otras te­c­no­lo­gías de vi­r­tua­li­za­ción similares.

¿Qué es Docker?

La fu­n­cio­na­li­dad principal de Docker es la vi­r­tua­li­za­ción de apli­ca­cio­nes en co­n­te­ne­do­res. Esto contrasta con la vi­r­tua­li­za­ción con máquinas virtuales (VM). Con Docker, el código de la apli­ca­ción, incluidas todas las de­pe­n­de­n­cias, se empaqueta en una “imagen”. El software Docker ejecuta la apli­ca­ción em­pa­que­ta­da en un co­n­te­ne­dor Docker. Las imágenes pueden moverse entre sistemas y eje­cu­tar­se en cualquier sistema que ejecute Docker.

Cita

Co­n­tai­ne­rs are a sta­n­da­r­di­zed unit of software that allows de­ve­lo­pe­rs to isolate their app from its en­vi­ro­n­me­nt […]”. - Cita de un de­sa­rro­lla­dor de Docker, fuente: https://www.Docker.com/why-Docker

“Los co­n­te­ne­do­res son una unidad de software es­ta­n­da­ri­za­da que permite a los de­sa­rro­lla­do­res aislar su apli­ca­ción de su entorno [...]” (Traducido por IONOS).

Al igual que en el caso de la im­pla­n­ta­ción de máquinas virtuales (VM), un objetivo principal de los co­n­te­ne­do­res Docker es aislar la apli­ca­ción que se está eje­cu­ta­n­do. Sin embargo, a di­fe­re­n­cia de las VM, no se vi­r­tua­li­za un sistema operativo completo. En su lugar, Docker asigna ciertos recursos del sistema operativo y del hardware a cada co­n­te­ne­dor. Se puede crear cualquier número de co­n­te­ne­do­res a partir de una imagen Docker y hacerlos funcionar en paralelo. Así es como se im­ple­me­n­tan los servicios es­ca­la­bles en la nube.

Aunque hablemos de Docker como una pieza de software, en realidad se trata de múltiples co­m­po­ne­n­tes de software que se comunican a través de la API Docker Engine. Además, se utiliza un gran número de objetos es­pe­cia­les de Docker, como las me­n­cio­na­das imágenes y co­n­te­ne­do­res. Los flujos de trabajo es­pe­cí­fi­cos de Docker están co­m­pue­s­tos por los co­m­po­ne­n­tes de software y los objetos Docker. Veamos en detalle cómo in­ter­ac­túan.

Software Docker

La base del software Docker es el “Docker Engine”. Se utiliza pri­n­ci­pa­l­me­n­te para gestionar y controlar los co­n­te­ne­do­res y sus imágenes su­b­ya­ce­n­tes. Para las fu­n­cio­na­li­da­des que van más allá se utilizan he­rra­mie­n­tas es­pe­cia­les, ne­ce­sa­rias pri­n­ci­pa­l­me­n­te para gestionar apli­ca­cio­nes que consisten en grupos de co­n­te­ne­do­res.

Docker Engine

Docker Engine se ejecuta en un sistema o servidor local y consta de dos co­m­po­ne­n­tes:

  1. El Docker daemon (Dockerd). Se ejecuta siempre en segundo plano y recibe las pe­ti­cio­nes de la API Docker Engine. Dockerd responde a los comandos adecuados para gestionar los co­n­te­ne­do­res Docker y otros objetos Docker.
  2. El cliente Docker (Docker). Es un programa de línea de comandos. El cliente Docker se utiliza para controlar el motor Docker y pro­po­r­cio­na comandos para crear y construir co­n­te­ne­do­res Docker, así como para crear, obtener y versionar imágenes Docker.

API Docker Engine

La API Docker Engine es una REST API. In­ter­ac­túa con el Docker daemon. Existen “software de­ve­lo­p­me­nt kits” (SKDs) para Go y Python que permiten integrar la API del Docker Engine en los proyectos de software. También existen bi­blio­te­cas similares para más de una docena de otros lenguajes de pro­gra­ma­ción. Puedes acceder a la API con la línea de comandos mediante el comando Docker. Además, puedes acceder a la API di­re­c­ta­me­n­te uti­li­za­n­do cURL o he­rra­mie­n­tas similares.

He­rra­mie­n­tas Docker

Cuando utilizas máquinas virtuales, sueles utilizar sistemas formados por varios co­m­po­ne­n­tes de software. En cambio, la vi­r­tua­li­za­ción de co­n­te­ne­do­res con Docker favorece los conjuntos de mi­cro­se­r­vi­cios mal acoplados. Estos son adecuados para so­lu­cio­nes di­s­tri­bui­das en la nube que ofrecen un alto grado de mo­du­la­ri­dad y alta di­s­po­ni­bi­li­dad. Sin embargo, este tipo de sistemas se vuelven muy complejos rá­pi­da­me­n­te. Para gestionar efi­ca­z­me­n­te las apli­ca­cio­nes en co­n­te­ne­do­res, se utilizan he­rra­mie­n­tas de software es­pe­cia­les conocidas como “or­che­s­tra­to­rs” u or­que­s­ta­do­ras.

Docker Swarm y Docker Compose son dos he­rra­mie­n­tas oficiales de Docker que están di­s­po­ni­bles para orquestar conjuntos de co­n­te­ne­do­res. El comando “Docker swarm” puede uti­li­zar­se para combinar varios Docker Engines en un solo motor virtual. Los motores in­di­vi­dua­les pueden operar entonces en múltiples sistemas e in­frae­s­tru­c­tu­ras. El comando “Docker compose” se utiliza para crear apli­ca­cio­nes mu­l­ti­co­n­te­ne­dor conocidas como “stacks” o pilas.

El or­que­s­ta­dor Ku­be­r­ne­tes, de­sa­rro­lla­do ori­gi­na­l­me­n­te por Google, es más fácil de usar que Swarm y Compose. Se ha es­ta­ble­ci­do como estándar y es am­plia­me­n­te utilizado por la industria. Las empresas de alo­ja­mie­n­to y otros pro­vee­do­res de so­lu­cio­nes de “Software as a Service” (SaaS) y de “Platform as a Service” (PaaS) utilizan cada vez más Ku­be­r­ne­tes como in­frae­s­tru­c­tu­ra de base.

Objetos Docker

Los flujos de trabajo en el eco­si­s­te­ma Docker son el resultado de cómo los objetos Docker in­ter­ac­túan entre sí. Se gestionan mediante la co­mu­ni­ca­ción con la API del Docker Engine. Veamos en detalle cada tipo de objeto.

Imagen Docker

Una imagen Docker es una plantilla de solo lectura para crear uno o más co­n­te­ne­do­res idénticos. Las imágenes Docker son efe­c­ti­va­me­n­te las semillas del sistema; se utilizan para agrupar y entregar apli­ca­cio­nes.

Se utilizan varios re­po­si­to­rios para compartir imágenes Docker. Hay re­po­si­to­rios públicos y privados. En el momento de escribir este artículo, hay más de cinco millones de imágenes di­fe­re­n­tes di­s­po­ni­bles para su descarga en el popular “Docker Hub”. Los comandos Docker “Docker pull” y “Docker push” se utilizan para descargar una imagen de un re­po­si­to­rio o co­m­pa­r­ti­r­la allí.

Las imágenes Docker se co­n­s­tru­yen por capas. Cada capa re­pre­se­n­ta un cambio es­pe­cí­fi­co en la imagen. Esto da lugar a un ve­r­sio­na­do continuo de las imágenes, que permite volver a un estado anterior. Una imagen existente puede uti­li­zar­se como base para crear una nueva imagen.

Do­c­ke­r­fi­le

Un Do­c­ke­r­fi­le es un archivo de texto que describe la es­tru­c­tu­ra de una imagen Docker. Un Do­c­ke­r­fi­le es similar a un script de pro­ce­sa­mie­n­to por lotes; el archivo contiene comandos que describen una imagen. Cuando ejecutas un Do­c­ke­r­fi­le, los comandos se procesan uno tras otro. Cada comando crea una nueva capa en la imagen Docker. Así que también puedes pensar en un Do­c­ke­r­fi­le como una especie de receta utilizada como base para crear una imagen.

Co­n­te­ne­dor Docker

Ahora pasemos al concepto principal del universo Docker: los co­n­te­ne­do­res Docker. Mientras que una imagen Docker es una plantilla inerte, un co­n­te­ne­dor Docker es una instancia activa y en ejecución de una imagen. Una imagen Docker existe lo­ca­l­me­n­te en una única copia y solo ocupa un poco de espacio de al­ma­ce­na­mie­n­to. En cambio, se pueden crear varios co­n­te­ne­do­res Docker a partir de la misma imagen y eje­cu­tar­se en paralelo.

Cada co­n­te­ne­dor Docker consume una cierta cantidad de recursos del sistema para su ejecución, como el uso de la CPU, la RAM, las in­te­r­fa­ces de red, etc. Un co­n­te­ne­dor Docker puede ser creado, iniciado, detenido y destruido. También se puede guardar el estado de un co­n­te­ne­dor en ejecución como una nueva imagen.

Volumen Docker

Como hemos visto, se crea un co­n­te­ne­dor Docker en fu­n­cio­na­mie­n­to a partir de una imagen no mo­di­fi­ca­ble. Pero ¿qué pasa con los datos que se utilizan dentro del co­n­te­ne­dor y que deben co­n­se­r­var­se más allá de su vida útil? Los volúmenes Docker se utilizan para este caso de uso. Un volumen Docker existe fuera de un co­n­te­ne­dor es­pe­cí­fi­co. Así, varios co­n­te­ne­do­res pueden compartir un volumen. Los datos co­n­te­ni­dos en el volumen se almacenan en el sistema de archivos del host. Esto significa que un volumen Docker es como una carpeta co­m­pa­r­ti­da en una máquina virtual.

¿Cómo funciona Docker?

El principio de actuación básico de Docker funciona de forma similar a la te­c­no­lo­gía de vi­r­tua­li­za­ción LXC de­sa­rro­lla­da an­te­rio­r­me­n­te: ambos se basan en el núcleo de Linux y realizan una vi­r­tua­li­za­ción basada en co­n­te­ne­do­res. Tanto Docker como LXC combinan dos objetivos co­n­tra­di­c­to­rios:

  1. Los co­n­te­ne­do­res que se ejecutan comparten el mismo núcleo de Linux, lo que los hace más ligeros que las máquinas virtuales.
  2. Los co­n­te­ne­do­res en ejecución están aislados unos de otros y solo tienen acceso a una cantidad limitada de recursos del sistema.

Tanto Docker como LXC utilizan “kernel na­me­s­pa­ces” y “control groups” para lograr estos objetivos. Veamos cómo funciona en detalle.

Kernel de Linux

El kernel de Linux es el co­m­po­ne­n­te central del sistema operativo de código abierto GNU/Linux. El kernel gestiona el hardware y controla los procesos. Cuando se ejecuta Docker fuera de Linux, se necesita un hy­pe­r­vi­sor o una máquina virtual para pro­po­r­cio­nar la fu­n­cio­na­li­dad del kernel de Linux. En macOS, se utiliza xhyve, un derivado del hy­pe­r­vi­sor BSD bhyve. En Windows 10, Docker utiliza el hy­pe­r­vi­sor Hyper-V.

Na­me­s­pa­ces de Kernel

Los na­me­s­pa­ces son una ca­ra­c­te­rí­s­ti­ca del núcleo de Linux. Pa­r­ti­cio­nan los recursos del kernel y así aseguran que los procesos pe­r­ma­ne­z­can separados unos de otros. Un proceso de namespace solo puede ver los recursos del kernel de ese mismo namespace. Aquí hay una visión general de los na­me­s­pa­ces uti­li­za­dos en Docker:

Namespace De­s­cri­p­ción Ex­pli­ca­ción
UTS Ide­n­ti­fi­ca­ción del sistema Asignar a los co­n­te­ne­do­res sus propios nombres de host y dominio
PID Ide­n­ti­fi­ca­ción de procesos Cada co­n­te­ne­dor utiliza su propio espacio de nombres para los ID de los procesos; los PID de otros co­n­te­ne­do­res no son visibles; así, dos procesos en di­fe­re­n­tes co­n­te­ne­do­res pueden utilizar el mismo PID sin conflicto.
IPC Co­mu­ni­ca­ción entre procesos Los espacios de nombres IPC aíslan los procesos de un co­n­te­ne­dor para que no puedan co­mu­ni­car­se con los procesos de otros co­n­te­ne­do­res.
NET Recursos de red Asignar recursos de red separados, como di­re­c­cio­nes IP o tablas de en­ru­ta­mie­n­to, a un co­n­te­ne­dor.
MNT Puntos de montaje del sistema de archivos Restringe el sistema de archivos del host a una sección muy definida desde el punto de vista del co­n­te­ne­dor

Control groups

Los control groups, no­r­ma­l­me­n­te abre­via­dos como cgroups, se utilizan para organizar los procesos de Linux je­rá­r­qui­ca­me­n­te. A un proceso (o grupo de procesos) se le asigna una cantidad limitada de recursos del sistema. Esto incluye RAM, núcleos de CPU, al­ma­ce­na­mie­n­to masivo y di­s­po­si­ti­vos de red (virtuales). Mientras que los espacios de nombres aíslan los procesos entre sí, los control groups imitan el acceso a los recursos del sistema. Esto garantiza que el sistema general siga fu­n­cio­na­n­do cuando se utilizan varios co­n­te­ne­do­res.

¿Cuáles son las ventajas de Docker?

Echemos un vistazo a la historia del de­sa­rro­llo de software para co­m­pre­n­der las ventajas de Docker. ¿Cómo se construye, entrega y ejecuta el software? ¿Qué partes del proceso han cambiado fu­n­da­me­n­ta­l­me­n­te? El software es la co­n­tra­pa­r­ti­da del hardware, el ordenador físico. Sin el software, el ordenador no es más que un trozo de materia. Mientras que el hardware es fijo e inal­te­ra­ble, el software puede re­co­n­s­trui­r­se y pe­r­so­na­li­zar­se. La in­ter­ac­ción de ambos niveles da lugar a este ma­ra­vi­llo­so mundo digital.

Software en una máquina física

Tra­di­cio­na­l­me­n­te, el software se ha creado para ser ejecutado en una máquina física. Pero cuando lo hacemos nos topamos rá­pi­da­me­n­te con un muro. El software solo puede eje­cu­tar­se en un de­te­r­mi­na­do hardware. Requiere, por ejemplo, un pro­ce­sa­dor concreto.

Además, el software más complejo no suele funcionar de forma co­m­ple­ta­me­n­te autónoma, sino que está integrado en un eco­si­s­te­ma de software. Este incluye un sistema operativo, bi­blio­te­cas y de­pe­n­de­n­cias. Para que todos los co­m­po­ne­n­tes in­ter­ac­túen co­rre­c­ta­me­n­te, deben estar di­s­po­ni­bles las versiones adecuadas. También hay una co­n­fi­gu­ra­ción que describe cómo se vinculan los co­m­po­ne­n­tes in­di­vi­dua­les entre sí.

Si quieres ejecutar varias apli­ca­cio­nes en una máquina en paralelo, rá­pi­da­me­n­te surgen co­n­fli­c­tos de versiones. Una apli­ca­ción puede necesitar una versión de un co­m­po­ne­n­te que sea in­co­m­pa­ti­ble con otra apli­ca­ción. En el peor de los casos, cada apli­ca­ción tendría que eje­cu­tar­se en su propia máquina física. Lo cierto es que las máquinas físicas son caras y no se pueden escalar fá­ci­l­me­n­te. Así que si los re­qui­si­tos de recursos de una apli­ca­ción crecen, puede ser necesario migrar a una nueva máquina física.

Otro problema surge del hecho de que el software en de­sa­rro­llo se utiliza en di­fe­re­n­tes entornos. Un de­sa­rro­lla­dor escribe el código en el sistema local y lo ejecuta allí para probarlo. La apli­ca­ción pasa por varias etapas de prueba antes de pasar a pro­du­c­ción, in­clu­ye­n­do un entorno de prueba para ga­ra­n­ti­zar la calidad o un entorno de ensayo para que el equipo del producto lo pruebe.

Los distintos entornos suelen existir en máquinas físicas di­fe­re­n­tes. Casi siempre hay di­fe­re­n­cias en las versiones del sistema operativo, la bi­blio­te­ca y la co­n­fi­gu­ra­ción. ¿Cómo puedes co­n­ci­liar­las todas? Porque si los entornos difieren entre sí, las pruebas pierden su sentido. Además, hay que sustituir un sistema si falla. ¿Cómo puedes ga­ra­n­ti­zar la co­he­re­n­cia? Es difícil en­fre­n­tar­se a estos problemas en máquinas físicas.

Las máquinas virtuales como un paso en la dirección correcta

Los problemas antes me­n­cio­na­dos re­la­cio­na­dos con las máquinas físicas han provocado el aumento de la po­pu­la­ri­dad de las máquinas virtuales (VM). La idea básica es integrar una capa entre el hardware y el sistema operativo o el sistema operativo anfitrión y los sistemas ope­ra­ti­vos ajenos. Una VM desacopla el entorno de la apli­ca­ción del hardware su­b­ya­ce­n­te. La co­m­bi­na­ción es­pe­cí­fi­ca de un sistema operativo, una apli­ca­ción, unas bi­blio­te­cas y una co­n­fi­gu­ra­ción puede re­pro­du­ci­r­se a partir de una imagen. Además de aislar co­m­ple­ta­me­n­te una apli­ca­ción, esto permite a los de­sa­rro­lla­do­res agrupar varias apli­ca­cio­nes en un “di­s­po­si­ti­vo”.

Las imágenes de las máquinas virtuales pueden moverse entre máquinas físicas y varios sistemas ope­ra­ti­vos vi­r­tua­li­za­dos pueden eje­cu­tar­se en paralelo. Esto garantiza la es­ca­la­bi­li­dad de la apli­ca­ción. Sin embargo, la vi­r­tua­li­za­ción del sistema operativo consume muchos recursos y es excesiva para casos de uso sencillos.

Las ventajas de la vi­r­tua­li­za­ción de co­n­te­ne­do­res con Docker

Las imágenes uti­li­za­das en la vi­r­tua­li­za­ción de co­n­te­ne­do­res no necesitan un sistema operativo. La vi­r­tua­li­za­ción de co­n­te­ne­do­res es más ligera y pro­po­r­cio­na casi tanto ai­s­la­mie­n­to como las máquinas virtuales. Una imagen de co­n­te­ne­dor combina el código de la apli­ca­ción con todas las de­pe­n­de­n­cias ne­ce­sa­rias y la co­n­fi­gu­ra­ción. Las imágenes son tra­n­s­fe­ri­bles entre sistemas, y los co­n­te­ne­do­res co­n­s­trui­dos sobre ellas pueden re­pro­du­ci­r­se. Los co­n­te­ne­do­res pueden uti­li­zar­se en varios entornos, como el de de­sa­rro­llo, el de pro­du­c­ción, el de pruebas y el de pre­pa­ra­ción. El control de las versiones de las capas y de las imágenes también pro­po­r­cio­na una buena dosis de mo­du­la­ri­dad.

Resumamos las pri­n­ci­pa­les ventajas de la vi­r­tua­li­za­ción de apli­ca­cio­nes basada en Docker frente a la uti­li­za­ción de una VM. Un co­n­te­ne­dor Docker:

  • no contiene su propio sistema operativo y hardware simulado
  • comparte un núcleo de sistema operativo con otros co­n­te­ne­do­res alojados en el mismo sistema
  • es ligero y compacto en términos de uso de recursos en co­m­pa­ra­ción con una apli­ca­ción basada en una máquina virtual
  • se inicia más rápido que una máquina virtual
  • puede eje­cu­tar­se en varias in­s­ta­n­cias de la misma imagen en paralelo
  • puede uti­li­zar­se junto con otros servicios basados en co­n­te­ne­do­res mediante la or­que­s­ta­ción
  • es ideal para el de­sa­rro­llo en local
Ir al menú principal