Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

27 d'abril a la conferència Vaga 2019, com a part de la secció "DevOps", es va presentar l'informe "Escaling automàtic i gestió de recursos a Kubernetes". Parla de com podeu utilitzar K8s per garantir una alta disponibilitat de les vostres aplicacions i garantir el màxim rendiment.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Per tradició, ens complau presentar vídeo del reportatge (44 minuts, molt més informatiu que l'article) i el resum principal en forma de text. Va!

Analitzem el tema de l'informe paraula per paraula i comencem pel final.

Kubernetes

Suposem que tenim contenidors Docker al nostre amfitrió. Per a què? Per garantir la repetibilitat i l'aïllament, que al seu torn permet un desplegament senzill i correcte, CI/CD. Tenim molts d'aquests vehicles amb contenidors.

Què ofereix Kubernetes en aquest cas?

  1. Deixem de pensar en aquestes màquines i comencem a treballar amb el "núvol" agrupació de contenidors o beines (grups de contenidors).
  2. A més, ni tan sols pensem en beines individuals, sinó que gestionem mésоgrups més grans. Tal primitives d'alt nivell ens permet dir que hi ha una plantilla per executar una determinada càrrega de treball, i aquí teniu el nombre d'instàncies necessaris per executar-la. Si posteriorment canviem la plantilla, totes les instàncies canviaran.
  3. Amb API declarativa En lloc d'executar una seqüència d'ordres específiques, descrivim l'"estructura del món" (en YAML), que és creada per Kubernetes. I de nou: quan la descripció canvia, la seva visualització real també canviarà.

Gestió de recursos

CPU

Executem nginx, php-fpm i mysql al servidor. En realitat, aquests serveis tindran encara més processos en execució, cadascun dels quals requereix recursos informàtics:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)
(els números de la diapositiva són "loros", la necessitat abstracta de cada procés de poder de càlcul)

Per facilitar el treball amb això, és lògic combinar processos en grups (per exemple, tots els processos nginx en un sol grup "nginx"). Una manera senzilla i òbvia de fer-ho és posar cada grup en un contenidor:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Per continuar, heu de recordar què és un contenidor (a Linux). La seva aparició va ser possible gràcies a tres característiques clau del nucli, implementades fa força temps: capacitats, espais de noms и cgroups. I el desenvolupament posterior es va facilitar per altres tecnologies (incloses les "petxines" convenients com Docker):

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

En el context de l'informe, només ens interessa cgroups, perquè els grups de control són la part de la funcionalitat dels contenidors (Docker, etc.) que implementa la gestió de recursos. Els processos combinats en grups, com volíem, són grups de control.

Tornem als requisits de CPU per a aquests processos, i ara per als grups de processos:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)
(Repeteixo que tots els números són una expressió abstracta de la necessitat de recursos)

Al mateix temps, la CPU mateixa té un determinat recurs finit (en l'exemple això és 1000), que pot mancar a tothom (la suma de les necessitats de tots els grups és 150+850+460=1460). Què passarà en aquest cas?

El nucli comença a distribuir recursos i ho fa “de manera justa”, donant la mateixa quantitat de recursos a cada grup. Però en el primer cas, n'hi ha més del necessari (333>150), de manera que l'excés (333-150=183) queda en reserva, que també es reparteix a parts iguals entre altres dos contenidors:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Com a resultat: el primer contenidor tenia prou recursos, el segon –no tenia prou recursos, el tercer– no tenia prou recursos. Aquest és el resultat de les accions planificador "honest" a Linux - Síndrome de fatiga crònica. El seu funcionament es pot ajustar mitjançant l'assignació pesos cadascun dels contenidors. Per exemple, així:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Vegem el cas de manca de recursos al segon contenidor (php-fpm). Tots els recursos dels contenidors es reparteixen per igual entre processos. Com a resultat, el procés mestre funciona bé, però tots els treballadors s'alenteixen i reben menys de la meitat del que necessiten:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Així és com funciona el programador CFS. A més anomenarem els pesos que assignem als contenidors peticions. Per què és així - vegeu més endavant.

Vegem tota la situació des de l'altra banda. Com sabeu, tots els camins porten a Roma, i en el cas d'un ordinador, a la CPU. Una CPU, moltes tasques: necessiteu un semàfor. La manera més senzilla de gestionar els recursos és el "semàfor": donaven a un procés un temps d'accés fix a la CPU, després al següent, etc.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Aquest enfocament s'anomena quotes dures (limitació difícil). Recordem-ho simplement com límits. Tanmateix, si distribuïu límits a tots els contenidors, sorgeix un problema: mysql circulava per la carretera i en algun moment es va acabar la seva necessitat de CPU, però tots els altres processos es veuen obligats a esperar fins que la CPU ociós.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Tornem al nucli de Linux i la seva interacció amb la CPU: la imatge general és la següent:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

cgroup té dos paràmetres, bàsicament aquests són dos "girs" senzills que us permeten determinar:

  1. el pes del contenidor (sol·licituds) és accions;
  2. percentatge del temps total de la CPU per treballar en tasques de contenidors (límits). quota.

Com mesurar la CPU?

Hi ha diferents maneres:

  1. Què és lloros, ningú ho sap: cal negociar cada vegada.
  2. Interès més clar, però relatiu: el 50% d'un servidor amb 4 nuclis i amb 20 nuclis són coses completament diferents.
  3. Podeu utilitzar els ja esmentats pesos, que Linux coneix, però també són relatius.
  4. L'opció més adequada és mesurar els recursos informàtics segons. Aquells. en segons de temps del processador en relació amb segons de temps real: s'ha donat 1 segon de temps de processador per 1 segon real; això és un nucli de CPU sencer.

Per facilitar encara més la paraula, van començar a mesurar directament nuclis, és a dir, per ells el mateix temps de CPU en relació amb el real. Com que Linux entén els pesos, però no tant el temps/nuclis de la CPU, es necessitava un mecanisme per traduir d'un a l'altre.

Considerem un exemple senzill amb un servidor amb 3 nuclis de CPU, on se'ls donarà pes a tres pods (500, 1000 i 1500) que es poden convertir fàcilment a les parts corresponents dels nuclis assignats a ells (0,5, 1 i 1,5).

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Si agafeu un segon servidor, on hi haurà el doble de nuclis (6), i hi col·loqueu els mateixos pods, la distribució de nuclis es pot calcular fàcilment multiplicant-lo simplement per 2 (1, 2 i 3, respectivament). Però es produeix un moment important quan en aquest servidor apareix un quart pod, el pes del qual, per comoditat, serà de 3000. Treu part dels recursos de la CPU (la meitat dels nuclis), i per als pods restants es tornen a calcular (a la meitat):

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Kubernetes i recursos de CPU

A Kubernetes, normalment es mesuren els recursos de la CPU miliadrax, és a dir Es prenen 0,001 nuclis com a pes base. (El mateix en terminologia de Linux/cgroups s'anomena CPU compartida, encara que, més precisament, 1000 milicores = 1024 CPU compartides). K8s assegura que no col·loca més pods al servidor dels que hi ha recursos de CPU per a la suma dels pesos de tots els pods.

Com passa això? Quan afegiu un servidor a un clúster de Kubernetes, s'informa de quants nuclis de CPU té disponibles. I quan es crea un pod nou, el planificador de Kubernetes sap quants nuclis necessitarà aquest pod. Així, el pod s'assignarà a un servidor on hi hagi prou nuclis.

Què passarà si no s'especifica la sol·licitud (és a dir, el pod no té un nombre definit de nuclis que necessita)? Anem a esbrinar com Kubernetes compta generalment els recursos.

Per a un pod, podeu especificar tant sol·licituds (programador CFS) com límits (recordeu el semàfor?):

  • Si s'especifiquen iguals, al pod s'assigna una classe de QoS garantit. Aquest nombre de nuclis sempre a la seva disposició està garantit.
  • Si la sol·licitud és inferior al límit, classe QoS esclatable. Aquells. Esperem que un pod, per exemple, utilitzi sempre 1 nucli, però aquest valor no és una limitació: de vegades pod pot utilitzar-ne més (quan el servidor té recursos gratuïts per a això).
  • També hi ha una classe de QoS el millor esforç — inclou aquells mateixos pods per als quals no s'especifica la sol·licitud. Els recursos se'ls donen per últim.

Память

Amb la memòria, la situació és similar, però lleugerament diferent; després de tot, la naturalesa d'aquests recursos és diferent. En general, l'analogia és la següent:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Vegem com s'implementen les peticions a la memòria. Deixeu que els pods visquin al servidor, canviant el consum de memòria, fins que un d'ells es faci tan gran que es quedi sense memòria. En aquest cas, apareix l'assassí OOM i mata el procés més gran:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Això no sempre ens convé, de manera que és possible regular quins processos són importants per a nosaltres i que no s'han de matar. Per fer-ho, utilitzeu el paràmetre oom_score_adj.

Tornem a les classes de QoS de la CPU i fem una analogia amb els valors oom_score_adj que determinen les prioritats de consum de memòria per als pods:

  • El valor oom_score_adj més baix per a un pod (-998) significa que aquest pod s'hauria de matar l'últim, això garantit.
  • El més alt - 1000 - és el millor esforç, aquestes beines es maten primer.
  • Per calcular els valors restants (esclatable) hi ha una fórmula, l'essència de la qual es redueix al fet que com més recursos hagi demanat una beina, menys probabilitats hi ha de ser assassinat.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

El segon "gir" - limit_in_bytes - pels límits. Amb ell, tot és més senzill: simplement assignem la quantitat màxima de memòria emesa, i aquí (a diferència de la CPU) no hi ha dubte de com mesurar-la (memòria).

En total

Cada pod a Kubernetes es dóna requests и limits - ambdós paràmetres per a la CPU i la memòria:

  1. a partir de les sol·licituds, funciona el planificador de Kubernetes, que distribueix pods entre servidors;
  2. en funció de tots els paràmetres, es determina la classe de QoS del pod;
  3. Els pesos relatius es calculen en funció de les peticions de la CPU;
  4. el planificador CFS es configura en funció de les peticions de la CPU;
  5. OOM killer es configura en funció de les peticions de memòria;
  6. es configura un "semàfor" en funció dels límits de la CPU;
  7. En funció dels límits de memòria, es configura un límit per al grup c.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

En general, aquesta imatge respon a totes les preguntes sobre com es produeix la part principal de la gestió de recursos a Kubernetes.

Autoescala

Escalador automàtic de clúster K8s

Imaginem que tot el clúster ja està ocupat i cal crear un nou pod. Tot i que el pod no pot aparèixer, es penja en estat Pendent. Perquè aparegui, podem connectar un nou servidor al clúster o... instal·lar cluster-autoscaler, que ho farà per nosaltres: demanar una màquina virtual al proveïdor del núvol (mitjançant una sol·licitud d'API) i connectar-la al clúster. , després del qual s'afegirà la beina .

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Es tracta de l'escala automàtica del clúster Kubernetes, que funciona molt bé (segons la nostra experiència). Tanmateix, com en altres llocs, aquí hi ha alguns matisos...

Mentre augmentem la mida del clúster, tot anava bé, però què passa quan el clúster va començar a alliberar-se? El problema és que migrar pods (per alliberar amfitrions) és tècnicament molt difícil i costós en termes de recursos. Kubernetes utilitza un enfocament completament diferent.

Penseu en un clúster de 3 servidors amb desplegament. Té 6 pods: ara n'hi ha 2 per a cada servidor. Per alguna raó hem volgut apagar un dels servidors. Per fer-ho utilitzarem l'ordre kubectl drain, quin:

  • prohibirà enviar pods nous a aquest servidor;
  • suprimirà els pods existents al servidor.

Com que Kubernetes és responsable de mantenir el nombre de pods (6), simplement recrearà en altres nodes, però no en el que està desactivat, ja que ja està marcat com a no disponible per allotjar nous pods. Aquesta és una mecànica fonamental per a Kubernetes.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Tanmateix, aquí també hi ha un matís. En una situació similar, per StatefulSet (en lloc de Deployment), les accions seran diferents. Ara ja tenim una aplicació amb estat, per exemple, tres pods amb MongoDB, un dels quals té algun tipus de problema (les dades s'han malmès o un altre error que impedeix que el pod s'iniciï correctament). I tornem a decidir desactivar un servidor. Què passarà?

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

MongoDB podria morir perquè necessita un quòrum: per a un clúster de tres instal·lacions, almenys dues han de funcionar. No obstant això, això no passa - gràcies a PodDisruptionBudget. Aquest paràmetre determina el nombre mínim requerit de beines de treball. Saber que un dels pods de MongoDB ja no funciona i veure que PodDisruptionBudget està establert per a MongoDB minAvailable: 2, Kubernetes no us permetrà suprimir un pod.

Conclusió: perquè el moviment (i, de fet, la recreació) de pods funcioni correctament quan s'allibera el clúster, cal configurar PodDisruptionBudget.

Escalat horitzontal

Considerem una altra situació. Hi ha una aplicació que s'executa com a Deployment a Kubernetes. El trànsit d'usuaris arriba als seus pods (per exemple, n'hi ha tres) i hi mesurem un determinat indicador (per exemple, la càrrega de la CPU). Quan la càrrega augmenta, l'enregistrem en una programació i augmentem el nombre de pods per distribuir les sol·licituds.

Avui a Kubernetes això no cal fer-ho manualment: es configura un augment/disminució automàtic del nombre de pods en funció dels valors dels indicadors de càrrega mesurats.

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Les preguntes principals aquí són: què mesurar exactament и com interpretar valors obtinguts (per prendre una decisió sobre el canvi del nombre de beines). Pots mesurar molt:

Autoscaling i gestió de recursos a Kubernetes (visió general i informe de vídeo)

Com fer-ho tècnicament: recopilar mètriques, etc. — Vaig parlar amb detall a l'informe Monitorització i Kubernetes. I el principal consell per triar els paràmetres òptims és experiment!

Hi Mètode USE (Saturació d'utilització i errors), el significat del qual és el següent. Sobre quina base té sentit escalar, per exemple, php-fpm? A partir del fet que els treballadors s'esgoten, això és utilització. I si s'acaben els treballadors i no s'accepten noves connexions, això ja està saturació. Aquests dos paràmetres s'han de mesurar i, en funció dels valors, s'ha de fer l'escalat.

En lloc d'una conclusió

L'informe té una continuació: sobre l'escala vertical i com seleccionar els recursos adequats. En parlaré en propers vídeos el nostre YouTube - Subscriu-te perquè no t'ho perdis!

Vídeos i diapositives

Vídeo de l'actuació (44 minuts):

Presentació de l'informe:

PS

Altres informes sobre Kubernetes al nostre bloc:

Font: www.habr.com

Afegeix comentari