BLOGS
Avisi is een Atlassian Specialized Partner in Cloud! ☁️
Blogs Door Özge Özdes / nov 2022 / 1 Min
Blogs
Door Thomas Kooi / jan 2022 / 6 min
Met Kubernetes kunnen applicaties op 100% geautomatiseerde wijze beheerd worden. Eén van de handige functies in Kubernetes is het concept van horizontaal autoscaling van applicaties. In deze blog gaan we dieper in op de manieren waarop jij autoscaling kan implementeren én waar je goed op moet letten. Deze blog bestaat uit twee delen, dit is deel één. Klik hier voor deel twee waarin de focus ligt op autoscaling met ingress-nginx en Linkerd.
Autoscaling kan ingezet worden om resources efficiënter in te zetten door gebruik te maken van minder VM's, zoals bijvoorbeeld tijdens piektijden. Als je handmatig op piektijden moet inspelen, dan ben je vaak te langzaam waardoor er niet optijd genoeg capaciteit is en applicaties langzamer zullen werken. Dit kan ervoor zorgen dat jouw applicaties onbeschikbaar of bruikbaar worden! Maar wanneer is autoscaling niet relevant? Autoscaling is niet relevant op het moment dat je een statisch, voorspelbaar applicatielandschap hebt, omdat het dan weinig toegevoegde waarde heeft. Je applicatie zal namelijk stabiel blijven.
💡 Maak je gebruik van een AME Kubernetes-cluster, dan is autoscaling standaard ondersteund.
Om autoscaling toe te kunnen passen, is ondersteuning voor de metrics-API in je cluster vereist. De meeste managed Kubernetes-providers ondersteunen dit, zonder dat hier een aanpassing voor gedaan hoeft te worden. De meestvoorkomende implementatie is de metrics-server. Via kubectl top node kun je valideren of jouw cluster de metrics-api ondersteunt.
$ kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-10-0-0-7.eu-west-1.compute.internal 100m 5% 1781Mi 51%
ip-10-0-0-92.eu-west-1.compute.internal 162m 8% 1927Mi 56%
Indien de metrics-API niet beschikbaar is binnen je cluster, kan je deze zelf makkelijk installeren middels kubectl:
$ kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
Ook zijn er opties voor meer geavanceerde set-ups, die custom metrics ondersteunen. In deel 2 van de blog gaan we hier dieper op in.
Autoscaling wordt geconfigureerd met een resource genaamd HorizontalPodAutoscaler (HPA) in Kubernetes. HPA biedt ondersteuning voor zowel Deployments als StatefulSets.
Als voorbeeld beginnen wij met het installeren van een nieuwe Deployment, genaamd myapp (example.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: default
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx
resources:
limits:
memory: "128Mi"
cpu: "100m"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 80
We installeren deze resources uit de example.yaml via kubectl apply:
$ kubectl apply -f example.yaml
deployment.apps/myapp created
service/myapp created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-58fd9b8cb7-4pf4d 1/1 Running 0 4s
Na de uitrol is er een pod voor de myapp deployment. Initieel zal deze nagenoeg geen CPU in gebruik hebben. Dit kan worden gevalideerd door gebruik te maken van kubectl top pod:
$ kubectl top pod
NAME CPU(cores) MEMORY(bytes)
myapp-5664749b7-bblqk 0m 2Mi
Het is mogelijk dat je direct na het opstarten van de pod, de volgende melding krijgt in plaats van bovenstaande output: "error: metrics not available yet". Dit komt omdat de metrics-server eerst nog metrics moet verzamelen voor deze pod. Na ongeveer een minuut zullen er metrics beschikbaar zijn en zal het top commando wel output geven.
Hierna starten wij een load generator op. Hiervoor maken wij gebruik van het slow_cooker project van Buoyant (de ontwikkelaars achter linkerd).
kubectl run load-generator --image=buoyantio/slow_cooker -- -qps 100 -concurrency 10 http://myapp
Met deze load generator genereren wij 100 queries (requests) per seconde tegen de zojuist uitgerolde Deployment. Dit doen wij om verkeer te simuleren waarop wij kunnen autoscalen. Je kan de logs van de load-generator pod volgen om verschillende metrics te zien, zoals latency. Als je even wacht en de kubectl top pod opstart, zul je zien dat het CPU-gebruik gestegen is.
$ kubectl top pod
NAME CPU(cores) MEMORY(bytes)
load-generator 128m 5Mi
myapp-5664749b7-bblqk 79m 2Mi
We gaan nu beginnen met het configureren van een HPA policy. Dit doen we met onderstaande code.
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
Binnen scaleTargetRef refereren we aan de Deployment die we eerder hebben gecreëerd. We configureren minReplicas en maxReplicas, dit zijn de onder- en bovengrenzen voor het aantal instanties (replicas) van een pod. Tot slot configureren we de metrics waarop wij het aantal replicas binnen de deployment willen schalen. In bovenstaand voorbeeld doen we dit op basis van het gemiddelde CPU-gebruik.
De autoscaler reageert zodra het CPU-gebruik boven de 60% van de gestelde limiet komt. Aangezien de limiet voor onze Deployment is gesteld op 100m, zal de autoscaler starten met op- of afschalen bij een CPU gebruik van 60m.
Het automatisch op- en afschalen gebeurt op basis van het gemiddelde gebruik.
Belangrijk om hierbij te realiseren is dat er een 10% tolerantie-marge wordt gehanteerd voordat de autoscaler een actie onderneemt. Dit voorkomt herhaalijke starten en stoppen van pods als gevolg van een snel fluctuerend CPU-gebruik.
Zodra de HPA policy toegevoegd is, duurt het ongeveer een minuut voordat het effect heeft.
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
myapp Deployment/myapp 75%/60% 1 10 1 51s
Kort hierna zal er een nieuwe pod starten.
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
myapp Deployment/myapp 40%/70% 1 10 2 8m42s
$ kubectl describe hpa myapp
Name: myapp
Namespace: default
Labels:
Annotations:
CreationTimestamp: Sat, 07 Aug 2021 12:30:10 +0200
Reference: Deployment/myapp
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 40% (40m) / 70%
Min replicas: 1
Max replicas: 10
Deployment pods: 2 current / 2 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
ScalingLimited False DesiredWithinRange the desired count is within the acceptable range
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 5m26s horizontal-pod-autoscaler New size: 2; reason: cpu resource utilization (percentage of request) above target
Je zal zien dat de CPU-utilisation van beide pods nu onder de target utilisation zit:
NAME CPU(cores) MEMORY(bytes)
load-generator 139m 5Mi
myapp-5664749b7-bblqk 41m 2Mi
myapp-5664749b7-lrj8g 54m 2Mi
Daarnaast kan autoscaling ook geconfigureerd worden op basis van geheugengebruik:
metrics:
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 50
Merk op dat omdat metrics een reeks is, je meerdere regels kan gebruiken:
$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
myapp Deployment/myapp 2%/50%, 48%/60% 1 10 2 19m0
Er zijn een paar dingen waar rekening mee gehouden moet worden wanneer je gebruikmaakt van autoscaling.
Clustercapaciteit
Je cluster moet genoeg capaciteit hebben om de nieuwe workloads te kunnen opstarten. Een oplossing hiervoor kan zijn om node-autoscaling aan te zetten (niet elk cluster ondersteund dit). Let hierbij op dat het enige tijd kan duren voordat de nieuwe nodes beschikbaar zijn. Het op- en afschalen van pods gaat sneller dan het op- en afschalen van nieuwe nodes. Om hiermee om te kunnen gaan, heb je voldoende capaciteit nodig binnen je cluster voor een autoscaling-actie, terwijl jij (of jouw cloud-provider) nieuwe nodes provisioned en toevoegt aan jouw cluster.
Als alternatief kan je jouw cluster over-dimensioneren zodat er ruim voldoende capaciteit is om het aantal pods dat wordt opgestart bij autoscaling op te vangen.
Configureer betrouwbare implementaties
Als je gebruikmaakt van autoscaling, wil je er zeker van zijn dat je een paar properties goed geconfigureerd hebt in je implementatie. Hiermee voorkom je (connectie-)errors tijdens scaling operations. Vaak zijn dit dezelfde properties die nodig zijn om zero-downtime implementaties te ondersteunen.
Probes
Configureer een readinessProbe en startupProbe. Op deze manier zorg je ervoor dat een pod pas traffic ontvangt wanneer deze volledig gereed is.
Bijvoorbeeld:
startupProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 5
Sluit je applicatie goed af
Het is belangrijk dat jouw applicaties bij het afsluiten zorgen dat al het werk waaraan begonnen is, eerst wordt afgehandeld. Dit zorgt ervoor dat je geen fouten krijgt zodra de autoscaler het aantal pods naar beneden schaalt.
Daarnaast is het handig om enkele seconden te wachten voordat je applicatie het stop-proces begint. Aangezien Kubernetes een distributed systeem is, duurt het even voordat alle systemen doorhebben dat een pod op een andere node aan het afsluiten is. Door enkele seconden te wachten, krijgen andere systemen de kans om te stoppen met het versturen van nieuwe requests naar een pod die afsluit, voordat deze stopt met het accepteren van nieuw verkeer. Hiervoor moet je applicatie tijdens deze status initieel nog verkeer afhandelen.
Verder kan overwogen worden om in upstream componenten een retry mechanism te implementeren die voor gefaalde connecties een retry uitvoert. Echter is een retry niet geschikt voor elke type transactie of call.
Configureer geen replicas
Zorg ervoor dat je het replicas-veld in je Deployment niet configureert, wanneer je gebruikmaakt van een horizontal pod autoscaler. Wanneer je deze toch configureert, zal bij de uitrol deze waarde gerespecteerd worden, waarna de autoscaler dit weer reset. Dit zorgt voor onnodige opstart en/of afsluit acties.
Gebruik de HorizontalPodAutoscaler resource om het minimum aantal benodigde replicas te configureren via spec.minReplicas.
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
# This will make sure there are always at least 3 pods in the myapp deployment
minReplicas: 3
maxReplicas: 10
Custom metrics
Horizontal pod autoscaling kan ook worden geconfigureerd op basis van custom metrics. Dit kan je doen via bijvoorbeeld de Prometheus metrics adapter. Hiermee kan je jouw HPA configureren om op en neer te schalen gebaseerd op het aantal verzoeken per seconde, latentie of een andere metric. In deel twee van deze blog gaan wij hier dieper op in.
Nu je weet hoe autoscaling werkt, kan je zelf aan de slag gaan! In deel twee van deze blog kijken we naar hoe custom metrics gebruikt kunnen worden voor het autoscaling van je deployments.
Door de State-mindset van Cloud Provider Hosts kost het developers veel tijd en handwerk om softwarereleases te doen. Wij van Avisi Cloud vinden dat het uitrollen van software geautomatiseerd moet worden en dat vanuit de Change-mindset gehandeld moet worden. Daarom hebben wij Avisi Managed Environments gecreëerd, waarmee jij 20% extra ontwikkelcapaciteit kan behalen. Wil jij ook 20% extra ontwikkelcapaciteit? Neem dan contact met ons op.
Blogs | Avisi Managed Environments
Door Thomas Kooi / feb 2023
Dan denken we dat dit ook wat voor jou is.