Auto-scaling delle applicazioni Kubernetes con Prometheus e KEDA

Auto-scaling delle applicazioni Kubernetes con Prometheus e KEDABalloon Man di Cimuanos

La scalabilità è un requisito fondamentale per le applicazioni cloud. Con Kubernetes, scalare un'applicazione è semplice quanto aumentare il numero di repliche per il relativo deployment o ReplicaSet — ma questo è un processo manuale.

Kubernetes consente di scalare automaticamente le applicazioni (cioè i Pod in un deployment o ReplicaSet) in modo dichiarativo utilizzando la specifica Horizontal Pod Autoscaler. Di default, il criterio per la scalabilità automatica sono le metriche di utilizzo della CPU (metriche delle risorse), ma è possibile integrare metriche personalizzate e metriche fornite dall'esterno.

Team Kubernetes aaS di Mail.ru ha tradotto un articolo su come utilizzare metriche esterne per la scalabilità automatica delle applicazioni Kubernetes. Per dimostrare come funziona tutto, l'autore utilizza metriche di richieste HTTP, che vengono raccolte tramite Prometheus.

Invece della scalabilità orizzontale dei pod, si utilizza Kubernetes Event Driven Autoscaling (KEDA) - un operatore Kubernetes open source. Si integra inizialmente con l'Horizontal Pod Autoscaler per fornire una scalabilità fluida (inclusa fino/a partire da zero) per i carichi di lavoro basati su eventi. Il codice è disponibile su GitHub.

Panoramica breve del funzionamento del sistema

Auto-scaling delle applicazioni Kubernetes con Prometheus e KEDA

Nello schema - una breve descrizione di come funziona tutto:

  1. L'applicazione fornisce metriche sul numero di accessi HTTP nel formato Prometheus.
  2. Prometheus è configurato per raccogliere queste metriche.
  3. Lo scaler Prometheus in KEDA è configurato per scalare automaticamente l'applicazione in base al numero di accessi HTTP.

Ora parlerò in dettaglio di ogni elemento.

KEDA e Prometheus

Prometheus è un insieme di strumenti open source per il monitoraggio e la segnalazione dei sistemi, parte Cloud Native Computing Foundation. Raccoglie metriche da diverse fonti e le memorizza come dati temporali. Per la visualizzazione dei dati, è possibile utilizzare Grafana o altri strumenti di visualizzazione che lavorano con l'API di Kubernetes.

KEDA supporta il concetto di scaler - agisce come un ponte tra KEDA e un sistema esterno. L'implementazione dello scaler è specifica per ciascun sistema di destinazione ed estrae i dati da esso. Successivamente, KEDA utilizza questi dati per gestire la scalabilità automatica.

Gli scaler supportano più fonti di dati, come Kafka, Redis e Prometheus. Ciò significa che KEDA può essere utilizzato per il ridimensionamento automatico dei deployment di Kubernetes, utilizzando come criteri le metriche di Prometheus.

Applicazione di test

L'applicazione di test in Golang offre accesso tramite HTTP e svolge due funzioni principali:

  1. Utilizza la libreria client Prometheus Go per strumentare l'applicazione e fornire la metrica http_requests, che contiene un contatore delle richieste. L'endpoint da cui sono accessibili le metriche di Prometheus si trova all'URI /metrics.
    var httpRequestsCounter = promauto.NewCounter(prometheus.CounterOpts{
           Name: "http_requests",
           Help: "numero di richieste http",
       })
    
  2. In risposta alla richiesta e username/password: admin/admin. l'applicazione incrementa il valore della chiave (access_count) in Redis. Questo è un modo semplice per eseguire il lavoro come parte del gestore HTTP e testare anche le metriche di Prometheus. Il valore della metrica deve essere lo stesso del valore access_count in Redis.
    func main() {
           http.Handle("/metrics", promhttp.Handler())
           http.HandleFunc("/test", func(w http.ResponseWriter, r 
    *http.Request) {
               defer httpRequestsCounter.Inc()
               count, err := client.Incr(redisCounterName).Result()
               if err != nil {
                   fmt.Println("Impossibile incrementare il contatore di redis", err)
                   os.Exit(1)
               }
               resp := "Accesso il " + time.Now().String() + "
    Conteggio accessi " + strconv.Itoa(int(count))
               w.Write([]byte(resp))
           })
           http.ListenAndServe(":8080", nil)
       }
    

L'applicazione viene distribuita in Kubernetes tramite Deployment. Viene anche creata un servizio ClusterIP, che consente al server Prometheus di ricevere le metriche dell'applicazione.

Ecco manifesto di deployment per l'applicazione.

Server Prometheus

Il manifesto di deployment di Prometheus è composto da:

  • ConfigMap — per trasmettere la configurazione di Prometheus;
  • Deployment — per il deployment di Prometheus nel cluster Kubernetes;
  • ClusterIP — servizio per accedere all'UI di Prometheus;
  • ClusterRole, ClusterRoleBinding e ServiceAccount — per gestire l'auto-scoperta dei servizi in Kubernetes (Auto-discovery).

Ecco manifesto per l'avvio di Prometheus.

KEDA Prometheus ScaledObject

Lo scaler agisce come un ponte tra KEDA e un sistema esterno da cui è necessario ottenere metriche. ScaledObject — una risorsa configurabile, deve essere distribuita per sincronizzare il deployment con la fonte di eventi, in questo caso con Prometheus.

ScaledObject contiene informazioni sul ridimensionamento del deployment, metadati sulla fonte dell'evento (ad esempio, segreti per la connessione, nome della coda), intervallo di polling, periodo di recupero e altri dati. Conduce alla risorsa di autoscaling corrispondente (definizione HPA) per il ridimensionamento del deployment.

Quando l'oggetto ScaledObject viene rimosso, la definizione HPA corrispondente viene svuotata.

Ecco la definizione ScaledObject per il nostro esempio, si utilizza uno scaler Prometheus:

apiVersion: keda.k8s.io/v1alpha1
kind: ScaledObject
metadata:
 name: prometheus-scaledobject
 namespace: default
 labels:
   deploymentName: go-prom-app
spec:
 scaleTargetRef:
   deploymentName: go-prom-app
 pollingInterval: 15
 cooldownPeriod: 30
 minReplicaCount: 1
 maxReplicaCount: 10
 triggers:
 - type: prometheus
   metadata:
     serverAddress: 
http://prometheus-service.default.svc.cluster.local:9090
     metricName: access_frequency
     threshold: '3'
     query: sum(rate(http_requests[2m]))

Considera i seguenti punti:

  1. Indica Deployment con il nome go-prom-app.
  2. Il tipo di trigger è Prometheus. L'indirizzo del server Prometheus è menzionato insieme al nome della metrica, al valore soglia e alla query PromQL, che verrà utilizzata. La query PromQL è sum(rate(http_requests[2m])).
  3. Secondo pollingInterval, KEDA interroga l'obiettivo da Prometheus ogni quindici secondi. È supportato un minimo di un pod (minReplicaCount), mentre il numero massimo di pod non supera maxReplicaCount (in questo esempio - dieci).

Può essere impostato minReplicaCount a zero. In questo caso, KEDA attiva il deployment da zero a uno, per poi fornire HPA per ulteriore scalabilità automatica. È possibile anche l'inverso, ovvero scalare da uno a zero. Nell'esempio non abbiamo scelto zero, poiché si tratta di un servizio HTTP e non di un sistema a richiesta.

La magia dentro l'automazione dello scaling

Il valore soglia viene utilizzato come trigger per scalare il deployment. Nel nostro esempio, la query PromQL sum(rate(http_requests[2m])) restituisce il valore aggregato del tasso di richieste HTTP (numero di richieste al secondo), misurato negli ultimi due minuti.

Poiché il valore soglia è tre, ci sarà un pod finché il valore sum(rate(http_requests[2m])) è inferiore a tre. Se invece il valore aumenta, viene aggiunto un ulteriore pod ogni volta che sum(rate(http_requests[2m])) aumenta di tre. Ad esempio, se il valore passa da 12 a 14, il numero di pod sarà quattro.

Ora proviamo a configurare!

Configurazione preliminare

Tutto ciò di cui hai bisogno è un cluster Kubernetes e un'utilità configurata kubectl. In questo esempio utilizziamo un cluster minikube, ma puoi prendere qualsiasi altro. Per installare il cluster, ci sono guida.

Installa l'ultima versione su Mac:

curl -Lo minikube 
https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 
&& chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

Installare kubectl, per accedere al cluster Kubernetes.

Installare l'ultima versione su Mac:

curl -LO 
"https://storage.googleapis.com/kubernetes-release/release/$(curl -s
https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
kubectl version

Installazione di KEDA

Puoi distribuire KEDA in diversi modi, elencati in documentazione. Utilizzo di un YAML monolitico:

kubectl apply -f
https://raw.githubusercontent.com/kedacore/keda/master/deploy/KedaScaleController.yaml

KEDA e i suoi componenti vengono installati nello spazio dei nomi keda. Comando per controllare:

kubectl get pods -n keda

Aspetta che il pod KEDA Operator parta — passi a Running State. E dopo continua.

Installazione di Redis tramite Helm

Se non hai installato Helm, utilizza questo guida. Comando per l'installazione su Mac:

brew install kubernetes-helm
helm init --history-max 200

helm init inizializza l'interfaccia della riga di comando locale e installa Tiller nel cluster Kubernetes.

kubectl get pods -n kube-system | grep tiller

Aspetta che il pod Tiller passi allo stato Running.

Nota del traduttore: L'autore utilizza Helm@2, che richiede l'installazione del componente server Tiller. Ora è attuale Helm@3, per il quale non è necessaria la parte server.

Dopo aver installato Helm, per avviare Redis basta un comando:

helm install --name redis-server --set cluster.enabled=false --set 
usePassword=false stable/redis

Assicurati che Redis si sia avviato con successo:

kubectl get pods/redis-server-master-0

Aspetta che il pod Redis passi allo stato Esecuzione.

Distribuzione dell'applicazione

Comando per la distribuzione:

kubectl apply -f go-app.yaml

//output
deployment.apps/go-prom-app created
service/go-prom-app-service created

Controlla che tutto sia partito:

kubectl get pods -l=app=go-prom-app

Aspetta che Redis passi allo stato Esecuzione.

Distribuzione del server Prometheus

Il manifesto di Prometheus utilizza Kubernetes Service Discovery per Prometheus. Permette di scoprire dinamicamente i pod dell'applicazione in base all'etichetta del servizio.

kubernetes_sd_configs:
   - role: service
   relabel_configs:
   - source_labels: [__meta_kubernetes_service_label_run]
     regex: go-prom-app-service
     action: keep

Per la distribuzione:

kubectl apply -f prometheus.yaml

//output
clusterrole.rbac.authorization.k8s.io/prometheus created
serviceaccount/default configured
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
configmap/prom-conf created
deployment.extensions/prometheus-deployment created
service/prometheus-service created

Controlla che tutto sia partito:

kubectl get pods -l=app=prometheus-server

Aspetta che il pod Prometheus passi allo stato Esecuzione.

Usa kubectl port-forward per accedere all'interfaccia utente di Prometheus (o al server API) all'indirizzo http://localhost:9090.

kubectl port-forward service/prometheus-service 9090

Distribuzione della configurazione per il ridimensionamento automatico KEDA

Comando per creare ScaledObject:

kubectl apply -f keda-prometheus-scaledobject.yaml

Controlla i log dell'operatore KEDA:

KEDA_POD_NAME=$(kubectl get pods -n keda 
-o=jsonpath='{.items[0].metadata.name}')
kubectl logs $KEDA_POD_NAME -n keda

Il risultato appare circa così:

time="2019-10-15T09:38:28Z" level=info msg="Watching ScaledObject:
default/prometheus-scaledobject"
time="2019-10-15T09:38:28Z" level=info msg="Created HPA with 
namespace default and name keda-hpa-go-prom-app"

Controlla gli pod dell'applicazione. Deve essere in esecuzione una singola istanza poiché minReplicaCount è uguale a 1:

kubectl get pods -l=app=go-prom-app

Verifica che la risorsa HPA sia stata creata con successo:

kubectl get hpa

Dovresti vedere qualcosa del tipo:

NOME                   RIFERIMENTI                TARGETS     MINPODS   MAXPODS   REPLICAS   ETÀ
keda-hpa-go-prom-app   Deployment/go-prom-app   0/3 (avg)   1         10        1          45s

Verifica della funzionalità: accesso all'applicazione

Per accedere all'endpoint REST della nostra applicazione, esegui:

kubectl port-forward service/go-prom-app-service 8080

Ora puoi accedere all'applicazione Go utilizzando l'indirizzo http://localhost:8080. Per fare ciò, esegui il comando:

curl http://localhost:8080/test

Il risultato appare circa così:

Accesso effettuato il 2019-10-21 11:29:10.560385986 +0000 UTC 
m=+406004.817901246
Contatore accessi 1

In questa fase controlla anche Redis. Vedrai che la chiave access_count è aumentata a 1:

kubectl exec -it redis-server-master-0 -- redis-cli get access_count
//output
"1"

Assicurati che il valore della metrica http_requests sia lo stesso:

curl http://localhost:8080/metrics | grep http_requests
//output
# HELP http_requests numero di http requests
# TYPE http_requests counter
http_requests 1

Creazione del carico

Useremo hey — un'utilità per generare il carico:

curl -o hey https://storage.googleapis.com/hey-release/hey_darwin_amd64 
&& chmod a+x hey

Puoi anche scaricare l'utilità per Linux o Windows.

Eseguila:

./hey http://localhost:8080/test

Per impostazione predefinita, l'utilità invia 200 richieste. Puoi verificarlo usando le metriche di Prometheus e anche Redis.

curl http://localhost:8080/metrics | grep http_requests
//output
# HELP http_requests numero di http requests
# TYPE http_requests counter
http_requests 201
kubectl exec -it redis-server-master-0 -- redis-cli get access_count
//output
201

Conferma il valore della metrica effettiva (ritornata dalla query PromQL):

curl -g 
'http://localhost:9090/api/v1/query?query=sum(rate(http_requests[2m]))'
//output
{"status":"success","data":{"resultType":"vector","result":[{"metric":{},"value":[1571734214.228,"1.686057971014493"]}]}}

In questo caso il risultato effettivo è 1,686057971014493 e viene visualizzato nel campo value. Non è sufficiente per il scaling, poiché la soglia impostata è 3.

Più carico!

In un nuovo terminale, monitora il numero di pod dell'applicazione:

kubectl get pods -l=app=go-prom-app -w

Aumentiamo il carico usando il comando:

./hey -n 2000 http://localhost:8080/test

Dopo un po' vedrai che l'HPA scala il deployment e avvia nuovi pod. Controlla HPA per confermarlo:

kubectl get hpa
NOME                   RIFERIMENTI                TARGETS         MINPODS   MAXPODS   REPLICAS   ETÀ
keda-hpa-go-prom-app   Deployment/go-prom-app   1830m/3 (avg)   1         10        6          4m22s

Se il carico non è costante, il deployment si ridurrà al punto in cui funziona solo un pod. Se desideri controllare la metrica effettiva (restituita dalla query PromQL), utilizza il comando:

curl -g 
'http://localhost:9090/api/v1/query?query=sum(rate(http_requests[2m]))'

Pulizia

//Delete KEDA
kubectl delete namespace keda
//Delete the app, Prometheus server and KEDA scaled object
kubectl delete -f .
//Delete Redis
helm del --purge redis-server

Conclusione

KEDA consente di scalare automaticamente i tuoi deployment Kubernetes (fino/a zero) basandosi su dati provenienti da metriche esterne. Ad esempio, basandosi su metriche di Prometheus, sulla lunghezza della coda in Redis, o sulla latenza del consumatore nel topic Kafka.

KEDA esegue l'integrazione con una fonte esterna e fornisce le sue metriche tramite il Metrics Server per l'Horizontal Pod Autoscaler.

Buona fortuna!

Cosa leggere ancora:

  1. Le migliori pratiche e raccomandazioni per l'implementazione di container e Kubernetes negli ambienti di produzione.
  2. 90+ strumenti utili per Kubernetes: distribuzione, gestione, monitoraggio, sicurezza e altro ancora.
  3. Il nostro canale Intorno a Kubernetes su Telegram.

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