Nove cunsiglii di rendiment Kubernetes

Nove cunsiglii di rendiment Kubernetes

Salut à tutti ! Mi chjamu Oleg Sidorenkov, travagliu in DomClick cum'è capu di squadra di infrastruttura. Avemu usatu u Cube in vendita per più di trè anni, è duranti stu tempu avemu avutu assai diversi mumenti interessanti cun ellu. Oghje vi dicu cumu, cù l'approcciu ghjusta, pudete strincà ancu più prestazioni da Vanilla Kubernetes per u vostru cluster. Pronti à andà fermu!

Tutti sapete bè chì Kubernetes hè un sistema open source scalable per l'orchestrazione di cuntainer; bè, o 5 binari chì facenu a magia gestionendu u ciclu di vita di i vostri microservizi in un ambiente di servitore. Inoltre, questu hè un strumentu abbastanza flessibile chì pò esse assemblatu cum'è un constructore Lego per a persunalizazione massima per e diverse attività.

È tuttu pare bè: lanciate i servitori in u cluster, cum'è a legna in un focu, è ùn cunnosci micca u dulore. Ma sè vo site per l'ambiente, allora penserete: "Cumu possu mantene u focu in a stufa è dispiace u boscu?". In altre parolle, cumu truvà modi per migliurà l'infrastruttura è riduce i costi.

1. Mantene a traccia di e risorse di a squadra è di l'applicazione

Nove cunsiglii di rendiment Kubernetes

Unu di i metudi più banali ma efficaci hè l'intruduzioni di richieste / limiti. Separate l'applicazioni per namespaces, è namespaces per squadre di sviluppu. Stabilite l'applicazione prima di implementà i valori per u cunsumu di u tempu di processore, memoria, almacenamiento effimeru.

resources:
   requests:
     memory: 2Gi
     cpu: 250m
   limits:
     memory: 4Gi
     cpu: 500m

Per spirienza, avemu ghjuntu à a cunclusione: ùn vale a pena inflating requests from limits per più di duie volte. A dimensione di u cluster hè calculatu basatu annantu à e dumande, è se stabilisce l'applicazione à una diferenza di risorse, per esempiu, da 5-10 volte, allora imagine ciò chì succede à u vostru node quandu hè pienu di pods è subitu riceve una carica. Nunda di bonu. À u minimu, throttling, è cum'è un massimu, dite addiu à u travagliadore è uttene una carica ciclica nantu à u restu di i nodi dopu chì i baccelli cumincianu à muvimenti.

Inoltre, cù l'aiutu limitranges pudete stabilisce i valori di risorse per u cuntainer à u principiu - minimu, massimu è predeterminatu:

➜  ~ kubectl describe limitranges --namespace ops
Name:       limit-range
Namespace:  ops
Type        Resource           Min   Max   Default Request  Default Limit  Max Limit/Request Ratio
----        --------           ---   ---   ---------------  -------------  -----------------------
Container   cpu                50m   10    100m             100m           2
Container   ephemeral-storage  12Mi  8Gi   128Mi            4Gi            -
Container   memory             64Mi  40Gi  128Mi            128Mi          2

Ricurdatevi di limità e risorse di u spaziu di nomi in modu chì un cumandamentu ùn pò micca piglià tutte e risorse di u cluster:

➜  ~ kubectl describe resourcequotas --namespace ops
Name:                   resource-quota
Namespace:              ops
Resource                Used          Hard
--------                ----          ----
limits.cpu              77250m        80
limits.memory           124814367488  150Gi
pods                    31            45
requests.cpu            53850m        80
requests.memory         75613234944   150Gi
services                26            50
services.loadbalancers  0             0
services.nodeports      0             0

Comu pudete vede da a descrizzione resourcequotas, Se u cumandamentu ops vole implementà pods chì cunsumanu un'altra CPU 10, allora u pianificatore ùn permettenu micca di fà è emette un errore:

Error creating: pods "nginx-proxy-9967d8d78-nh4fs" is forbidden: exceeded quota: resource-quota, requested: limits.cpu=5,requests.cpu=5, used: limits.cpu=77250m,requests.cpu=53850m, limited: limits.cpu=10,requests.cpu=10

Per risolve un prublema simili, pudete scrive un strumentu, per esempiu, cum'è questu, chì ponu almacenà è cummette u statu di risorse di cumandamentu.

2. Sceglie u megliu almacenamentu di schedari

Nove cunsiglii di rendiment Kubernetes

Quì vogliu tuccà u tema di volumi persistenti è u sottosistema di discu di i nodi di u travagliu di Kubernetes. Spergu chì nimu ùn usa u "Cube" in u HDD in a pruduzzione, ma qualchì volta ancu un SSD regulare ùn hè micca abbastanza. Avemu affruntatu un tali prublema chì i logs anu uccisu u discu da operazioni I / O, è ùn ci sò micca assai suluzioni quì:

  • Aduprate SSD d'altu rendiment o cambiate à NVMe (se gestite u vostru propiu hardware).

  • Diminuisce u livellu di logging.

  • Fate un equilibriu "intelligente" di baccelli chì violanu u discu (podAntiAffinity).

A screenshot sopra mostra ciò chì succede sottu nginx-ingress-controller cù un discu quandu access_logs hè attivatu (~ 12k logs / sec). Un tali statu, sicuru, pò purtà à a degradazione di tutte l'applicazioni nantu à questu node.

In quantu à PV, alas, ùn aghju micca pruvatu tuttu. tipi di Volumi persistenti. Aduprate a megliu opzione chì vi cunvene. Hè accadutu storicamente in u nostru paese chì una piccula parte di i servizii necessitanu volumi RWX, è assai tempu fà cuminciaru à utilizà l'almacenamiento NFS per questu compitu. Economicu è ... abbastanza. Di sicuru, avemu manghjatu merda cun ellu - esse sanu, ma avemu amparatu à sintonizzallu, è u so capu ùn hè più male. È s'ellu hè pussibule, cambiate à l'almacenamiento d'uggetti S3.

3. Custruì Images Optimized

Nove cunsiglii di rendiment Kubernetes

Hè megliu aduprà l'imaghjini ottimizzati per u containeru in modu chì Kubernetes pò piglià più veloce è eseguisce in modu più efficiente. 

