
El secreto de Docker es que Linux hace todo el trabajo sucio
Docker se ha consolidado como una herramienta fundamental en el sector IT, especialmente en roles técnicos. Es común observar el clásico diagrama que compara las máquinas virtuales con los contenedores, aunque raras veces se profundiza en la tecnología subyacente.
Las máquinas virtuales, solución predominante en la infraestructura antes de la estandarización de los contenedores, resultan costosas en términos de recursos (overhead) debido a su propia naturaleza. La adopción masiva de contenedores responde principalmente a dos factores: el auge de las arquitecturas de microservicios y su bajo consumo de cómputo en comparación con las máquinas virtuales.
La virtualización emplea un modelo de traducción y emulación. Se crea un entorno que simula hardware real para la máquina invitada (guest); el hipervisor intercepta las instrucciones, las traduce al sistema operativo anfitrión y devuelve los resultados al guest.

Este proceso conlleva un alto gasto computacional. Por el contrario, los contenedores son eficientes porque comparten el kernel del anfitrión. Esto permite crear entornos aislados con un consumo de recursos significativamente menor, optimizando la capacidad del sistema para otras tareas.

La arquitectura de Docker
A nivel de arquitectura, Docker es sencillo. Con modelo cliente-servidor, el cliente de Docker se comunica con el daemon de Docker (dockerd), que a su vez se encarga montar, correr y distribuir los contenedores. Ambos se comunican mediante una API REST, a través de sockets UNIX (si cliente y servidor están en la misma máquina) o una interfaz de red (para gestión remota).
Es decir, el daemon está a la escucha actuando como servidor. Cuando recibe peticiones a la API de Docker realiza las acciones solicitadas en contenedores, imágenes, redes o volúmenes. El cliente es habitualmente la aplicación CLI (docker), pero puede ser una SDK o una interfaz gráfica (Docker Desktop).

Los conceptos fundamentales son las imágenes y los contenedores, habitualmente almacenados en registros (registries). Las imágenes funcionan como plantillas con instrucciones de creación, mientras que el contenedor es una instancia funcional de una imagen. A través de la API, es posible gestionar su ejecución, conectarlos a redes o persistir su estado, aunque la migración de contenedores activos entre diferentes hosts suele requerir herramientas adicionales de orquestación.

Los namespaces
En esencia, los contenedores son entornos delimitados que ejecutan sistemas operativos diversos sin necesidad de virtualización. Para lograr este aislamiento, Docker emplea una característica del kernel de Linux denominada namespaces.
Un namespace «envuelve» un recurso global del sistema en un abstracción que hace parecer al proceso contenido en el namespace que está en un entorno aislado. Otros procesos en el mismo namespace podrían interactuar pero no «ver» procesos fuera de ese namespace. Hay varios tipos de namespace, cada uno con su función.
| Espacio de Nombres (Namespace) | Flag (Bandera) | Página de Manual | Aísla / Separa |
|---|---|---|---|
| Cgroup | CLONE_NEWCGROUP | cgroup_namespaces(7) | Directorio raíz de cgroups |
| IPC | CLONE_NEWIPC | ipc_namespaces(7) | IPC de System V, colas de mensajes POSIX |
| Red (Network) | CLONE_NEWNET | network_namespaces(7) | Dispositivos de red, stacks, puertos, etc. |
| Montaje (Mount) | CLONE_NEWNS | mount_namespaces(7) | Puntos de montaje |
| PID | CLONE_NEWPID | pid_namespaces(7) | IDs de proceso |
| Tiempo (Time) | CLONE_NEWTIME | time_namespaces(7) | Relojes de arranque y monotónicos |
| Usuario (User) | CLONE_NEWUSER | user_namespaces(7) | IDs de usuario y de grupo |
| UTS | CLONE_NEWUTS | uts_namespaces(7) | Nombre de host (hostname) y dominio NIS |
Docker aprovecha estas funcionalidades para garantizar que los procesos no interfieran con el host u otros contenedores. Los Control Groups (cgroups), por su parte, limitan el consumo de recursos (memoria, CPU, E/S) para evitar el colapso del sistema anfitrión.
También se utilizan las capabilities, una funcionalidad de Linux que pretende hacer más robusta la seguridad definiendo una serie de permisos granulares, frente al modelo privilegiado vs. no privilegiado, tradicional el Linux. Esto permite crear contenedores con algunas capacidades privilegiadas sin darles privilegios elevados.

