Kubernetes en 2026: autoescalado, HPA y gestión de recursos para servicios Go
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
cpuThrottlingPercentde 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/automaxprocspara 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: 30Mé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: Prometheus → prometheus-adapter → Custom 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
Offpara 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: 1Ejemplo 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-apiMonitorizació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 yamlMé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
- Los
requestsylimitsestán configurados a partir de pruebas de carga reales, no arbitrariamente. - Se usa
automaxprocspara establecer correctamente GOMAXPROCS según el CPU limit. - Los
readinessProbeylivenessProbeestán configurados con umbrales realistas. - Se ha añadido el hook
preStoppara el graceful shutdown. - Se ha creado un
PodDisruptionBudgetconminAvailable≥ 1. - El HPA está configurado con el
stabilizationWindowSecondsadecuado para el scale-down. - Las métricas del runtime de Go y las métricas de negocio se exportan a Prometheus.
- Se han configurado alertas para CPU throttling y eventos OOMKilled.
- Se ha elegido y probado la estrategia de despliegue (Rolling/Canary/Blue-Green).
- 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í →