Mascota Jacar — leyendo contigo Un portátil cuyos ojos siguen el cursor mientras lees.
Arquitectura Tecnología

containerd: el runtime que sustenta a Kubernetes

containerd: el runtime que sustenta a Kubernetes

Actualizado: 2026-05-03

containerd[1] es, probablemente, el runtime de contenedores más extendido del planeta, y al mismo tiempo uno de los menos conocidos. Cuando Kubernetes 1.24 consumó la retirada del dockershim en mayo de 2022, miles de clusters acabaron usando containerd como runtime por defecto. Pocos operadores se enteraron — y esa es precisamente la señal de que la migración salió bien: un runtime bien integrado tiene que ser invisible. Este artículo lo hace visible el tiempo suficiente para entender qué corre debajo de cada pod.

Puntos clave

  • containerd gestiona el ciclo de vida completo de un contenedor en un nodo: descargar imagen, crear, arrancar, pausar, parar, montar filesystem y coordinar red con el CNI.
  • La pila en capas (Kubernetes → CRI → containerd → OCI → runc) permite sustituir piezas sin romper nada arriba.
  • Docker ha usado containerd internamente desde 2017; el dockershim era solo un traductor que Kubernetes 1.24 eliminó.
  • containerd domina en cloud (EKS, GKE, AKS); CRI-O es estándar en OpenShift.
  • crictl, ctr y nerdctl son las tres herramientas para operar containerd directamente cuando kubectl no es suficiente.

Qué es containerd y qué no

containerd es un runtime de contenedores de alto nivel. Su responsabilidad es el ciclo de vida completo de un contenedor en una máquina: descargar la imagen desde un registro, almacenarla, crear el contenedor, arrancarlo, pausarlo, pararlo, montar snapshots del filesystem y coordinar los namespaces de red con el CNI del nodo. Todo esto como demonio, sin interfaz gráfica ni experiencia de desarrollador.

Lo que no hace: no construye imágenes (no conoce el Dockerfile), no orquesta (eso le toca a Kubernetes por encima), no compone varios contenedores y no pretende sustituir a una herramienta interactiva tipo Docker CLI.

containerd nació como componente interno de Docker Engine. En marzo de 2017 fue donado a la CNCF; en febrero de 2019 alcanzó la categoría de graduated project. Desde entonces se ha convertido en la base común sobre la que Docker, Kubernetes, BuildKit y muchas otras herramientas construyen.

La pila en capas

Entender containerd requiere ver la pila completa:

Kubernetes (orquestación)
    │
    └── CRI (Container Runtime Interface) — gRPC API
            │
            ▼
        containerd (runtime de alto nivel)
            │
            └── OCI spec → runc (o crun, gVisor, Kata Containers)
                                │
                                └── kernel Linux (namespaces, cgroups, seccomp)

Esta separación permite sustituir piezas sin romper nada más arriba. Puedes cambiar runc por crun (reimplementación en C), por gVisor (sandbox en espacio de usuario para aislamiento fuerte) o por Kata Containers (microVM por contenedor), y Kubernetes no se entera. Puedes cambiar containerd por CRI-O con poco más que un flag de kubelet.

CRI y OCI son los dos contratos que hacen posible ese desacoplamiento.

Dos conceptos internos importantes. Los namespaces de containerd (distintos de los del kernel) son espacios lógicos que separan imágenes y contenedores de distintos consumidores: Kubernetes usa k8s.io, Docker usa moby. Consultar el demonio sin indicar namespace hace que parezca vacío aunque el nodo esté lleno. Los snapshotters montan el filesystem con overlays: el por defecto es overlayfs, con alternativas (btrfs, zfs, stargz para lazy pulling) configurables en el daemon.

containerd y Docker: la relación real

La verdad es que containerd y Docker llevan años siendo la misma cosa por debajo. Docker Engine usa containerd internamente desde 2017: cuando lanzas docker run, Docker construye la spec OCI, llama a containerd por un socket local y containerd invoca runc. El comando es una abstracción conveniente sobre el runtime real.

Por eso los clusters Kubernetes que decían “usar Docker” ya ejecutaban sus contenedores con containerd; el dockershim era un traductor entre CRI y la API de Docker Engine. La retirada del dockershim en Kubernetes 1.24 eliminó esa capa de traducción. Kubernetes habla ahora directamente con containerd (o con CRI-O), sin pasar por Docker Engine. Para un cluster, el cambio fue reconfigurar kubelet y reiniciar nodos. Para un servidor de desarrollo con Docker, nada cambia.

