Ya te he contado en varios artículos cómo puedes hacer para que tus aplicaciones crezcan de un modo u otro, utilizando HorizontalPodAutoscaler, KEDA o desbordando con Virtual Kubelet. Una de las opciones que me quedaba por explorar era cómo autoescalar los pods verticalmente gracias al recurso VerticalPodAutoscaler.
En el artículo «Administrar los recursos para tus contenedores en Kubernetes» te contaba que es buena práctica especificar por cada contenedor cuántos son los recursos que este va a necesitar. El problema es que normalmente no es un dato fácil de estimar, ya que normalmente solo es posible conseguirlo a base de monitorizar tu aplicación a lo largo del tiempo. Aquí es donde entra en juego VPA, quien hace este trabajo por ti.
Instalación de VPA en tu clúster
A día de hoy este recurso no está por defecto instalado en los clústeres de Kubernetes. Para este ejemplo voy a utilizar Azure Kubernetes Service, aunque se pueden seguir estos mismos pasos para cualquier otro.
#Login on Azure
az login
#Variables
RESOURCE_GROUP="VPA-AKS"
AKS_NAME="vpa-aks"
#Get AKS context
az aks get-credentials -g $RESOURCE_GROUP -n $AKS_NAME
#Clone autoscaler repository
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
#Install VerticalPodAutoscaler
./hack/vpa-up.sh
En el código anterior, específicamente para Azure, inicio sesión en la plataforma y recupero las credenciales del clúster donde quiero instalar VPA. Clono el proyecto kubernetes/autoscaler, donde está incluido el script vpa-up.sh, que da de alta todos los recursos necesarios para dejar mi clúster listo.
¿Cómo pruebo el escalado vertical?
Ahora que ya tienes todo preparado, lo siguiente es entender cómo funciona este recurso. Para ello, voy a crear un despliegue tan sencillo como el que sigue:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx
El objetivo es que los contenedores de web-deployment ajusten de manera automática el apartado requests que, como ves, en este ejemplo no están ni especificados. Para ello, debes crear un VPA asociado a este despliegue:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: web-deployment
updatePolicy:
updateMode: "Auto"
En este ejemplo he puesto el modo automático, el cual no solo nos mostrará las recomendaciones para nuestros contenedores sino que además aplicará las mismas:
➜ VPA kubectl get vpa web-vpa -o yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"autoscaling.k8s.io/v1","kind":"VerticalPodAutoscaler","metadata":{"annotations":{},"name":"web-vpa","namespace":"default"},"spec":{"targetRef":{"apiVersion":"apps/v1","kind":"Deployment","name":"web-deployment"},"updatePolicy":{"updateMode":"Auto"}}}
creationTimestamp: "2020-07-25T06:35:07Z"
generation: 24
name: web-vpa
namespace: default
resourceVersion: "175400"
selfLink: /apis/autoscaling.k8s.io/v1/namespaces/default/verticalpodautoscalers/web-vpa
uid: 3403142a-4d8c-4317-a60a-c958e97f4660
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web-deployment
updatePolicy:
updateMode: Auto
status:
conditions:
- lastTransitionTime: "2020-07-25T06:36:10Z"
status: "True"
type: RecommendationProvided
recommendation:
containerRecommendations:
- containerName: web
lowerBound:
cpu: 25m
memory: 262144k
target:
cpu: 25m
memory: 262144k
uncappedTarget:
cpu: 25m
memory: 262144k
upperBound:
cpu: 799m
memory: "836064315"
Hay que tener cuidado con esto ya que cada vez que VPA intente hacer un ajuste recreará los contenedores del pod. También es importante que sepas que, sino pones ningún máximo en tu VPA, este modo puede hacer que algunos pods se queden en estado pendiente por no tener suficiente espacio.

Para que esto no ocurra, puedes modificar su definición, añadiendo el apartado containerPolicies > maxAllowed:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: web-deployment
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: '*'
maxAllowed:
cpu: 50m
memory: 10m
En este caso he puesto un asterisco para que estos máximos apliquen a todos los contenedores, pero podría especificarlos de forma individual si fuera necesario.
También es posible recibir únicamente las recomendaciones, sin que estas se apliquen, poniendo a updateMode el valor Off y aplicar estas de manera manual.
Otra de las cosas que te pueden interesar es excluir del autoajuste a alguno de los contenedores de tu pod. Podría añadir un segundo contenedor a mi despliegue:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx
- name: cache
image: redis
Y en el VPA indicar que el contenedor cache queda deshabilitado para el ajuste:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: web-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: web-deployment
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: '*'
maxAllowed:
cpu: 50m
memory: 10m
- containerName: cache
mode: "Off"
¡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?