Contenedores sin Docker: Podman, containerd y runc
Introducción: El ecosistema de contenedores más allá de Docker
Durante años, Docker ha sido el sinónimo de contenedores. Sin embargo, el mundo del software libre y la infraestructura moderna ha evolucionado hacia un ecosistema más modular, ligero y seguro. Hoy, herramientas como Podman, containerd y runc están ganando terreno como alternativas viables, ofreciendo ventajas en seguridad, rendimiento y cumplimiento de estándares. Este artículo explora en profundidad estas herramientas, sus diferencias clave y cómo implementarlas en entornos de producción.
¿Por qué buscar alternativas a Docker?
Docker, aunque revolucionario, no está exento de críticas. Su arquitectura monolítica y dependencia de un demonio central (dockerd) con permisos de root ha sido señalada como un riesgo de seguridad. Además, la tendencia hacia la estandarización con la Open Container Initiative (OCI) ha permitido que herramientas más ligeras y especializadas ocupen su lugar.
Principales razones para explorar alternativas:
- Seguridad: Los contenedores rootless eliminan la necesidad de privilegios elevados.
- Modularidad: Herramientas como containerd y runc permiten construir pipelines de contenedores personalizados.
- Rendimiento: Menos capas de abstracción significan menor latencia.
- Cumplimiento: Muchas distribuciones Linux (como RHEL, Fedora) priorizan Podman sobre Docker.
Podman: El gestor de contenedores sin demonio
¿Qué es Podman?
Podman (Pod Manager) es una herramienta de gestión de contenedores desarrollada por Red Hat. Su principal característica es que no requiere un demonio central. Cada contenedor o pod se ejecuta como un proceso hijo directo del usuario que lo lanza, lo que permite contenedores rootless de forma nativa.
Ventajas clave de Podman
- Arquitectura sin demonio: No hay un proceso dockerd corriendo como root. Esto reduce la superficie de ataque.
- Compatible con Docker CLI: La mayoría de comandos de Docker (docker run, docker ps, docker build) tienen un equivalente directo en Podman (podman run, podman ps, podman build). Puedes usar
alias docker=podmansin problemas. - Pods nativos: Podman soporta pods (grupos de contenedores que comparten namespace) de forma nativa, similar a Kubernetes.
- Integración con systemd: Puedes generar archivos de unidad systemd para contenedores con
podman generate systemd.
Comandos básicos de Podman
# Ejecutar un contenedor rootless
podman run -d --name nginx-rootless -p 8080:80 nginx:alpine
# Listar contenedores en ejecución
podman ps
# Construir una imagen desde un Dockerfile
podman build -t mi-app .
# Ejecutar un pod (grupo de contenedores)
podman pod create --name mi-pod -p 3000:3000
podman run --pod mi-pod -d --name app node:18
podman run --pod mi-pod -d --name db postgres:15
[TIP] Si migras desde Docker, usa podman system migrate para convertir imágenes y volúmenes existentes.
Podman en producción: systemd y rootless
Una de las grandes ventajas de Podman es su integración con systemd para gestión de servicios. Puedes generar un archivo de unidad fácilmente:
podman generate systemd --new --name mi-contenedor > /etc/systemd/system/mi-contenedor.service
systemctl daemon-reload
systemctl enable --now mi-contenedor
Esto permite que los contenedores se inicien automáticamente con el sistema, sin necesidad de Docker Compose o orquestadores complejos.
containerd: El runtime de contenedores industrial
¿Qué es containerd?
containerd es un runtime de contenedores de alto nivel, diseñado para ser incrustado en sistemas más grandes. Originalmente extraído de Docker, ahora es un proyecto de la CNCF (Cloud Native Computing Foundation). Se encarga de la gestión del ciclo de vida del contenedor: descarga de imágenes, ejecución, supervisión y redes básicas.
Arquitectura de containerd
containerd actúa como una capa intermedia entre el usuario (o un orquestador como Kubernetes) y el runtime de bajo nivel (como runc). Su arquitectura es modular:
- containerd: El demonio principal que gestiona imágenes, contenedores y snapshots.
- ctr: Cliente CLI para interactuar con containerd (uso básico).
- nerdctl: Cliente compatible con Docker CLI para containerd (recomendado para usuarios).
Instalación y uso básico con nerdctl
# Instalar containerd (ejemplo en Ubuntu)
sudo apt update && sudo apt install containerd
# Configurar containerd (generar config por defecto)
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl restart containerd
# Usar nerdctl (cliente Docker-compatible)
nerdctl run -d --name nginx -p 8080:80 nginx:alpine
nerdctl ps
nerdctl images
[INFO] containerd es el runtime predeterminado en Kubernetes desde la versión 1.24. Si trabajas con clústeres K8s, ya lo estás usando indirectamente.
Ventajas de containerd frente a Docker
- Menor consumo de recursos: containerd es más ligero que el stack completo de Docker (dockerd + containerd + runc).
- Estabilidad: Es el runtime utilizado en entornos de producción masivos (Google, AWS, Azure).
- APIs estandarizadas: Cumple con las especificaciones OCI, lo que facilita la interoperabilidad.
runc: El corazón de la contenerización
¿Qué es runc?
runc es el runtime de contenedores de bajo nivel, también de la CNCF. Es la herramienta que realmente crea y ejecuta los contenedores utilizando las características del kernel de Linux (namespaces, cgroups, seccomp, etc.). Tanto Docker como containerd y Podman utilizan runc por debajo.
Cómo funciona runc
runc no gestiona imágenes ni redes; solo se encarga de la ejecución del contenedor a partir de un bundle OCI (un sistema de archivos raíz y un archivo config.json). El flujo típico es:
- El runtime de alto nivel (containerd, Podman) descarga la imagen y la convierte en un bundle.
- runc lee el bundle y aplica las configuraciones de seguridad y recursos.
- runc crea los namespaces, monta el sistema de archivos y ejecuta el proceso.
Ejemplo básico con runc (sin Docker)
# Crear un bundle OCI mínimo
mkdir mi-contenedor && cd mi-contenedor
mkdir rootfs
# Descargar un sistema de archivos (ejemplo: Alpine)
docker export $(docker create alpine) | tar -C rootfs -xvf -
# Generar config.json (especificaciones del contenedor)
runc spec
# Modificar config.json para ejecutar un comando (ej: /bin/sh)
# (Editar el archivo JSON manualmente)
# Ejecutar el contenedor
sudo runc run mi-contenedor
[WARNING] runc requiere privilegios de root para operar con la configuración por defecto. Para entornos rootless, se necesita configuración adicional (usermode-linux, newuidmap, etc.).
runc y la seguridad: seccomp, capabilities y cgroups
runc permite un control granular de la seguridad mediante:
- seccomp: Filtros de llamadas al sistema.
- Capabilities: Conjunto mínimo de privilegios (ej: CAP_NET_BIND_SERVICE).
- Cgroups: Límites de CPU, memoria y E/S.
Ejemplo en config.json:
"linux": {
"seccomp": {
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{"names": ["write", "read", "exit"], "action": "SCMP_ACT_ALLOW"}
]
},
"capabilities": {
"bounding": ["CAP_NET_BIND_SERVICE"],
"effective": ["CAP_NET_BIND_SERVICE"]
}
}
Comparativa práctica: Podman vs containerd vs runc
| Característica | Podman | containerd | runc |
|---|---|---|---|
| Nivel | Alto (gestor) | Medio (runtime) | Bajo (ejecutor) |
| Requiere demonio | No | Sí (containerd) | No (directo) |
| Rootless nativo | Sí | Parcial (con configuración) | No por defecto |
| Compatibilidad Docker | Alta (alias) | Alta (nerdctl) | Baja (solo bundles) |
| Uso principal | Sustituto Docker | Runtime K8s | Base para otros |
| Orquestación | Pods nativos | A través de K8s | No |
Casos de uso reales
1. Desarrollo local con Podman
Para desarrolladores que quieren evitar el demonio Docker:
# En Fedora/RHEL
sudo dnf install podman
podman run -it --rm ubuntu:22.04 bash
# Construir imágenes con Buildah (herramienta complementaria)
buildah bud -t mi-app .
2. Producción en Kubernetes con containerd
Si gestionas un clúster K8s, containerd es el runtime recomendado:
# En cada nodo del clúster
sudo apt install containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
sudo systemctl restart containerd
# Configurar kubelet para usar containerd
# En /var/lib/kubelet/kubeadm-flags.env:
# --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock
3. Contenedores rootless con Podman en servidores
Para servicios que no requieren root:
# Crear usuario sin privilegios
sudo useradd -m appuser
sudo -u appuser podman run -d --name web -p 8080:80 nginx:alpine
# Habilitar linger para que los contenedores persistan tras logout
sudo loginctl enable-linger appuser
Seguridad: Contenedores rootless como estándar
Una de las mayores críticas a Docker es que, por defecto, el demonio corre como root. Podman y containerd (con configuraciones adecuadas) permiten ejecutar contenedores completamente sin privilegios.
Cómo funcionan los contenedores rootless
- User Namespaces: El usuario del host se mapea a root dentro del contenedor, pero sin privilegios reales fuera.
- Subordinate ID mapping: Se asignan rangos de UIDs/GIDs secundarios (ej: 100000-165535) para el mapeo.
- Slirp4netns: Red virtual sin necesidad de interfaces de red reales.
Configuración de Podman para rootless
# Añadir rangos de subordinados al usuario
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 appuser
# Verificar configuración
podman unshare cat /proc/self/uid_map
# Salida: 0 100000 65536
[INFO] Los contenedores rootless no pueden montar sistemas de archivos del host ni exponer puertos privilegiados (<1024). Para esto último, usa redirección con iptables o un proxy como socat.
Integración con herramientas modernas
Podman Compose
Para quienes extrañan Docker Compose, existe podman-compose (en Python) o la opción nativa de Podman con pods:
# podman-compose.yml
version: '3'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: example
pip install podman-compose
podman-compose up -d
Buildah para imágenes sin Docker
Buildah es la herramienta complementaria de Podman para construir imágenes sin necesidad de un demonio:
buildah from alpine
buildah run alpine-container-working-container apk add nginx
buildah commit alpine-container-working-container mi-nginx
Conclusión: ¿Cuál elegir?
La elección entre Podman, containerd y runc depende del contexto:
- Para desarrollo local y migración desde Docker: Podman es la opción más directa. Su CLI familiar y soporte rootless lo convierten en el reemplazo ideal.
- Para producción en Kubernetes: containerd es el estándar de facto. Ligero, estable y mantenido por la CNCF.
- Para construir tu propio runtime o experimentar: runc te da el control total, pero requiere más configuración.
El ecosistema de contenedores sin Docker no solo es posible, sino que en muchos casos es superior. La modularidad, seguridad y estandarización OCI están impulsando esta transición. Como SysAdmin, conocer estas herramientas te permitirá diseñar infraestructuras más seguras, eficientes y alineadas con las mejores prácticas actuales.
Recuerda: No se trata de abandonar Docker por capricho, sino de elegir la herramienta adecuada para cada trabajo. Y hoy, las alternativas son más maduras que nunca.
