La traduzione dell'articolo è stata preparata in vista dell'inizio del corso .

Come risparmiare sui costi cloud lavorando con Kubernetes? Non esiste una soluzione unica, ma in questo articolo vengono descritti diversi strumenti che possono aiutarti a gestire le risorse in modo più efficiente e a ridurre le spese per il cloud computing.
Ho scritto questo articolo pensando a Kubernetes per AWS, ma sarà applicabile (quasi) esattamente allo stesso modo per altri fornitori di cloud. Presumo che il tuo cluster(o) abbia già configurato l'autoscaling (). Rimuovere risorse e ridurre la scala del deployment permetterà di risparmiare solo se ciò riduce anche il tuo parco di nodi di lavoro (istanze EC2).
In questo articolo verranno trattati:
- pulizia delle risorse non utilizzate ()
- riduzione della scala durante il tempo non operativo ()
- utilizzo dell'autoscaling orizzontale (HPA),
- riduzione del sovra-approvvigionamento delle risorse (, VPA)
- utilizzo di istanze Spot
Pulizia delle risorse non utilizzate
Lavorare in un ambiente in rapido cambiamento è fantastico. Vogliamo che le organizzazioni tecniche . Una consegna più rapida del software significa anche più deployment PR, ambienti di anteprima, prototipi e soluzioni analitiche. Tutto distribuito su Kubernetes. Chi ha tempo per pulire manualmente i deployment di test? È facile dimenticarsi di eliminare un esperimento di una settimana fa. La bolletta del cloud alla fine aumenterà a causa di ciò che abbiamo dimenticato di chiudere:

(Henning Jacobs:
Reality check:
(cita) Corey Quinn:
Mito: Il tuo conto AWS è funzione del numero dei tuoi utenti.
Fatto: Il tuo conto AWS è funzione del numero dei tuoi ingegneri.
Ivan Kurnosov (in risposta):
Fatto reale: Il tuo conto AWS è funzione di quante cose hai dimenticato di spegnere/rimuovere.)
(kube-janitor) aiuta a pulire il tuo cluster. La configurazione del janitor è flessibile sia per uso globale che locale:
- Le regole generali per l'intero cluster possono definire il tempo massimo di vita (TTL — time-to-live) per deployment PR/test.
- Risorse specifiche possono essere annotate con janitor/ttl, ad esempio, per cancellare automaticamente uno spike/prototipo dopo 7 giorni.
Le regole generali sono definite in un file YAML. Il suo percorso è passato tramite il parametro --rules-file in kube-janitor. Ecco un esempio di regola per eliminare tutti gli spazi dei nomi che contengono -pr- nel nome dopo due giorni:
- id: pulizia-risorse-da-pull-requests
resources:
- namespaces
jmespath: "contains(metadata.name, '-pr-')"
ttl: 2dIl seguente esempio disciplina l'uso dell'etichetta application sui Deployment e StatefulSet per tutti i nuovi Deployments/StatefulSet nel 2020, ma allo stesso tempo consente di eseguire test senza questa etichetta per una settimana:
- id: richiesta-etichetta-application
# rimuovere deployments e statefulsets senza etichetta "application"
resources:
- deployments
- statefulsets
# vedi http://jmespath.org/specification.html
jmespath: "!(spec.template.metadata.labels.application) && metadata.creationTimestamp > '2020-01-01'"
ttl: 7dEsecuzione di una demo a tempo limitato di 30 minuti in un cluster dove è attivo kube-janitor:
kubectl run nginx-demo --image=nginx
kubectl annotate deploy nginx-demo janitor/ttl=30mUn ulteriore fonte di costi crescenti sono i volumi persistenti (AWS EBS). Quando si elimina uno StatefulSet di Kubernetes, i suoi volumi persistenti (PVC — PersistentVolumeClaim) non vengono eliminati. I volumi EBS non utilizzati possono facilmente portare a spese di centinaia di dollari al mese. Kubernetes Janitor ha una funzione per pulire i PVC non utilizzati. Ad esempio, questa regola eliminerà tutti i PVC che non sono montati da un modulo e non sono referenziati da uno StatefulSet o CronJob:
# удалить все PVC, которые не смонтированы и на которые не ссылаются StatefulSets
- id: remove-unused-pvcs
resources:
- persistentvolumeclaims
jmespath: "_context.pvc_is_not_mounted && _context.pvc_is_not_referenced"
ttl: 24hKubernetes Janitor può aiutarti a mantenere il tuo cluster "pulito" e a prevenire costi di cloud computing che si accumulano lentamente. Per istruzioni su come distribuire e configurare, segui il .
Riduzione dello scaling durante il non lavoro
Sistemi di test e di staging sono generalmente richiesti solo per il tempo lavorativo. Alcune applicazioni di produzione, come il back-office / strumenti di amministrazione, richiedono anche solo disponibilità limitata e possono essere spente di notte.
(kube-downscaler) consente a utenti e operatori di ridimensionare il sistema durante i periodi di inattività. I Deployment e gli StatefulSet possono essere ridimensionati a zero repliche. I CronJob possono essere sospesi. Kubernetes Downscaler è configurabile per l'intero cluster, uno o più namespace o risorse specifiche. Può essere impostato per il "tempo di inattività" oppure al contrario per il "tempo di operatività". Ad esempio, per ridurre al minimo il ridimensionamento durante la notte e nei fine settimana:
image: hjacobs/kube-downscaler:20.4.3
args:
- --interval=30
# non disabilitare i componenti dell'infrastruttura
- --exclude-namespaces=kube-system,infra
# non disabilitare kube-downscaler e lasciare il Postgres Operator, per gestire i database esclusi
- --exclude-deployments=kube-downscaler,postgres-operator
- --default-uptime=Lun-Ven 08:00-20:00 Europe/Berlino
- --include-resources=deployments,statefulsets,stacks,cronjobs
- --deployment-time-annotation=deployment-timeEcco il grafico del ridimensionamento dei nodi worker del cluster nei fine settimana:

Ridurre il numero di nodi da ~13 a 4 fa sicuramente una differenza significativa nella bolletta AWS.
Ma cosa succede se devo lavorare durante il "tempo di inattività" del cluster? Alcuni deployment possono essere permanentemente esclusi dal ridimensionamento aggiungendo l'annotazione downscaler/exclude: true. I deployment possono essere temporaneamente esclusi utilizzando l'annotazione downscaler/exclude-until con un timestamp assoluto nel formato AAAA-MM-GG HH:MM (UTC). Se necessario, l'intero cluster può essere ridimensionato nuovamente eseguendo un pod con l'annotazione downscaler/force-uptime, ad esempio, eseguendo un'immagine nginx di esempio:
kubectl run scale-up --image=nginx
kubectl annotate deploy scale-up janitor/ttl=1h # rimuovi il deployment dopo un'ora
kubectl annotate pod $(kubectl get pod -l run=scale-up -o jsonpath="{.items[0].metadata.name}") downscaler/force-uptime=trueVedi , se sei interessato a istruzioni per il deployment e opzioni aggiuntive.
Utilizza l'autoscaling orizzontale
Molte applicazioni/servizi affrontano schemi di carico dinamico: a volte i loro moduli rimangono inattivi e altre volte funzionano a pieno regime. Mantenere un parco costante di pod per gestire il picco massimo non è economico. Kubernetes supporta l'autoscaling orizzontale automatico tramite la risorsa (HPA). L'utilizzo della CPU è spesso un buon indicatore per il ridimensionamento:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
averageUtilization: 100
type: UtilizationZalando ha creato un componente per la semplice integrazione delle metriche personalizzate per il scaling: (kube-metrics-adapter) è un adattatore di metriche universale per Kubernetes, che può raccogliere e fornire metriche personalizzate ed esterne per il ridimensionamento orizzontale dei pod. Supporta il ridimensionamento basato su metriche Prometheus, code SQS e altre configurazioni. Ad esempio, per scalare un deployment per una metrica personalizzata esposta dall'app stessa in formato JSON in /metrics usa:
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
annotations:
# metric-config.../<>
metric-config.pods.requests-per-second.json-path/json-key: "$.http_server.rps"
metric-config.pods.requests-per-second.json-path/path: /metrics
metric-config.pods.requests-per-second.json-path/port: "9090"
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 1
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: requests-per-second
target:
averageValue: 1k
type: AverageValueLa configurazione del ridimensionamento orizzontale tramite HPA dovrebbe essere una delle azioni predefinite per migliorare l'efficienza per i servizi stateless. Spotify ha una presentazione con la loro esperienza e raccomandazioni per l'HPA: .
Ridurre il sovradimensionamento delle risorse
Le workload di Kubernetes definiscono le loro esigenze di CPU/memoria attraverso le "richieste di risorse" (resource requests). Le risorse CPU sono misurate in core virtuali o più spesso in "millicore" (millicores), ad esempio, 500m implica il 50% di vCPU. Le risorse di memoria sono misurate in byte, e si possono utilizzare suffissi comuni, ad esempio, 500Mi, che significa 500 megabyte. Le richieste di risorse "bloccano" la capacità sui nodi di lavoro, quindi un pod con una richiesta di CPU di 1000m su un nodo con 4 vCPU lascerà solo 3 vCPU disponibili per altri pod.
Slack (sovradimensionamento delle risorse) — questa è la differenza tra le risorse richieste e l'utilizzo reale. Ad esempio, un pod che richiede 2 GiB di memoria, ma utilizza solo 200 MiB, ha circa 1,8 GiB di memoria "in eccesso". L'eccesso costa denaro. Si può stimare approssimativamente che 1 GiB di memoria in eccesso costi circa 10 dollari al mese.
(kube-resource-report) mostra le riserve eccessive e può aiutarti a determinare le potenzialità di risparmio:

mostra l'eccesso aggregato dall'applicazione e dal team. Questo consente di identificare le aree in cui le richieste di risorse possono essere ridotte. Il rapporto HTML generato fornisce solo un'istantanea dell'utilizzo delle risorse. È necessario monitorare l'utilizzo della CPU/memoria nel tempo per determinare le richieste di risorse appropriate. Ecco un diagramma Grafana per un servizio "tipico" con un alto carico CPU: tutti i pod utilizzano significativamente meno di 3 core CPU richiesti:

Ridurre la richiesta di CPU da 3000m a circa 400m libera risorse per altri carichi di lavoro e consente di ridurre il cluster.
"L'utilizzo medio della CPU delle istanze EC2 varia spesso nell'intervallo di percentuali a una cifra," . Mentre per EC2 , modificare alcune richieste di risorse Kubernetes nel file YAML è semplice e può portare a enormi risparmi.
Ma vogliamo realmente che le persone modifichino i valori nei file YAML? No, le macchine possono farlo molto meglio! Kubernetes (VPA) fa proprio questo: adatta le richieste di risorse e i limiti in base al carico di lavoro. Ecco un esempio di grafico delle richieste di CPU di Prometheus (linea blu sottile), adattate dal VPA nel tempo:

per i componenti dell'infrastruttura. Anche le applicazioni non critiche possono utilizzare il VPA.
di Fairwind è uno strumento che crea un VPA per ogni distribuzione nello spazio dei nomi e poi visualizza la raccomandazione VPA sul proprio cruscotto. Può aiutare gli sviluppatori a impostare le corrette richieste di CPU/memoria per le proprie applicazioni:

Ho scritto un piccolo nel 2019 e recentemente nel .
Utilizzo delle istanze EC2 Spot
Infine, ciò che è altrettanto importante, i costi di AWS EC2 possono essere ridotti utilizzando le istanze Spot come nodi di lavoro per Kubernetes. . Le istanze Spot sono disponibili con uno sconto fino al 90% rispetto ai prezzi on-demand. Eseguire Kubernetes su EC2 Spot è una buona combinazione: è necessario specificare diversi tipi di istanze per una maggiore disponibilità, il che significa che puoi ottenere un nodo più grande allo stesso prezzo o a un prezzo inferiore, e la maggiore capacità può essere utilizzata dai carichi di lavoro containerizzati di Kubernetes.
Come avviare Kubernetes su EC2 Spot? Ci sono diverse opzioni: utilizzare un servizio di terze parti come SpotInst (ora si chiama "Spot", non chiedermi perché) o semplicemente aggiungere un Spot AutoScalingGroup (ASG) al tuo cluster. Ad esempio, ecco un frammento di CloudFormation per un ASG Spot "ottimizzato per la capacità" con più tipi di istanze:
MySpotAutoScalingGroup:
Properties:
HealthCheckGracePeriod: 300
HealthCheckType: EC2
MixedInstancesPolicy:
InstancesDistribution:
OnDemandPercentageAboveBaseCapacity: 0
SpotAllocationStrategy: capacity-optimized
LaunchTemplate:
LaunchTemplateSpecification:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
Overrides:
- InstanceType: "m4.2xlarge"
- InstanceType: "m4.4xlarge"
- InstanceType: "m5.2xlarge"
- InstanceType: "m5.4xlarge"
- InstanceType: "r4.2xlarge"
- InstanceType: "r4.4xlarge"
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
MinSize: 0
MaxSize: 100
Tags:
- Key: k8s.io/cluster-autoscaler/node-template/label/aws.amazon.com/spot
PropagateAtLaunch: true
Value: "true"Alcuni appunti sull'utilizzo di Spot con Kubernetes:
- Devi gestire le terminazioni delle Spot, ad esempio attraverso il drain del nodo in caso di arresto dell'istanza.
- Zalando utilizza dell'auto-scaling ufficiale del cluster con priorità per i pool di nodi
- I nodi Spot ad accettare le 'registrazioni' dei carichi di lavoro per essere eseguiti in Spot.
Riepilogo
Spero che tu trovi alcuni degli strumenti presentati utili per ridurre la tua bolletta per il cloud. Puoi trovare gran parte del contenuto dell'articolo anche nel .
Quali sono le tue migliori pratiche per risparmiare sui costi del cloud su Kubernetes? Ti prego di farmelo sapere in .
In effetti, meno di 3 CPU virtuali rimarranno utilizzabili, poiché la capacità del nodo si riduce a causa delle risorse di sistema riservate. Kubernetes distingue tra la capacità fisica del nodo e le risorse "allocate" ().
Esempio di calcolo: un'istanza m5.large con 8 GiB di memoria costa circa 84 dollari USA al mese (eu-central-1, On-Demand), ovvero la frazione 1/8 del nodo costa circa 10 dollari USA al mese.
Ci sono molti altri modi per ridurre il tuo conto EC2, ad esempio istanze riservate, piani di risparmio, ecc. — non tratterò questi argomenti qui, ma dovresti sicuramente informarti su di essi!
Fonte: habr.com
