Kubernetes Kubernetes

Mantén sanas las cargas de trabajo: namespaces, recursos, cuotas y probes

Comparte un clúster de forma justa con requests, limits y cuotas, y deja que Kubernetes detecte los contenedores no saludables.

15 min Intermedio

Un clúster es un pool compartido de CPU y memoria. Sin protecciones, una carga de trabajo voraz puede dejar sin recursos a sus vecinas, y una aplicación colgada puede seguir recibiendo tráfico. Esta guía cubre las herramientas para ambos casos: namespaces y cuotas para dividir el pool, requests y limits para describir lo que necesita cada contenedor, y probes para que Kubernetes pueda saber cuándo un contenedor no está sano.

Divide un clúster con namespaces

Los namespaces dividen un clúster en áreas separadas para equipos, aplicaciones o entornos:

kubectl create namespace demo
kubectl get pods -n demo
kubectl config set-context --current --namespace=demo
kubectl get pods -A

Tus objetos van a default a menos que indiques otra cosa, usando -n NAME en un comando o metadata.namespace en un manifiesto. Los componentes propios del clúster viven en kube-system. La mayoría de los objetos tienen namespace (Pods, Services, ConfigMaps, Secrets), mientras que algunos, como los nodos y los PersistentVolumes, son de ámbito de clúster. Los namespaces son la unidad a la que se asocian las cuotas y las reglas de acceso, pero por sí solos son un límite organizativo, no uno de seguridad fuerte. Una sorpresa común es un Pod que parece haber desaparecido, cuando en realidad lo creaste en otro namespace. Compruébalo con kubectl get pods -A.

Define requests y limits

Cada contenedor puede declarar lo que necesita y lo máximo que puede usar:

spec:
  containers:
    - name: web
      image: nginx:1.25
      resources:
        requests:
          cpu: 250m
          memory: 64Mi
        limits:
          cpu: 500m
          memory: 128Mi
  • Requests es lo que reserva el scheduler. Un Pod solo se coloca en un nodo con esa cantidad sin reclamar, y al contenedor se le garantiza al menos esto.
  • Limits es un techo rígido. Un contenedor que intenta usar más CPU es limitado (throttled). Uno que supera su límite de memoria es terminado (OOMKilled) y reiniciado.

La CPU se mide en núcleos, donde 1000m (milicores) es un núcleo completo, así que 250m es un cuarto de uno. Un limit no puede ser menor que su request. Ambos se definen por contenedor, no por Pod.

Observa el uso con el metrics server

kubectl top informa del uso en vivo, pero necesita el metrics server, que a muchos clústeres recién creados les falta. Sin él verás “Metrics API not available”. En minikube:

minikube addons enable metrics-server
kubectl top nodes
kubectl top pods -A

En otros clústeres, instala metrics-server desde su página del proyecto. Es una forma rápida de detectar qué Pods usan más recursos.

Aplica un presupuesto con ResourceQuota y LimitRange

Un ResourceQuota limita el total que un namespace puede solicitar o usar:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: demo-quota
  namespace: demo
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
    pods: "10"

kubectl describe resourcequota -n demo muestra lo usado frente a cada límite. Cuando el total se superaría, los Pods nuevos se rechazan en la creación con un error de “exceeded quota”. Cuando una cuota cubre CPU o memoria, todo Pod de ese namespace también debe declarar esos requests y limits, o se rechaza. Un LimitRange lo evita proporcionando valores predeterminados para los contenedores que no definen los suyos:

apiVersion: v1
kind: LimitRange
metadata:
  name: container-defaults
  namespace: demo
spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: 100m
        memory: 64Mi
      default:
        cpu: 250m
        memory: 128Mi

Añade readiness y liveness probes

Un contenedor en ejecución no es necesariamente un contenedor que funciona. Las probes permiten a Kubernetes comprobarlo:

  • Una readiness probe decide si el contenedor debe recibir tráfico. Cuando falla, el Pod se retira de los endpoints de sus Services pero no se reinicia. Úsala para arranques lentos o sobrecargas temporales.
  • Una liveness probe decide si el contenedor sigue vivo. Tras suficientes fallos consecutivos, el kubelet reinicia el contenedor.
  • Una startup probe retrasa las otras dos mientras una aplicación lenta arranca.
spec:
  containers:
    - name: web
      image: nginx:1.25
      readinessProbe:
        httpGet:
          path: /
          port: 80
        initialDelaySeconds: 2
        periodSeconds: 5
        timeoutSeconds: 1
        failureThreshold: 3
      livenessProbe:
        httpGet:
          path: /
          port: 80
        initialDelaySeconds: 10
        periodSeconds: 10
        failureThreshold: 3

Los campos de temporización funcionan igual para todas las probes. initialDelaySeconds es cuánto esperar tras arrancar el contenedor antes de la primera comprobación, periodSeconds es cada cuánto comprobar, timeoutSeconds es cuánto esperar una respuesta y failureThreshold es cuántos fallos consecutivos cuentan como fallo. Además de peticiones HTTP, las probes pueden abrir una conexión TCP (tcpSocket), ejecutar un comando dentro del contenedor (exec) o usar gRPC.

Mantén las comprobaciones de liveness simples y centradas en el proceso en sí. Si una liveness probe falla porque una base de datos está caída, Kubernetes reinicia contenedores de aplicación sanos para nada y puede empeorar una interrupción. Una readiness probe es el lugar adecuado para reflejar las dependencias. La readiness también guía los rolling updates: los Pods nuevos solo cuentan como disponibles una vez que están listos.

Puedes ver los resultados de las probes en kubectl describe pod, donde los fallos aparecen en los eventos, y en kubectl get pods, donde una readiness probe fallida se muestra como 0/1 en la columna READY.

Guías populares