Ahora que ya te he contado cómo desplegar tus pods a través de Jobs, CronJobs, Deployments, ReplicaSets (obvié los ReplicationControllers porque deberían caer en el deuso) y los StatefulSets, para terminar la semana quería mostrarte cómo de sencillo es autoescalar tus aplicaciones dentro de Kubernetes.
HorizontalPodAutoscaler
Para que una aplicación pueda aumentar o disminuir de manera automática sus réplicas necesitas crear un objeto llamado HorizontalPodAutoscaler. Este se encargará de subir y/o bajar el número de réplicas que necesita tu aplicación en cada momento en base a unos umbrales que establezcas.
Para este ejemplo voy a utilizar un despliegue de una página web en ASP.NET Core:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: aspnet
template:
metadata:
labels:
app: aspnet
spec:
containers:
- name: web
image: mcr.microsoft.com/dotnet/core/samples:aspnetapp
resources:
requests:
cpu: "100m"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: aspnet-svc
spec:
type: LoadBalancer
selector:
app: aspnet
ports:
- protocol: TCP
port: 80
targetPort: 80
Esta tiene configurada durante su creación 3 réplicas. Ahora, para crear este objeto la forma más sencilla es a través del comando autoscale:
kubectl autoscale deployment web --cpu-percent=30 --min=1 --max=5
Este recuperará todas las métricas de los pods que componen tu despliegue y hará una operación aritmética para determinar si el número de pods actual es el adecuado, en base al porcentaje establecido para el umbral, en este caso del 30%. Para este ejemplo sólo me estoy basando en el estado de la CPU, pero también es posible combinarlo con la memoria, o solamente basarnos en esta.
El proceso de muestreo no es inmediato sino que se revisan las métricas cada cierto tiempo (por defecto cada 15 segundos). Es por ello que inicialmente el valor de la operación que te contaba aparecerá como unknown y después de unos segundos comenzará a mostrar el valor actual del cálculo realizado:
Giselas-MacBook-Pro:HPA gis$ kubectl get hpa --watch
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web Deployment/web <unknown>/30% 1 5 0 7s
web Deployment/web <unknown>/30% 1 5 3 20s
web Deployment/web 2%/30% 1 5 3 95s
De hecho, si esperas unos minutos comprobarás que de las 3 réplicas que habías establecido se quedará únicamente una al no tener actividad en la web:
Giselas-MacBook-Pro:HPA gis$ kubectl get hpa --watch
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web Deployment/web <unknown>/30% 1 5 0 7s
web Deployment/web <unknown>/30% 1 5 3 20s
web Deployment/web 2%/30% 1 5 3 95s
web Deployment/web 3%/30% 1 5 3 2m36s
web Deployment/web 1%/30% 1 5 3 3m37s
web Deployment/web 1%/30% 1 5 3 5m24s
web Deployment/web 1%/30% 1 5 1 5m39s
Date cuenta de que para que un despliegue pueda autoescalar es necesario indicar los requests de los containers del pod que estableces para el HPA, ya que de lo contrario no funcionará. Te darás cuenta porque en los Eventos del Horizontal Pods Autoscaler aparecerá lo siguiente:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedGetResourceMetric 7s (x2 over 22s) horizontal-pod-autoscaler missing request for cpu
Warning FailedComputeMetricsReplicas 7s (x2 over 22s) horizontal-pod-autoscaler invalid metrics (1 invalid out of 1), first error is: failed to get cpu utilization: missing request for cpu
Ahora que ya tienes una web y un objeto HPA, vamos a intentar que el despliegue llegue hasta las 5 réplicas que tiene establecidas como máximo, haciendo que la CPU de los pods se dispare. Antes de ello, vigila en dos terminales separados lo siguiente:
#Terminal 1
kubectl get hpa --watch
#Terminal 2
kubectl get deployment --watch
Para estresar mis pods voy a utilizar Apache Benchmark con el siguiente comando:
ab -n 50000 -c 200 http://IP_DEL_ASPNET_SVC/
Como ves, le he pedido 50.000 peticiones simulando 200 usuarios concurrentes. Igual me he pasado un poco 😛 pero tendrás tiempo más que de sobra para ver cómo se comporta el autoescalado:
Giselas-MacBook-Pro:HPA gis$ kubectl get hpa --watch
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
web Deployment/web <unknown>/30% 1 5 0 7s
web Deployment/web <unknown>/30% 1 5 3 20s
web Deployment/web 2%/30% 1 5 3 95s
web Deployment/web 3%/30% 1 5 3 2m36s
web Deployment/web 1%/30% 1 5 3 3m37s
web Deployment/web 1%/30% 1 5 3 5m24s
web Deployment/web 1%/30% 1 5 1 5m39s
web Deployment/web 2%/30% 1 5 1 6m40s
web Deployment/web 1%/30% 1 5 1 7m41s
web Deployment/web 2%/30% 1 5 1 8m41s
web Deployment/web 366%/30% 1 5 1 9m42s
web Deployment/web 366%/30% 1 5 4 9m58s
web Deployment/web 366%/30% 1 5 5 10m
web Deployment/web 50%/30% 1 5 5 10m
web Deployment/web 65%/30% 1 5 5 11m
web Deployment/web 62%/30% 1 5 5 12m
web Deployment/web 1%/30% 1 5 5 13m
web Deployment/web 1%/30% 1 5 5 18m
web Deployment/web 1%/30% 1 5 1 18m
También verás cómo el deployment ha ido ajustando el número de réplicas según la CPU iba aumentando o disminuyendo para tus pods:
Giselas-MacBook-Pro:HPA gis$ kubectl get deployment --watch
NAME READY UP-TO-DATE AVAILABLE AGE
web 0/3 3 0 17s
web 1/3 3 1 24s
web 2/3 3 2 25s
web 3/3 3 3 26s
web 3/1 3 3 5m28s
web 3/1 3 3 5m28s
web 1/1 1 1 5m28s
web 1/4 1 1 9m46s
web 1/4 1 1 9m46s
web 1/4 1 1 9m46s
web 1/4 4 1 9m47s
web 2/4 4 2 9m49s
web 3/4 4 3 9m49s
web 4/4 4 4 9m49s
web 4/5 4 4 10m
web 4/5 4 4 10m
web 4/5 4 4 10m
web 4/5 5 4 10m
web 5/5 5 5 10m
web 5/1 5 5 18m
web 5/1 5 5 18m
web 1/1 1 1 18m
Por último si revisas los eventos del HorizontalPodAutoscaler:
kubectl describe hpa web
Podrás comprobar todas las subidas y bajas que ha tenido que realizar en base a las métricas recibidas de tus pods:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedGetResourceMetric 19m (x5 over 20m) horizontal-pod-autoscaler unable to get metrics for resource cpu: no metrics returned from resource metrics API
Warning FailedComputeMetricsReplicas 19m (x5 over 20m) horizontal-pod-autoscaler invalid metrics (1 invalid out of 1), first error is: failed to get cpu utilization: unable to get metrics for resource cpu: no metrics returned from resource metrics API
Normal SuccessfulRescale 11m horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 10m horizontal-pod-autoscaler New size: 5; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 2m7s (x2 over 15m) horizontal-pod-autoscaler New size: 1; reason: All metrics below target
Si bien todo esto nos permite gestionar picos de manera automatizada, la versión estable, a día de hoy, de los HorizontalPodAutoscaler solo se puede basar en las métricas CPU y memoria. En muchos escenarios son más que suficientes pero en otros se requiere vigilar algo más. Por ejemplo, si tu aplicación es más propensa a tener cuellos de botella en la red, más que en la CPU o en la memoria, seguramente te interese valorar otras métricas. Por otro lado, también puede ocurrir que necesites tener en cuenta servicios externos, como pueden ser colas de mensajerías.
A partir de Kubernetes 1.6 se añade soporte para hacer uso de métricas personalizadas y externas a través de la versión autoscaling/v2beta2. En un próximo artículo te mostraré cómo hacerlo.
¡Saludos!

Bootcamp DevOps
Si tienes ganas de meterte en el área de DevOps, formo parte del
equipo de docentes del Bootcamp DevOps Lemoncode, ¿Te animas a
aprender con nosotros?