Docker es una plataforma de código abierto que permite automatizar la implementación, el escalado y la gestión de aplicaciones dentro de contenedores de software. En este artículo, vamos a profundizar en cómo funciona Docker específicamente en sistemas Linux, explicando los conceptos clave y las tecnologías subyacentes.
¿Qué es un contenedor?
Un contenedor es una unidad estándar de software que empaqueta el código y todas sus dependencias para que la aplicación se ejecute de forma rápida y fiable de un entorno informático a otro. Es una forma ligera, independiente y ejecutable de empaquetar software que incluye todo lo necesario para ejecutarlo: código, tiempo de ejecución, herramientas del sistema, bibliotecas del sistema y configuraciones.
Arquitectura de Docker en Linux
Docker utiliza una arquitectura cliente-servidor. El cliente de Docker (comando docker
) se comunica con el demonio de Docker (dockerd
), que se encarga de la construcción, ejecución y distribución de los contenedores Docker. El demonio de Docker y el cliente pueden ejecutarse en el mismo sistema, o bien se puede conectar un cliente de Docker a un demonio de Docker remoto.
Fuente: Documentación oficial de Docker
Componentes principales en Linux:
- Cliente de Docker (
docker
): Interfaz de línea de comandos (CLI) para interactuar con el demonio de Docker. - Demonio de Docker (
dockerd
): Proceso en segundo plano que gestiona los contenedores, imágenes, redes y volúmenes. - Imágenes: Plantillas de solo lectura que se utilizan para crear contenedores. Una imagen se define por un
Dockerfile
. - Contenedores: Instancias en ejecución de una imagen.
- Registro: Repositorio de imágenes de Docker. Docker Hub es el registro público por defecto.
Tecnologías clave en el kernel de Linux que utiliza Docker
Docker aprovecha varias características del kernel de Linux para proporcionar aislamiento y gestión de recursos para los contenedores:
1. Namespaces
Los namespaces proporcionan aislamiento a nivel de sistema. Docker utiliza namespaces para aislar los diferentes aspectos de un contenedor del sistema anfitrión y de otros contenedores:
Namespace | Descripción |
---|---|
pid |
Aísla los identificadores de proceso (PID). |
net |
Aísla las interfaces de red, tablas de enrutamiento, etc. |
mnt |
Aísla los puntos de montaje del sistema de archivos. |
uts |
Aísla el nombre de host y el dominio. |
ipc |
Aísla los recursos de comunicación entre procesos (IPC). |
user |
Aísla los identificadores de usuario y grupo (UID y GID). |
cgroup (no es un namespace per sé, pero trabaja en conjunto) |
Limita el uso de recursos como CPU y memoria. |
2. Control Groups (cgroups)
Los cgroups limitan y monitorizan el uso de recursos (CPU, memoria, ancho de banda de red, etc.) de un conjunto de procesos. Docker utiliza cgroups para asegurar que cada contenedor solo use los recursos que se le han asignado.
3. Union File Systems (UnionFS)
Docker utiliza sistemas de archivos en capas como OverlayFS, AUFS, etc. Estos sistemas permiten que las imágenes de Docker se construyan de forma incremental, compartiendo capas comunes entre imágenes y ahorrando espacio. Cada capa representa un conjunto de cambios en el sistema de archivos. En un contenedor en ejecución, la capa superior de escritura permite realizar modificaciones que son efímeras por defecto, es decir se pierden al detener el contenedor.
Ejemplo práctico: Ejecutar un contenedor Nginx
Vamos a ejecutar un contenedor Nginx simple para ilustrar algunos de los conceptos explicados.
# 1. Descargar la imagen de Nginx (si no está en caché localmente)
docker pull nginx
# 2. Ejecutar el contenedor Nginx
docker run -d -p 8080:80 --name mi-nginx nginx
# Explicación de los parámetros:
# -d: Ejecutar en segundo plano (detached mode).
# -p 8080:80: Mapea el puerto 8080 del host al puerto 80 del contenedor.
# --name mi-nginx: Asigna el nombre "mi-nginx" al contenedor.
# nginx: Nombre de la imagen a utilizar.
Con este comando, Docker realiza las siguientes acciones:
- El cliente de Docker envía el comando
run
al demonio de Docker. - El demonio de Docker busca la imagen
nginx
. Si no la encuentra localmente, la descarga de Docker Hub. - El demonio crea un nuevo contenedor a partir de la imagen.
- Docker asigna al contenedor un sistema de archivos en capas.
- Se crea una interfaz de red virtual que conecta el contenedor a la red del host.
- Se inicia el proceso de Nginx dentro del contenedor.
- Se reenvía el tráfico del puerto 8080 del host al puerto 80 del contenedor.
Ahora puedes acceder al servidor web Nginx a través de http://localhost:8080
en tu navegador.
Para ver los namespaces que utiliza el contenedor:
#Obtener el PID del contenedor
PID=$(docker inspect --format '{{.State.Pid}}' mi-nginx)
#Ver los namespaces
ls -l /proc/$PID/ns
Conclusión
Docker aprovecha las capacidades del kernel de Linux, como los namespaces y los cgroups, para proporcionar un entorno aislado y eficiente para ejecutar aplicaciones en contenedores. La arquitectura cliente-servidor y el uso de sistemas de archivos en capas permiten una gestión flexible y un uso eficiente del espacio. Comprender estos fundamentos es esencial para trabajar eficazmente con Docker en entornos Linux.