L'optimizazione significa chì l'imaghjini:

  • cuntene una sola applicazione o compie una sola funzione;

  • piccula taglia, perchè grandi imagine sò peggiu trasmessi nantu à a reta;

  • avè punti finali di salute è prontezza chì Kubernetes pò aduprà per piglià l'azzione in casu di downtime;

  • Aduprate sistemi operativi cuntenituri (cum'è Alpine o CoreOS) chì sò più resistenti à l'errore di cunfigurazione;

  • Aduprate builds multi-stadi in modu chì pudete implementà solu applicazioni compilate è micca e fonti accumpagnate.

Ci hè parechje arnesi è servizii chì permettenu di verificà è ottimisà l'imaghjini nantu à a mosca. Hè impurtante di mantene sempre à ghjornu è sicuru. In u risultatu, avete:

  1. Carica di rete ridutta nantu à tuttu u cluster.

  2. Diminuzione di u tempu di partenza di u containeru.

  3. Dimensione più chjuca di tuttu u vostru registru Docker.

4. Aduprate una cache DNS

Nove cunsiglii di rendiment Kubernetes

Se parlemu di carichi elevati, allora senza sintonizà u sistema DNS di u cluster, a vita hè abbastanza brutta. Una volta, i sviluppatori di Kubernetes sustenevanu a so suluzione kube-dns. Hè statu ancu implementatu in u nostru paese, ma stu software ùn hà micca particularmente sintonizatu è ùn hà micca datu u rendimentu necessariu, ancu s'ellu pare chì u compitu hè simplice. Allora apparsu coredns, à quale avemu cambiatu è ùn cunnosci micca u dulore, dopu hè diventatu u serviziu DNS predeterminatu in K8s. À un certu puntu, avemu crisciutu à 40 mila rps à u sistema DNS, è sta suluzione ùn era ancu abbastanza. Ma, per una furtuna furtuna, Nodelocaldns esce, aka node local cache, aka NodeLocal DNSCache.

Perchè avemu aduprà? Ci hè un bug in u kernel Linux chì, quandu l'accessi multipli attraversu u conntrack NAT nantu à UDP, portanu à una cundizione di razza per scrive à e tavule di cuntrack, è una parte di u trafficu attraversu NAT hè persa (ogni viaghju attraversu u serviziu hè NAT). Nodelocaldns risolve stu prublema per sbarazzarsi di NAT è aghjurnà à a connettività TCP à u DNS upstream, è ancu cachendu e dumande DNS upstream localmente (cumprese una corta cache negativa di 5 secondi).

5. Scale pods horizontally è vertically automaticamente

Nove cunsiglii di rendiment Kubernetes

Pudete dì cun fiducia chì tutti i vostri microservizi sò pronti per un aumentu di dui à trè volte di carica? Cumu assignà bè risorse à e vostre applicazioni? Mantene un coppiu di baccelli chì superanu a carica di travagliu pò esse redundante, è mantenenduli back to back risicheghjanu i tempi di inattività da un bruscu aumentu di u trafficu à u serviziu. U significatu d'oru aiuta à ottene l'incantesimu di multiplicazione cum'è servizii Autoscaler à pod horizontale и Autoscaler à pod verticale.

VPA permette di elevà automaticamente e richieste / limiti di i vostri cuntenituri in un pod basatu annantu à l'usu attuale. Cumu pò esse utile? Sè vo avete Pods chì, per una certa ragione, ùn pò esse scalatu orizzontalmente (chì ùn hè micca cumplettamente affidabile), allura pudete pruvà à cunfidenza VPA per cambià i so risorse. A so funzione hè un sistema di ricunniscenza basatu nantu à e dati storichi è attuali da u metric-server, cusì se ùn vulete micca cambià automaticamente richieste / limiti, pudete simpricimenti monitorizà e risorse cunsigliate per i vostri cuntenituri è ottimisate i paràmetri per salvà CPU è memoria. in u cluster.

Nove cunsiglii di rendiment KubernetesImmagine presa da https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

U pianificatore in Kubernetes hè sempre basatu nantu à e dumande. Qualunque sia u valore chì mette quì, u pianificatore cercarà un node adattatu basatu annantu à questu. U valore limite hè necessariu da u kublet per sapè quandu throttle o tumbà un pod. E postu chì l'unicu paràmetru impurtante hè u valore di e dumande, VPA hà da travaglià cun ellu. Ogni volta chì scala a vostra applicazione verticalmente, definisce ciò chì e richieste duveranu esse. E allora chì succede à i limiti ? Stu paràmetru serà ancu scalatu proporzionalmente.

Per esempiu, quì sò i paràmetri tipici di pod:

resources:
   requests:
     memory: 250Mi
     cpu: 200m
   limits:
     memory: 500Mi
     cpu: 350m

U mutore di ricunniscenza determina chì a vostra applicazione hà bisognu di 300m CPU è 500Mi per eseguisce bè. Averete questi paràmetri:

resources:
   requests:
     memory: 500Mi
     cpu: 300m
   limits:
     memory: 1000Mi
     cpu: 525m

Cum'è l'esitatu sopra, questu hè una scala proporzionale basatu annantu à u rapportu richieste / limiti in u manifestu:

  • CPU: 200m → 300m: rapportu 1:1.75;

  • Memoria: 250Mi → 500Mi: ratio 1:2.

Cuncirnendu HPA, allura u miccanisimu di funziunamentu hè più trasparente. I limiti sò stabiliti per metriche cum'è u processatore è a memoria, è se a media di tutte e rèpliche supera u limitu, allora l'applicazione scala da + 1 pod finu à chì u valore cade sottu à u limitu, o finu à chì u massimu di rèpliche hè righjuntu.

Nove cunsiglii di rendiment KubernetesImmagine presa da https://levelup.gitconnected.com/kubernetes-autoscaling-101-cluster-autoscaler-horizontal-pod-autoscaler-and-vertical-pod-2a441d9ad231

In più di e metriche abituali cum'è CPU è Memoria, pudete stabilisce soglie nantu à e vostre metriche Prometheus persunalizate è travaglià cun elli se sente chì questu hè u modu più precisu per determinà quandu scala a vostra applicazione. Una volta chì l'applicazione si stabilizza sottu à u sogliu metricu specificatu, HPA hà da cumincià à scalà i pods finu à u minimu numeru di repliche o finu à chì a carica scontra u sogliu specificatu.

6. Ùn vi scurdate di Node Affinity è Pod Affinity

Nove cunsiglii di rendiment Kubernetes

Micca tutti i nodi funzionanu nantu à u stessu hardware, è micca tutti i pods anu bisognu di eseguisce applicazioni intensivi di calculu. Kubernetes permette di specificà a specializazione di i nodi è i podi chì utilizanu Node Affinity и Pod Affinity.

Sì avete nodi chì sò adattati per l'operazioni compute-intensive, allora per a massima efficienza, hè megliu ligà l'applicazioni à i nodi appropritati. Per fà questu, utilizate nodeSelector cù l'etichetta di u nodu.

Diciamu chì avete dui nodi: unu cù CPUType=HIGHFREQ è un gran numaru di core veloci, un altru cun MemoryType=HIGHMEMORY più memoria è prestazioni più veloci. A manera più faciule hè di assignà una implementazione di pod à un node HIGHFREQaghjunghjendu à a rùbbrica spec un selettore cum'è questu:

…
nodeSelector:
	CPUType: HIGHFREQ

Un modu più caru è specificu per fà questu hè di utilizà nodeAffinity in campu affinity rùbbrica spec. Ci sò dui opzioni:

  • requiredDuringSchedulingIgnoredDuringExecution: paràmetru duru (u scheduler implementerà solu pods nantu à nodi specifichi (è in nulla altru));

  • preferredDuringSchedulingIgnoredDuringExecution: paràmetru soft (u pianificatore pruvarà à implementà à nodi specifichi, è se falla, pruvarà à implementà à u prossimu nodu dispunibule).

Pudete specificà una sintassi specifica per a gestione di etichette di nodi, per esempiu, In, NotIn, Exists, DoesNotExist, Gt o Lt. Tuttavia, ricordate chì i metudi cumplessi in longhi listi di etichette rallentanu a decisione in situazioni critiche. In altre parolle, ùn fate micca troppu complicatu.

Cum'è l'esitatu sopra, Kubernetes permette di stabilisce l'associazione di pods attuali. Questu hè, pudete fà chì certi baccelli travaglianu inseme cù altri pods in a listessa zona di dispunibilità (rilevante per i nuvuli) o nodi.

В podAffinity campi affinity rùbbrica spec i stessi campi sò dispunibuli cum'è in u casu di nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution и preferredDuringSchedulingIgnoredDuringExecution. L'unica diferenza hè chì matchExpressions vincerà i pods à un node chì hè digià eseguitu un pod cù quella etichetta.

Più Kubernetes offre un campu podAntiAffinity, chì, in cuntrastu, ùn ligà micca un pod à un node cù pods specifichi.

Circa l'espressioni nodeAffinity U stessu cunsigliu pò esse datu: pruvate à mantene e regule simplici è logicu, ùn pruvate micca di sopracarcà l'specificazione di pod cun un settore cumplessu di regule. Hè assai faciule di creà una regula chì ùn currisponde micca à e cundizioni di u cluster, mettendu una carica extra in u pianificatore è degradandu u rendiment generale.

7. Taints & Tollerations

Ci hè un altru modu di gestisce u pianificatore. Se tenete un grande cluster cù centinaie di nodi è millaie di microservizi, hè assai difficiuli di prevene certi pods da esse ospitati da certi nodi.

U mecanismu di taints - reguli pruibenti - aiuta cù questu. Per esempiu, pudete impedisce à certi nodi di eseguisce pods in certi scenarii. Per applicà a contaminazione à un nodu specificu, utilizate l'opzione taint in kubectl. Specificate a chjave è u valore è dopu taint like NoSchedule o NoExecute:

$ kubectl taint nodes node10 node-role.kubernetes.io/ingress=true:NoSchedule

Hè vale a pena nutà ancu chì u mecanismu di taint sustene trè effetti principali: NoSchedule, NoExecute и PreferNoSchedule.

  • NoSchedule significa chì finu à chì ci hè una entrata currispondente in a specificazione di pod tolerations, ùn pò micca esse implementatu à u node (in questu esempiu node10).

  • PreferNoSchedule - versione simplificata NoSchedule. In questu casu, u pianificatore pruvarà micca di assignà pods chì ùn anu micca una entrata currispondente. tolerations per node, ma questu ùn hè micca un limitu duru. Se ùn ci sò micca risorse in u cluster, allora i pods cumincianu à implementà nantu à questu node.

  • NoExecute - stu effettu provoca una evacuazione immediata di baccelli chì ùn anu micca una entrata currispondente tolerations.

Curiosamente, stu cumpurtamentu pò esse annullatu cù u mecanismu di tollerazioni. Questu hè cunvenutu quandu ci hè un node "proibitu" è avete bisognu di mette solu servizii di infrastruttura nantu à questu. Cumu fà? Permettenu solu quelli baccelli per i quali ci hè una toleranza adattata.

Eccu ciò chì a spec specìfica di a poda seria:

spec:
   tolerations:
     - key: "node-role.kubernetes.io/ingress"
        operator: "Equal"
        value: "true"
        effect: "NoSchedule"

Questu ùn significa micca chì durante a prossima redistribuzione, u pod chjappà esattamente stu node, questu ùn hè micca u mecanismu Node Affinity è nodeSelector. Ma cumminendu parechje funziunalità, pudete ottene una configurazione di pianificazione assai flexible.

8. Set Pod Deployment Priority

Solu perchè avete cunfiguratu l'associazioni pod-to-node ùn significa micca chì tutti i pods deve esse trattati cù a listessa priorità. Per esempiu, pudete vulete implementà alcuni Pods prima di l'altri.

Kubernetes offre diverse modi per stabilisce Pod Priority è Preemption. U paràmetru hè custituitu da parechje parte: ughjettu PriorityClass e descrizzioni di u campu priorityClassName in a specificazione di pod. Cunsiderate un esempiu:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 99999
globalDefault: false
description: "This priority class should be used for very important pods only"

Creemu PriorityClass, dà un nome, descrizzione è valore. U più altu value, più alta hè a priorità. U valore pò esse qualsiasi integer di 32-bit menu o uguale à 1 000 000 000. I valori più alti sò riservati per i pods di sistema criticu di missione, chì generalmente ùn ponu esse preempted. L'evacuazione sarà solu s'ellu u podu d'alta priorità ùn hà nudda parte per vultà, allora alcuni di i pods da un nodu particulari seranu evacuati. Se stu mecanismu hè troppu rigidu per voi, pudete aghjunghje l'opzione preemptionPolicy: Never, è dopu ùn ci sarà micca preemption, u pod serà u primu in a fila è aspittà chì u pianificatore truvà risorse gratuiti per questu.

In seguitu, creamu un pod, in quale spicificà u nome priorityClassName:

apiVersion: v1
kind: Pod
metadata:
  name: static-web
  labels:
    role: myrole
 spec:
  containers:
    - name: web
      image: nginx
      ports:
        - name: web
          containerPort: 80
          protocol: TCP
  priorityClassName: high-priority
          

Pudete creà tante classi priurità quant'è vo vulete, ancu s'ellu hè cunsigliatu per ùn esse micca purtatu cù questu (per dì, limitàvi à a priorità bassa, media è alta).

Cusì, se ne necessariu, pudete aumentà l'efficienza di implementà servizii critichi, cum'è nginx-ingress-controller, coredns, etc.

9. Optimize u vostru cluster ETCD

Nove cunsiglii di rendiment Kubernetes

ETCD pò esse chjamatu u cervellu di tuttu u cluster. Hè assai impurtante di mantene l'operazione di sta basa di dati à un altu livellu, postu chì a vitezza di l'operazioni in u "Cube" dipende da questu. Un abbastanza standard, è à u stessu tempu, una bona suluzione seria di mantene un cluster ETCD nantu à i nodi maestri per avè un ritardu minimu à kube-apiserver. S'ellu ùn hè micca pussibule, postu l'ETCD u più vicinu pussibule, cù una bona larghezza di banda trà i participanti. Fate ancu attenzione à quanti nodi da ETCD ponu cascà senza danni à u cluster.

Nove cunsiglii di rendiment Kubernetes

Mantene in mente chì un incrementu eccessivu di u numeru di participanti in u cluster pò aumentà a toleranza di difetti à a spesa di u rendiment, tuttu deve esse in moderazione.

Se parlemu di stallà u serviziu, allora ci sò pochi cunsiglii:

  1. Avè un bonu hardware, basatu annantu à a dimensione di u cluster (pudete leghje ccà).

  2. Tweak uni pochi di parametri si avete spargugliatu un cluster trà un paru di DC o a vostra rete è i dischi lascianu assai à desiderate (pudete leghje ccà).

cunchiusioni

Questu articulu descrive i punti chì a nostra squadra prova di rispettà. Questa ùn hè micca una descrizzione passu à passu di l'azzioni, ma l'opzioni chì ponu esse utili per ottimisà u sopratuttu di un cluster. Hè chjaru chì ogni cluster hè unicu in u so modu, è e soluzioni di tuning pò varià assai, per quessa, saria interessante per ottene feedback da voi: cumu monitorate u vostru cluster Kubernetes, cumu migliurà u so rendiment. Sparte a vostra sperienza in i cumenti, serà interessante di sapè.

Source: www.habr.com