containerd 2.0 se publicó el 5 de noviembre de 2024 y hemos tenido seis meses para ver cómo se comporta en despliegues reales, según las notas oficiales de la versión 2.0[1]. La 1.7 sigue en soporte extendido, pero la rama 1.6 lleva desde 2023 sin recibir soporte activo, con la ventana de soporte extendido cerrándose en agosto de 2025. Ese cierre obliga a los equipos que siguen en esa rama a plantear el salto, según la política de soporte de containerd[2]. En este tiempo han aparecido suficientes informes para hacer una lectura honesta: qué se rompe, qué mejora y cuándo compensa planificar la migración.

Puntos clave

  • El mayor motor para saltar es que la 1.6 ya no tiene soporte, no que la 2.0 traiga funcionalidades imprescindibles.

  • CRI v1alpha2 se elimina: hay que actualizar kubelet a 1.26+ antes de migrar en clusters Kubernetes.

  • El formato del archivo de configuración cambia: version = 3 en lugar de version = 2.

  • Schema 1 de imágenes OCI se retira: imágenes construidas antes de 2017 pueden no ejecutarse.

  • La migración en Docker Swarm es más suave que en Kubernetes porque Swarm no depende de CRI.

  • Las métricas clave durante la migración son: contenedores activos, ratio de pull fallidos, latencia de la API de tasks y errores de shim.

Qué trae 2.0 que justifique la migración

Dejando a un lado la limpieza interna, cuatro cosas aportan valor operativo concreto:

  • Soporte nativo de sandboxes. Kata Containers y Firecracker pueden integrarse como runtimes vía la API de sandbox sin necesidad de shims externos. Para equipos que evalúan aislamiento reforzado esto reduce el número de piezas móviles en el stack. Conecta directamente con lo que describimos en Firecracker: microVMs para servicios multi-tenant.

  • CRI v1 estable y v1alpha2 retirado. Kubernetes 1.26 en adelante usa CRI v1 por defecto. containerd 2.0 elimina la implementación de v1alpha2, lo cual simplifica el código pero rompe compatibilidad con kubelet anteriores a 1.26.

  • Mejoras en el runtime shim. El shim de runc se refactorizó y consume menos memoria por contenedor. En un host con cientos de contenedores el ahorro es perceptible: del orden de decenas de megabytes menos de overhead total.

  • NRI como API de plugins estable. El Node Resource Interface, antes experimental, es ahora la interfaz oficial para integrar CNI custom, device plugins y agentes de seguridad.

Lo que se rompe al migrar

Casi nunca es una actualización drop-in. Hay al menos cinco puntos donde hay que tocar configuración o scripts:

  • Formato del archivo de configuración. La cláusula version = 2 deja de reconocerse; hay que declarar version = 3 en /etc/containerd/config.toml. Scripts de Ansible o Puppet que inyectan configuración deben ajustar la plantilla. containerd 2.0 convierte automáticamente la versión 2 pero emite aviso, y la 2.1 planea retirar la conversión automática.

  • Plugins desregistrados. Hay plugins del tipo io.containerd.grpc.v1.introspection que cambiaron de namespace o nombre. Si hay integraciones externas que hacen introspección de plugins, hay que revisar.

  • Soporte de Schema 1 de imágenes OCI retirado. Imágenes viejas construidas antes de 2017 pueden ser Schema 1 y containerd 2.0 no las ejecuta. Los registros modernos convierten al hacer pull, pero si hay imágenes en registros privados antiguos hay que reempaquetarlas.

  • Comportamiento de ctr en contenedores compartidos entre namespaces. Algunos comandos que antes trabajaban silenciosamente across namespaces ahora piden el namespace explícito. Los scripts que usaban ctr sin --namespace fallan con errores claros, pero si esos scripts corren en cron o CI hay que adaptarlos.

  • Deprecación de CNI 0.x. containerd 2.0 requiere plugins CNI 1.0 o superior. Si el cluster tiene Calico 3.17 o Flannel pre-0.20, hay que actualizarlos.

El caso de Docker Swarm

Para quien aún opera Swarm, la migración es más suave que en Kubernetes porque Swarm no depende de CRI. Lo que importa aquí no es que Docker Engine traiga containerd 2.0 de fábrica, sino cómo está conectado al containerd del sistema.

Conviene aclarar un matiz que generó confusión en el equipo. Docker Engine sigue empaquetando su propio containerd estático, y esa copia se quedó en la rama 1.7.x durante la serie 27.x, según las notas de versión de Docker Engine 27[3]. Lo que sí funciona, y es lo que hicimos, es apuntar Docker Engine al containerd del sistema mediante el socket estándar (/run/containerd/containerd.sock). Ahí es donde lo deja el paquete de Debian.

En ese escenario Docker Engine habla con containerd por la API gRPC estándar y no le importa si la versión es 1.7 o 2.0 mientras el socket responda. El orden que seguimos fue:

  • Actualizar containerd de 1.7 a 2.0 en el sistema.

  • Reiniciar containerd.service.

  • Verificar ctr version y que los contenedores existentes seguían corriendo.

  • Verificar que Docker Engine, sin tocar su propia versión, seguía operando con normalidad contra el containerd del sistema.

No hubo caídas de contenedores, pero dos imágenes tuvieron que reconstruirse porque eran Schema 1.

Observabilidad durante la migración

Algo que aprendí a la fuerza en una migración anterior: el containerd por defecto no emite métricas Prometheus sin configurarlo. Antes de migrar hay que asegurarse de que metrics.address = "0.0.0.0:1338" está en la config y de que el exporter está scrapeado. Sin eso, la única señal de que algo va mal es que los contenedores mueren.

Las métricas clave a vigilar durante y después de la migración son:

  • Contador de contenedores activos.

  • Ratio de pull fallidos.

  • Latencia de la API de tasks.

  • Errores de shim.

Con esas cuatro señales cubiertas, una migración que va mal se detecta en minutos en vez de horas. El mismo principio de observabilidad antes de actuar aplica a la gestión de operaciones en Kubernetes 1.32.

Mi lectura

containerd 2.0 es una migración obligatoria pero no urgente si no hay presión regulatoria. El mayor motor para saltar es que la 1.6 ya no tiene soporte activo. Si el cluster está en 1.7 y no hay presión regulatoria, el salto directo a la 2.1 suele ser más seguro que quedarse en la primera oleada de la 2.0. Esa versión ya se publicó en mayo de 2025, con los primeros parches de estabilización.

Lo que me parece más positivo del release es la limpieza. Retirar CRI v1alpha2 y el soporte de Schema 1 de OCI, documentado en la guía oficial de cambios de containerd 2.0[4], son decisiones que la comunidad llevaba posponiendo años. Pagarán dividendos en mantenibilidad futura. El requisito de CRI v1 también está confirmado en la documentación de arquitectura CRI de Kubernetes[5]: desde la 1.26, el kubelet exige la API v1 para registrar el nodo.

Mi recomendación práctica:

  • Si operas Kubernetes: revisa el kubelet de todos los nodos antes de tocar nada, actualiza Calico o el CNI que uses a 1.0 y ten una ventana de mantenimiento con plan de reversión.

  • Si operas Swarm: más sencillo pero vigila las imágenes antiguas.

  • Si operas docker puro sin Swarm ni Kubernetes: la migración es casi transparente siempre que mantengas separado el ciclo de vida del containerd del sistema y el de Docker Engine.

Este artículo también está disponible en inglés: containerd 2.0 in production: real migrations.

Fuentes:

  1. containerd: notas de la versión 2.0.0[1]
  2. containerd: política de versionado y soporte[2]
  3. containerd: guía oficial de cambios en la 2.0[4]
  4. Docker Engine: notas de la versión 27[3]
  5. Kubernetes: arquitectura del Container Runtime Interface[5]

Preguntas frecuentes

¿Puedo actualizar a containerd 2.0 si mi kubelet es anterior a Kubernetes 1.26?

No sin actualizar kubelet primero: containerd 2.0 elimina la implementación de CRI v1alpha2 y solo ofrece CRI v1, que kubelet usa por defecto desde la 1.26 y exige para registrar el nodo. Antes de tocar nada, revisa la versión de kubelet en todos los nodos. Actualiza el CNI a plugins 1.0 o superior (Calico 3.17 o Flannel anterior a 0.20 no sirven) y reserva una ventana de mantenimiento con plan de reversión. Si estás en 1.7 sin presión, saltar a la 2.1 de mayo de 2025 suele ser más seguro.

¿Qué hay que cambiar en `/etc/containerd/config.toml` al pasar a la 2.0?

Declarar version = 3 en lugar de version = 2, y ajustar las plantillas de Ansible o Puppet que inyectan esa configuración. En containerd 2.0 la versión 2 se convierte automáticamente con un aviso, pero la 2.1 planea retirar esa conversión. Conviene también añadir metrics.address = "0.0.0.0:1338" y scrapear el exporter, porque por defecto containerd no emite métricas Prometheus y sin ellas la única señal de fallo es que los contenedores mueren. Los scripts con ctr sin --namespace fallarán y hay que adaptarlos.

¿Afecta containerd 2.0 a un servidor con Docker Engine o Docker Swarm?

Menos que a Kubernetes, porque Swarm no depende de CRI: Docker Engine sigue empaquetando su propio containerd estático en la rama 1.7.x durante toda la serie 27.x. Lo que funciona es apuntar Docker Engine al containerd del sistema por el socket /run/containerd/containerd.sock: habla gRPC estándar y no le importa si responde la 1.7 o la 2.0. El orden fue actualizar containerd, reiniciar containerd.service, verificar ctr version y comprobar Docker. No cayó ningún contenedor, pero dos imágenes Schema 1 tuvieron que reconstruirse.

Fuentes

  1. notas oficiales de la versión 2.0
  2. política de soporte de containerd
  3. notas de versión de Docker Engine 27
  4. guía oficial de cambios de containerd 2.0
  5. documentación de arquitectura CRI de Kubernetes