Los namespaces en acción
Al examinar los procesos en un host Linux, se observa el sistema de inicio (como systemd) y diversos hilos del kernel (kernel threads).
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 28520 16288 ? Ss 19:40 0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize=56 splash
root 2 0.0 0.0 0 0 ? S 19:40 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 19:40 0:00 [pool_workqueue_release]
root 4 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/R-rcu_gp]
root 5 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/R-sync_wq]
root 6 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/R-kvfree_rcu_reclaim]
root 7 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/R-slub_flushwq]
root 8 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/R-netns]
root 10 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/0:0H-kblockd]
root 13 0.0 0.0 0 0 ? I< 19:40 0:00 [kworker/R-mm_percpu_wq]
root 15 0.0 0.0 0 0 ? S 19:40 0:00 [ksoftirqd/0]
root 16 0.0 0.0 0 0 ? I 19:40 0:00 [rcu_preempt]
root 17 0.0 0.0 0 0 ? S 19:40 0:00 [rcub/0]
root 18 0.0 0.0 0 0 ? S 19:40 0:00 [rcu_exp_par_gp_kthread_worker/0]
root 19 0.0 0.0 0 0 ? S 19:40 0:00 [rcu_exp_gp_kthread_worker]
root 20 0.0 0.0 0 0 ? S 19:40 0:00 [migration/0]
root 21 0.0 0.0 0 0 ? S 19:40 0:00 [kprobe-optimizer]
root 22 0.0 0.0 0 0 ? S 19:40 0:00 [idle_inject/0]
root 23 0.0 0.0 0 0 ? S 19:40 0:00 [cpuhp/0]
En un contenedor, sin embargo, no existen procesos como init o systemd, visualizándose únicamente las tareas en ejecución.
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps aux
Lo que sucede por debajo es algo así:

El contenedor utiliza los recursos de la máquina anfitriona comunicándose directamente con el kernel de forma segura. En entornos de producción, esta arquitectura se gestiona mediante orquestadores como Kubernetes, que automatizan la monitorización y el escalado de miles de instancias.
Profundizando en la práctica
docker run --rm -it alpine:latest echo "Araintel"
Al ejecutar este comando, Docker crea un contenedor basado en la distribución Alpine. Tras ejecutar echo "Araintel", el contenedor se detiene y se elimina. El flujo interno es el siguiente:
- Se invoca el binario
docker, iniciando la comunicación vía socket UNIX. - El daemon (
dockerd) recibe la petición en el endpoint/containers/createe inicia la creación del entorno. RunCrealiza una serie de llamadas al sistema (syscalls) para configurar el aislamiento:- unshare: Desasocia partes del contexto de ejecución (namespaces) que antes compartía con su proceso padre.
- mount: Monta el sistema de archivos de la imagen en el directorio de destino del contenedor.
- pivot_root: Cambia el directorio raíz del proceso a la nueva ubicación, desplazando la raíz antigua a un subdirectorio.
- chdir: Cambia el directorio de trabajo actual a la nueva raíz (
/). - capset: Aplica privilegios granulares (capabilities) específicos para el proceso.
- prctl: Establece filtros de seguridad (como Seccomp) para limitar las syscalls disponibles.
- Una vez aislado, se ejecuta el comando especificado. La salida se captura y se redirige a la terminal del host a través de la pseudoterminal creada por la bandera
-it.
En definitiva
Docker se cimenta en funcionalidades de Linux para ser lo que es. De hecho, Windows soporta Docker sólo después de implementar WSL (Windows Subsystem for Linux). Utiliza estas funcionalidades de forma inteligente para crear los contenedores que cada vez más potencian arquitecturas de aplicaciones modernas, y entender la implementación puede ser muy útil para utilizarlo con más criterio.








