Risparmiamo sui costi cloud di Kubernetes su AWS

La traduzione dell'articolo è stata preparata in vista dell'inizio del corso «Piattaforma infrastrutturale basata su Kubernetes».

Risparmiamo sui costi cloud di Kubernetes su AWS

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 (cluster-autoscaler). 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 (kube-janitor)
  • riduzione della scala durante il tempo non operativo (kube-downscaler)
  • utilizzo dell'autoscaling orizzontale (HPA),
  • riduzione del sovra-approvvigionamento delle risorse (kube-resource-report, VPA)
  • utilizzo di istanze Spot

Pulizia delle risorse non utilizzate

Lavorare in un ambiente in rapido cambiamento è fantastico. Vogliamo che le organizzazioni tecniche accelerino. 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:

Risparmiamo sui costi cloud di Kubernetes su AWS

(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.)

Kubernetes Janitor (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: 2d

Il 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: 7d

Esecuzione 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=30m

Un 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: 24h

Kubernetes 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 README kube-janitor.

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.

Kubernetes Downscaler (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-time

Ecco il grafico del ridimensionamento dei nodi worker del cluster nei fine settimana:

Risparmiamo sui costi cloud di Kubernetes su AWS

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=true

Vedi README kube-downscaler, 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 HorizontalPodAutoscaler (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: Utilization

Zalando ha creato un componente per la semplice integrazione delle metriche personalizzate per il scaling: Kube Metrics Adapter (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: AverageValue

La 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: scalate i vostri deployment, non il vostro portafoglio.

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. [1]

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. [2]

Rapporto Risorse Kubernetes (kube-resource-report) mostra le riserve eccessive e può aiutarti a determinare le potenzialità di risparmio:

Risparmiamo sui costi cloud di Kubernetes su AWS

Rapporto Risorse Kubernetes 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:

Risparmiamo sui costi cloud di Kubernetes su AWS

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," scrive Corey Quinn. Mentre per EC2 la stima della dimensione corretta può rivelarsi una cattiva decisione, 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 Vertical Pod Autoscaler (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:

Risparmiamo sui costi cloud di Kubernetes su AWS

Zalando utilizza il VPA in tutti i suoi cluster per i componenti dell'infrastruttura. Anche le applicazioni non critiche possono utilizzare il VPA.

Goldilocks 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:

Risparmiamo sui costi cloud di Kubernetes su AWS

Ho scritto un piccolo post sul blog riguardo al VPA nel 2019 e recentemente nel CNCF End User Community si è discusso della questione del VPA.

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. [3]. 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 un fork dell'auto-scaling ufficiale del cluster con priorità per i pool di nodi
  • I nodi Spot possono essere costretti 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 mio intervento al DevOps Gathering 2019 su YouTube e nelle slide..

Quali sono le tue migliori pratiche per risparmiare sui costi del cloud su Kubernetes? Ti prego di farmelo sapere in Twitter (@try_except_).

[1] 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" (Node Allocatable).

[2] 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.

[3] 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!

Scopri di più sul corso.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster