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

Kubernetes 1.31: las estabilizaciones que importan en el día a día

Kubernetes 1.31: las estabilizaciones que importan en el día a día

Actualizado: 2026-05-03

Kubernetes 1.31 se publicó el 13 de agosto de 2024 y es, probablemente, una de las releases más tranquilas de los últimos dos años. No hay ningún titular espectacular, ningún cambio que obligue a reescribir manifiestos, ningún cliente de API rediseñado. Y precisamente por eso merece una lectura detenida: cuando una release no empuja novedades ruidosas, suele estar cerrando deudas antiguas. 1.31 cierra varias, y algunas cambian el día a día de quien opera clústeres mucho más de lo que aparenta.

Puntos clave

  • AppArmor pasa a GA como campo de primera clase en securityContext, eliminando la dependencia de anotaciones.
  • Los sidecars declarados como initContainers con restartPolicy: Always son oficialmente estables — los manifiestos se simplifican y los jobs dejan de colgarse.
  • Dynamic Resource Allocation (DRA) entra en beta: preparar la arquitectura ahora ahorra trabajo cuando llegue el GA en 1.32 o 1.33.
  • Los drivers in-tree de CephFS y CephRBD quedan eliminados — comprobar las storageclass antes de tocar el control plane.
  • El scheduler mejora entre un 5 y un 10 % en benchmarks; clústeres cerca de saturación lo notan.

AppArmor deja de ser una anotación

Durante años, aplicar un perfil de AppArmor a un pod se hacía mediante una anotación en el metadata — una convención heredada del pasado que arrastraba todos los problemas de las anotaciones: sin validación de esquema, sin descubrimiento desde kubectl explain, fácil de olvidar en una copia-pega de Helm. En 1.31, AppArmor pasa a GA como un campo de primera clase dentro de securityContext.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: hardened-web
spec:
  securityContext:
    appArmorProfile:
      type: Localhost
      localhostProfile: restricted-web
  containers:
    - name: app
      image: nginx:1.27

El cambio parece cosmético, pero tiene consecuencias prácticas: los admission webhooks pueden validar el perfil como parte del esquema, las herramientas de políticas (OPA/Gatekeeper, Kyverno) tienen una ruta canónica que inspeccionar, y los equipos de compliance dejan de depender de anotaciones que se pierden en rebases de charts. Para quien ya hace hardening con AppArmor, este cambio consolida lo que hasta ahora era una capa frágil y hace realista forzar un perfil base en todo el clúster sin montar un webhook mutante.

Sidecars reales, al fin

La estabilización más esperada. Hasta 1.29 el patrón sidecar era, literalmente, un hack: un contenedor más dentro del pod, sin garantías de orden de arranque respecto al contenedor principal, sin orden de terminación, y con problemas clásicos cuando el proxy moría antes que la aplicación. La solución comunitaria eran scripts de preStop, shareProcessNamespace, y workarounds específicos por service mesh.

1.31 marca estables los sidecars declarados como initContainers con restartPolicy: Always. Arrancan antes del contenedor principal, se reinician de forma independiente si caen, y terminan después de que el principal haya finalizado. Eso resuelve de un plumazo tres dolores:

  • Service meshes que bloqueaban jobs porque el sidecar seguía vivo.
  • Colectores de logs que perdían los últimos bytes antes del shutdown.
  • Proxies de seguridad que arrancaban tarde y dejaban ventana sin tráfico cubierto.

El impacto operativo es enorme para quien corre Istio, Linkerd, Vector o cualquier colector como sidecar. Los manifiestos se simplifican y desaparece una clase entera de incidentes de turno de noche. Entronca directamente con el análisis que hicimos de Kubernetes 1.28 y el patrón sidecar nativo, donde el feature estaba en alpha: aquel artículo explicaba la motivación; 1.31 es la receta definitiva.

DRA: beta, pero con intención

Dynamic Resource Allocation entra en beta. Sustituye al viejo modelo de device plugins para GPUs, FPGAs y aceleradores varios por una abstracción basada en claims, similar a cómo funcionan los volúmenes persistentes. Un pod declara qué necesita, un driver lo resuelve, el scheduler reconcilia.

Para single-tenant con una sola GPU por nodo, los device plugins seguían funcionando bien; pero en cuanto entras en territorio de sharing, time-slicing de GPUs, o pools heterogéneos, el modelo viejo se quedaba corto. En 1.31 todavía no es apto para producción sin reservas, pero quien esté planificando plataformas de ML o inferencia conviene que lo pruebe en staging ya: el salto a GA en 1.32 o 1.33 obligará a decisiones de arquitectura y es mejor llegar con la forma del API interiorizada.

Lo que se fue

Los drivers in-tree de CephFS y CephRBD quedan eliminados, y gce_pd in-tree queda deprecado. Si alguien sigue usando alguno, la migración a los CSI drivers equivalentes es requisito previo al upgrade. Este tipo de eliminaciones es el que provoca sorpresas: el clúster arranca bien, pero los PVCs antiguos quedan huérfanos y no se sabe hasta que un pod reintenta attach. El workflow seguro es un kubectl get storageclass revisando provisioner, cruzado con los PV activos, antes de tocar el control plane.

El scheduler, más silencioso

Las mejoras de scheduler en 1.31 son incrementales (entre un 5 y un 10 % de throughput en benchmarks propios del proyecto), pero se notan en dos escenarios concretos:

  • Clústeres grandes con muchos pods en Pending esperando hueco.
  • Cargas con preempción activa donde las decisiones de desalojo eran erráticas.

Nada que justifique un upgrade por sí solo, pero sí que explica por qué clústeres cercanos a saturación se sienten más fluidos tras actualizar. Quien mide el coste real de los nodos con Kubecost u OpenCost verá el impacto en utilización tras el salto.

Checklist honesto de upgrade

Antes de subir desde 1.29 o 1.30 conviene cerrar seis cosas:

  1. Informe de deprecaciones limpio en la versión actual.
  2. Backup reciente de etcd verificado con etcdctl snapshot status.
  3. Drenado de nodos respetando los PDB declarados (y comprobando que los PDB no son imposibles de satisfacer).
  4. CSI drivers al día con las matrices de compatibilidad.
  5. Prueba real de los service meshes que se vayan a migrar al nuevo modelo de sidecar.
  6. Canario de al menos un nodo con la nueva kubelet antes de rodar sobre el resto.

El upgrade en sí, con kubeadm, no tiene misterio: kubeadm upgrade plan, kubeadm upgrade apply v1.31.x, y luego kubelet nodo a nodo respetando los drains. Lo que duele no es el comando; es haberse saltado los seis puntos anteriores. Quien combine esto con una estrategia GitOps — como la descrita en GitOps con ArgoCD — puede validar los manifiestos actualizados contra el nuevo API antes de tocar producción.

Conclusión

Kubernetes 1.31 no va a aparecer en las keynotes de ningún evento, y está bien que así sea. Es una release de higiene: saca AppArmor del limbo de las anotaciones, convierte el patrón sidecar en algo que el orquestador entiende de verdad, y deja el camino preparado para que DRA se estabilice sin prisas. Para quien lleva clústeres en producción, la pregunta no es si vale la pena actualizar, sino cuánto antes puede hacerse antes de que el hueco con upstream se ensanche y cada salto empiece a acumular su propia deuda técnica.

¿Te ha resultado útil?
[Total: 12 · Media: 4.4]

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.