containerd frente a CRI-O

CRI-O[2] es la alternativa más relevante. Nació en Red Hat con un objetivo explícito: un runtime mínimo construido exclusivamente para Kubernetes, sin nada que CRI no requiera.

  • containerd: más general — lo usa Docker, lo usan entornos de desarrollo, lo usa BuildKit y lo usa Kubernetes.
  • CRI-O: más específico — hecho solo para Kubernetes, sin nada extra.

Ambos implementan CRI y OCI, ambos usan runc por defecto y el rendimiento es comparable en benchmarks serios. La elección es más de ecosistema y soporte que de capacidades: containerd domina en upstream Kubernetes y en cloud (EKS, GKE, AKS); CRI-O es estándar en OpenShift y el ecosistema Red Hat.

Operar containerd directamente

En el día a día con Kubernetes no se toca containerd: kubelet se encarga. Cuando algo se rompe en un nodo y kubectl describe no da pistas suficientes, tres herramientas son esenciales:

  • ctr: la CLI nativa de containerd. Cruda y poco amigable, pero permite ver exactamente lo que el demonio tiene.
  • crictl: la herramienta oficial de Kubernetes para depurar runtimes CRI. Habla con containerd por el socket CRI (unix:///run/containerd/containerd.sock) y ofrece subcomandos orientados a pods y contenedores. Configuración en /etc/crictl.yaml.
  • nerdctl[3]: CLI compatible con Docker que ataca containerd directamente. Ver el artículo completo en nerdctl-alternativa-docker.
bash
# Debug típico desde un nodo Kubernetes con containerd
sudo crictl pods --namespace kube-system
sudo crictl ps -a
sudo crictl logs --tail 200 <container-id>
sudo crictl exec -it <container-id> sh
sudo crictl inspecti registry.k8s.io/pause:3.9

# Si echas de menos la sintaxis Docker
sudo nerdctl --namespace k8s.io ps
sudo nerdctl --namespace k8s.io images

# Para ver el estado crudo del demonio
sudo journalctl -u containerd -f

Los cuatro casos donde esto compensa son concretos:

  1. Pod que no arranca y cuyos logs de kubelet no aclaran el motivo — containerd suele tener el detalle en journalctl -u containerd.
  2. Nodo con disco lleno que necesita crictl rmi --prune porque el GC de Kubernetes va lento.
  3. ImagePullBackOff que se resuelve haciendo crictl pull directo para aislar si el problema es de credenciales o de red.
  4. Auditar qué runtime corre cada nodo con kubectl get nodes -o wide.

Configuración habitual

El fichero principal vive en /etc/containerd/config.toml. Los cambios más habituales:

  • Mirrors de registro: para no saturar Docker Hub ni depender de él en producción.
  • Runtimes alternativos: configurar gVisor o Kata Containers para cargas sensibles.
  • Snapshotter: elegir btrfs o zfs si el entorno lo justifica.
  • Cgroup driver a systemd: alinear con kubelet. Este es el error clásico de instalación — kubelet con systemd y containerd con cgroupfs produce reinicios aleatorios de pods difíciles de diagnosticar.

Cualquier cambio en la configuración requiere systemctl restart containerd y, en producción, hacerlo nodo por nodo con cordon y drain. Los patrones de observabilidad de nodo de los que depende el diagnóstico de incidentes en containerd se integran bien con el stack de observabilidad con Grafana.

Conclusión

containerd es la pieza silenciosa sobre la que corre la mayor parte de Kubernetes. Entender su arquitectura no es un capricho académico: es lo que convierte un incidente opaco en uno diagnosticable, lo que permite tomar decisiones informadas sobre runtimes alternativos cuando la seguridad o el aislamiento lo piden, y lo que te deja leer con criterio notas de lanzamiento que hablan de CRI, snapshotters o shims. En operación ordinaria seguirá siendo una capa invisible; el día que toque bajar, hay que saberse el camino.

¿Te ha resultado útil?
[Total: 12 · Media: 4.4]
  1. containerd
  2. CRI-O
  3. nerdctl

Escrito por

CEO - Jacar Systems

Apasionado de la tecnología, la infraestructura cloud y la inteligencia artificial. Escribe sobre DevOps, IA, plataformas y software desde Madrid.