DevOps

Kubernetes en 2026: autoescalado, HPA y gestión de recursos para servicios Go

Ruslan Ismailov Publicado 14 min de lectura
K

Introducción: por qué los servicios Go necesitan una gestión de recursos eficiente en Kubernetes

Go se ha convertido en el lenguaje de facto para escribir microservicios de alto rendimiento. Su runtime compacto, bajo consumo de memoria y arranque rápido hacen que las aplicaciones Go sean candidatas ideales para la orquestación en Kubernetes. Sin embargo, precisamente esa "ligereza" de Go puede convertirse en una trampa: los desarrolladores subestiman la importancia de configurar correctamente los recursos, y el clúster termina sobrecargado o con CPU y memoria sobreasignadas sin uso.

En 2026, Kubernetes sigue evolucionando: la Gateway API alcanzó la estabilidad, los Sidecar Containers pasaron a GA y las capacidades de autoescalado se han enriquecido considerablemente. En este artículo recorreremos el ciclo completo — desde los requests/limits correctos hasta la configuración del HPA con métricas de Prometheus y la elección de la estrategia de despliegue — con manifiestos concretos para una API REST típica en Go.

Configuración de requests y limits para aplicaciones Go: errores comunes y buenas prácticas

Kubernetes utiliza dos parámetros para gestionar los recursos de un pod: requests (recursos garantizados, influyen en la planificación) y limits (techo máximo). Para los servicios Go es fundamental entender cómo el runtime gestiona la memoria y las goroutines.

Errores comunes

  • Limits excesivos con requests demasiado bajos. El planificador ubica el pod en un nodo teniendo en cuenta los requests, pero bajo carga pico el pod consume hasta el límite, lo que genera resource contention e inestabilidad en los pods vecinos.
  • Ausencia de memory limits. El garbage collector de Go puede retener temporalmente grandes volúmenes de memoria. Sin límite, el pod consumirá toda la memoria disponible del nodo.
  • CPU limits con goroutines multinúcleo. Un límite estricto de CPU provoca CPU throttling: el runtime de Go no puede planificar goroutines de forma eficiente. En 2026 se recomienda usar cpuThrottlingPercent de las métricas de cAdvisor para monitorizar este problema.
  • Ignorar GOMAXPROCS. Go ve por defecto todos los vCPU del nodo, no solo los asignados. Usa la librería go.uber.org/automaxprocs para que GOMAXPROCS coincida con el CPU limit.

Buenas prácticas

  • Comienza con pruebas de carga reales (k6, vegeta) y recoge métricas baseline mediante pprof.
  • Establece requests ≈ 70–80% del consumo medio bajo carga y limits ≈ 2× requests para CPU y 1.5× para memoria.
  • Usa la clase QoS Burstable para la mayoría de servicios Go y Guaranteed para componentes sensibles a la latencia.
resources:\n  requests:\n    cpu: "250m"\n    memory: "128Mi"\n  limits:\n    cpu: "500m"\n    memory: "256Mi"

Horizontal Pod Autoscaler: funcionamiento, métricas de CPU y métricas personalizadas

El HPA (Horizontal Pod Autoscaler) es la herramienta principal de autoescalado en Kubernetes para microservicios Go. Consulta periódicamente el Metrics Server (o un adaptador externo) y ajusta el número de réplicas del Deployment según las métricas objetivo.

Algoritmo de funcionamiento del HPA

El controlador HPA calcula cada 15 segundos (por defecto) el número deseado de réplicas con la fórmula:

desiredReplicas = ceil(currentReplicas × (currentMetricValue / desiredMetricValue))

Para evitar el flapping se utiliza stabilizationWindowSeconds — ventana de estabilización (por defecto 300 s para scale-down, 0 para scale-up).

HPA por CPU

Manifiesto básico de HPA v2 para una API REST en Go:

apiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\nmetadata:\n  name: go-api-hpa\n  namespace: production\nspec:\n  scaleTargetRef:\n    apiVersion: apps/v1\n    kind: Deployment\n    name: go-api\n  minReplicas: 2\n  maxReplicas: 20\n  metrics:\n    - type: Resource\n      resource:\n        name: cpu\n        target:\n          type: Utilization\n          averageUtilization: 60\n  behavior:\n    scaleDown:\n      stabilizationWindowSeconds: 120\n      policies:\n        - type: Percent\n          value: 25\n          periodSeconds: 60\n    scaleUp:\n      stabilizationWindowSeconds: 0\n      policies:\n        - type: Pods\n          value: 4\n          periodSeconds: 30

Métricas personalizadas con Prometheus

Para los servicios Go suele ser más útil escalar según métricas de negocio: RPS, profundidad de cola, latencia p99. El stack recomendado es: Prometheusprometheus-adapterCustom Metrics API.

Ejemplo de exportación de métrica en Go:

var httpRequestsTotal = prometheus.NewCounterVec(\n    prometheus.CounterOpts{\n        Name: "http_requests_total",\n        Help: "Total HTTP requests",\n    },\n    []string{"method", "path", "status"},\n)\n\nfunc init() {\n    prometheus.MustRegister(httpRequestsTotal)\n}

Configuración del prometheus-adapter para exponer la métrica RPS:

rules:\n  - seriesQuery: 'http_requests_total{namespace!="",pod!=""}'\n    resources:\n      overrides:\n        namespace: {resource: "namespace"}\n        pod: {resource: "pod"}\n    name:\n      matches: "http_requests_total"\n      as: "http_requests_per_second"\n    metricsQuery: 'rate(http_requests_total{<<.LabelMatchers>>}[2m])'

HPA con métrica personalizada:

metrics:\n  - type: Pods\n    pods:\n      metric:\n        name: http_requests_per_second\n      target:\n        type: AverageValue\n        averageValue: "500"

Vertical Pod Autoscaler y cuándo usarlo en lugar del HPA

El VPA (Vertical Pod Autoscaler) recomienda o establece automáticamente requests/limits óptimos basándose en el consumo histórico. A diferencia del HPA, no añade pods sino que modifica los recursos de los existentes.

Modos de funcionamiento del VPA

  • Off — solo recomendaciones, sin cambios automáticos. Ideal para el perfilado inicial.
  • Initial — establece los recursos únicamente al crear el pod.
  • Auto — recrea los pods con nuevos recursos (provoca downtime, incompatible con PodDisruptionBudget con 1 réplica).

Cuándo usar VPA para servicios Go

  • Tareas batch y CronJobs con consumo de memoria impredecible.
  • Servicios con consumo de memoria en crecimiento continuo (fugas de memoria, cachés).
  • Fase inicial: usa VPA en modo Off para recopilar recomendaciones y luego fija los valores en el manifiesto.

Importante: no se recomienda usar HPA y VPA simultáneamente sobre CPU, ya que provoca conflictos. Combínalos así: HPA por RPS + VPA para memoria en modo Initial.

apiVersion: autoscaling.k8s.io/v1\nkind: VerticalPodAutoscaler\nmetadata:\n  name: go-api-vpa\nspec:\n  targetRef:\n    apiVersion: apps/v1\n    kind: Deployment\n    name: go-api\n  updatePolicy:\n    updateMode: "Off"\n  resourcePolicy:\n    containerPolicies:\n      - containerName: go-api\n        minAllowed:\n          memory: "64Mi"\n        maxAllowed:\n          memory: "512Mi"

Estrategias de despliegue: Rolling Update, Blue-Green y Canary para servicios Go

Rolling Update

Es la estrategia predeterminada en Kubernetes. Los pods se actualizan de forma gradual, sin downtime total. Para los servicios Go es importante configurar correctamente el hook preStop y terminationGracePeriodSeconds para terminar de procesar las peticiones en vuelo.

spec:\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 0\n  template:\n    spec:\n      terminationGracePeriodSeconds: 30\n      containers:\n        - name: go-api\n          lifecycle:\n            preStop:\n              exec:\n                command: ["/bin/sh", "-c", "sleep 5"]

Blue-Green

Dos entornos idénticos (blue — el actual, green — el nuevo). El tráfico se conmuta instantáneamente cambiando el selector del Service. Requiere el doble de recursos, pero garantiza un rollback inmediato.

# Conmutar el tráfico a green\nkubectl patch service go-api-svc \\\n  -p '{"spec":{"selector":{"version":"green"}}}'

Canary

Transferencia gradual del tráfico a la nueva versión. En 2026 se recomienda usar Argo Rollouts o Flagger con análisis automático de métricas de Prometheus para decidir si continuar o hacer rollback.

apiVersion: argoproj.io/v1alpha1\nkind: Rollout\nmetadata:\n  name: go-api-rollout\nspec:\n  strategy:\n    canary:\n      steps:\n        - setWeight: 10\n        - pause: {duration: 5m}\n        - setWeight: 30\n        - pause: {duration: 10m}\n        - setWeight: 100\n      analysis:\n        templates:\n          - templateName: error-rate\n        startingStep: 1

Ejemplo práctico: manifiestos completos de Kubernetes para una API REST en Go

Deployment

apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: go-api\n  namespace: production\n  labels:\n    app: go-api\n    version: v1.5.0\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: go-api\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxSurge: 1\n      maxUnavailable: 0\n  template:\n    metadata:\n      labels:\n        app: go-api\n        version: v1.5.0\n      annotations:\n        prometheus.io/scrape: "true"\n        prometheus.io/port: "8080"\n        prometheus.io/path: "/metrics"\n    spec:\n      terminationGracePeriodSeconds: 30\n      containers:\n        - name: go-api\n          image: registry.example.com/go-api:v1.5.0\n          ports:\n            - containerPort: 8080\n          env:\n            - name: GOMAXPROCS\n              valueFrom:\n                resourceFieldRef:\n                  resource: limits.cpu\n          resources:\n            requests:\n              cpu: "250m"\n              memory: "128Mi"\n            limits:\n              cpu: "500m"\n              memory: "256Mi"\n          readinessProbe:\n            httpGet:\n              path: /healthz/ready\n              port: 8080\n            initialDelaySeconds: 5\n            periodSeconds: 10\n            failureThreshold: 3\n          livenessProbe:\n            httpGet:\n              path: /healthz/live\n              port: 8080\n            initialDelaySeconds: 15\n            periodSeconds: 20\n          lifecycle:\n            preStop:\n              exec:\n                command: ["/bin/sh", "-c", "sleep 5"]

Service y PodDisruptionBudget

apiVersion: v1\nkind: Service\nmetadata:\n  name: go-api-svc\n  namespace: production\nspec:\n  selector:\n    app: go-api\n  ports:\n    - port: 80\n      targetPort: 8080\n  type: ClusterIP\n---\napiVersion: policy/v1\nkind: PodDisruptionBudget\nmetadata:\n  name: go-api-pdb\n  namespace: production\nspec:\n  minAvailable: 2\n  selector:\n    matchLabels:\n      app: go-api

Monitorización y diagnóstico: kubectl top, métricas y logging

Comandos básicos de diagnóstico

# Consumo actual de recursos por pod\nkubectl top pods -n production --sort-by=memory\n\n# Consumo actual de los nodos\nkubectl top nodes\n\n# Ver eventos del HPA\nkubectl describe hpa go-api-hpa -n production\n\n# Historial de escalado\nkubectl get events -n production --field-selector reason=SuccessfulRescale\n\n# Salida detallada de métricas del HPA\nkubectl get hpa go-api-hpa -n production -o yaml

Métricas clave para servicios Go en Prometheus

  • container_cpu_throttled_seconds_total — CPU throttling (crítico, debe estar cerca de 0).
  • container_memory_working_set_bytes — consumo real de memoria (usado para decisiones de OOM).
  • go_goroutines — número de goroutines (fugas de goroutines = incremento de este valor).
  • go_gc_duration_seconds — duración de las pausas del GC.
  • process_resident_memory_bytes — memoria RSS del proceso.

Logging estructurado en Go

Para un logging eficiente en Kubernetes, utiliza el formato JSON estructurado con niveles (slog de la librería estándar de Go 1.21+):

logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{\n    Level: slog.LevelInfo,\n}))\nlogger.Info("request processed",\n    "method", r.Method,\n    "path", r.URL.Path,\n    "duration_ms", time.Since(start).Milliseconds(),\n    "status", statusCode,\n)

Este formato es parseado automáticamente por Loki, Elasticsearch y la mayoría de los agregadores de logs modernos sin configuración adicional.

Conclusión y checklist

La gestión eficiente de recursos y el autoescalado no son una configuración puntual, sino un proceso iterativo. Los servicios Go ofrecen una gran ventaja en rendimiento, pero solo con una configuración correcta del clúster Kubernetes. En 2026, el stack de herramientas se ha estabilizado: HPA v2 con métricas personalizadas, Argo Rollouts para Canary y VPA para perfilado son prácticas contrastadas.

Checklist antes de desplegar un servicio Go en Kubernetes

  1. Los requests y limits están configurados a partir de pruebas de carga reales, no arbitrariamente.
  2. Se usa automaxprocs para establecer correctamente GOMAXPROCS según el CPU limit.
  3. Los readinessProbe y livenessProbe están configurados con umbrales realistas.
  4. Se ha añadido el hook preStop para el graceful shutdown.
  5. Se ha creado un PodDisruptionBudget con minAvailable ≥ 1.
  6. El HPA está configurado con el stabilizationWindowSeconds adecuado para el scale-down.
  7. Las métricas del runtime de Go y las métricas de negocio se exportan a Prometheus.
  8. Se han configurado alertas para CPU throttling y eventos OOMKilled.
  9. Se ha elegido y probado la estrategia de despliegue (Rolling/Canary/Blue-Green).
  10. Los logs están estructurados en formato JSON para una indexación eficiente.

Tecnologías

Etiquetas

Ruslan Ismailov

Desarrollador Senior Web / Backend. Desarrollador senior web/backend con 9 años de experiencia. Stack: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, microservicios, CI/CD. Más sobre mí →