DEV Community

Cover image for Kubernetes resources
Coles C
Coles C

Posted on

Kubernetes resources

En Kubernetes, hay configuraciones que parecen pequeñas, pero tienen un impacto enorme en operación. Una de las más importantes es resources.

Muchos equipos la rellenan al final, copiando valores de otro deployment o usando números “razonables” sin validar nada. El problema es que Kubernetes sí se toma esos valores muy en serio. A partir de ahí decide dónde ubicar un pod, cuánto puede consumir y cómo se comporta el nodo cuando hay presión de recursos.

Por eso, cuando resources está mal definido, los síntomas aparecen rápido: pods en Pending, reinicios por OOMKilled, CPU throttling, degradación bajo carga o incluso Evicted en procesos con alto uso de almacenamiento temporal.

Qué estás definiendo realmente

Cuando declaras algo como esto:

resources:
  requests:
    cpu: "250m"
    memory: "256Mi"
  limits:
    cpu: "500m"
    memory: "512Mi"
Enter fullscreen mode Exit fullscreen mode

no estás simplemente completando un bloque del manifiesto. Le estás diciendo a Kubernetes dos cosas clave:

  • requests: lo mínimo que el contenedor necesita para que el scheduler lo coloque en un nodo.
  • limits: el máximo que ese contenedor puede llegar a consumir.

La diferencia importa mucho. Los requests afectan la planificación. Los limits afectan el comportamiento en tiempo de ejecución.

Si defines mal uno de los dos, el clúster empieza a tomar decisiones basadas en una realidad que no existe.

El error clásico: definir recursos a ojo

Este es uno de los errores más comunes en entornos reales. Se asignan valores porque “seguro con esto alcanza”, porque otro servicio usa algo parecido o porque interesa que el pod entre rápido en el nodo.

Ahí empiezan los problemas.

Si el request es demasiado alto, el pod puede quedarse en Pending porque ningún nodo tiene capacidad suficiente. Si es demasiado bajo, Kubernetes coloca más carga de la que el nodo realmente puede soportar. Si el limit es demasiado agresivo, el contenedor se vuelve inestable cuando aumenta el consumo. Y si no hay limits, una aplicación puede crecer sin control y afectar al resto de workloads.

Lo más peligroso es que muchas veces esto no explota al desplegar. Explota después, en producción, cuando llega tráfico, concurrencia o una ejecución inesperada.

Un ejemplo muy común en producción

Supongamos una API desplegada con esta configuración:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: orders-api
  template:
    metadata:
      labels:
        app: orders-api
    spec:
      containers:
        - name: orders-api
          image: registry.example.com/orders-api:1.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "200m"
              memory: "256Mi"
Enter fullscreen mode Exit fullscreen mode

En el papel, parece una configuración eficiente. Pero en la práctica, la aplicación arranca consumiendo entre 300 y 400 MiB y, en picos, supera 500 MiB.

¿Qué ocurre entonces?

Kubernetes planifica el pod pensando que necesita solo 128Mi de memoria. El nodo acepta más pods de los que realmente puede soportar. Cuando la aplicación entra en carga y supera el limit de 256Mi, el proceso termina en OOMKilled. El pod reinicia, sube la latencia, fallan peticiones y el equipo empieza a investigar la aplicación cuando, en realidad, el primer problema estaba en el manifiesto.

Una configuración más alineada con el comportamiento real podría ser esta:

resources:
  requests:
    cpu: "300m"
    memory: "512Mi"
  limits:
    cpu: "1000m"
    memory: "768Mi"
Enter fullscreen mode Exit fullscreen mode

Aquí el scheduler trabaja con una reserva más realista, el nodo no se sobrecarga tan fácilmente y la aplicación tiene margen para absorber picos sin colapsar.

El recurso que muchos olvidan: ephemeral-storage

En entornos DevOps hay otro punto que suele pasarse por alto: ephemeral-storage.

Esto aparece mucho en pipelines de Jenkins sobre Kubernetes, builds con Kaniko, procesos batch, cargas temporales o contenedores que generan archivos intermedios. Aunque CPU y memoria estén bien definidas, un uso elevado de disco efímero puede hacer que el pod termine en Evicted.

Ejemplo:

resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
    ephemeral-storage: "1Gi"
  limits:
    cpu: "1000m"
    memory: "1Gi"
    ephemeral-storage: "2Gi"
Enter fullscreen mode Exit fullscreen mode

Si tu workload descarga artefactos, genera cachés o escribe mucho en /tmp, ignorar este recurso puede convertirse en un problema operativo serio.

Cómo definir resources de forma correcta

La respuesta no está en adivinar mejor. Está en medir.

La forma sana de trabajar esto es observar el consumo real de la aplicación, entender su comportamiento base y sus picos, y ajustar a partir de datos. Los requests deberían acercarse al uso normal. Los limits deberían dejar margen, pero sin caer en valores exagerados que falseen la capacidad del clúster.

Bien definidos, los resources mejoran el scheduling, hacen más predecible el autoscaling, reducen reinicios innecesarios y ayudan a usar mejor la infraestructura. Mal definidos, convierten el clúster en una fuente constante de síntomas difíciles de interpretar.

Conclusión

resources no es un bloque decorativo del YAML. Es una de las decisiones más importantes que tomas sobre cómo va a vivir tu aplicación dentro de Kubernetes.

Cuando está bien configurado, aporta estabilidad, previsibilidad y control. Cuando está mal, aparecen errores que parecen de aplicación, pero en realidad son de operación.

En Kubernetes, muchas veces el problema no es que falten recursos. El problema es no haber descrito bien cuántos necesitaba de verdad tu workload.

Top comments (0)