Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

27 april op de conferentie Staking 2019, als onderdeel van de sectie “DevOps” werd het rapport “Autoscaling en resource management in Kubernetes” gegeven. Er wordt besproken hoe u K8s kunt gebruiken om een ​​hoge beschikbaarheid van uw applicaties te garanderen en topprestaties te garanderen.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Traditiegetrouw presenteren wij u graag video van het rapport (44 minuten, veel informatiever dan het artikel) en de hoofdsamenvatting in tekstvorm. Gaan!

Laten we het onderwerp van het rapport woord voor woord analyseren en vanaf het einde beginnen.

Kubernetes

Laten we zeggen dat we Docker-containers op onze host hebben. Waarvoor? Om herhaalbaarheid en isolatie te garanderen, wat op zijn beurt een eenvoudige en goede implementatie mogelijk maakt, is CI/CD. We hebben veel van dergelijke voertuigen met containers.

Wat biedt Kubernetes in dit geval?

  1. We stoppen met denken aan deze machines en gaan werken met de “cloud” cluster van containers of peulen (groepen containers).
  2. Bovendien denken we niet eens aan individuele pods, maar beheren we meerоgrotere groepen. Zo een primitieven op hoog niveau laten we zeggen dat er een sjabloon is voor het uitvoeren van een bepaalde werklast, en hier is het vereiste aantal instanties om deze uit te voeren. Als we vervolgens de sjabloon wijzigen, veranderen alle instanties.
  3. Met declaratieve API In plaats van een reeks specifieke opdrachten uit te voeren, beschrijven we de ‘structuur van de wereld’ (in YAML), die is gemaakt door Kubernetes. En nogmaals: wanneer de beschrijving verandert, verandert ook de daadwerkelijke weergave ervan.

авление есурсами

CPU

Laten we nginx, php-fpm en mysql op de server draaien. Deze services zullen zelfs nog meer processen uitvoeren, die elk computerbronnen vereisen:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)
(de cijfers op de dia zijn “papegaaien”, de abstracte behoefte van elk proces aan rekenkracht)

Om het makkelijker te maken hiermee te werken, is het logisch om processen in groepen te combineren (bijvoorbeeld alle nginx-processen in één groep “nginx”). Een eenvoudige en voor de hand liggende manier om dit te doen is door elke groep in een container te plaatsen:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Om door te gaan, moet je onthouden wat een container is (in Linux). Hun verschijning werd mogelijk gemaakt dankzij drie belangrijke functies in de kernel, die al lang geleden waren geïmplementeerd: mogelijkheden, namespaces и cgroepen. En verdere ontwikkeling werd mogelijk gemaakt door andere technologieën (waaronder handige “shells” zoals Docker):

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

In de context van het rapport zijn wij alleen geïnteresseerd in cgroepen, omdat stuurgroepen het deel vormen van de functionaliteit van containers (Docker, enz.) dat resourcebeheer implementeert. Processen die, zoals we wilden, in groepen zijn gecombineerd, zijn controlegroepen.

Laten we terugkeren naar de CPU-vereisten voor deze processen, en nu voor groepen processen:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)
(Ik herhaal dat alle cijfers een abstracte uitdrukking zijn van de behoefte aan hulpbronnen)

Tegelijkertijd beschikt de CPU zelf over een bepaalde eindige hulpbron (in het voorbeeld is dit 1000), die iedereen misschien mist (de som van de behoeften van alle groepen is 150+850+460=1460). Wat zal er in dit geval gebeuren?

De kernel begint hulpbronnen te verdelen en doet dit “eerlijk”, waarbij aan elke groep dezelfde hoeveelheid hulpbronnen wordt gegeven. Maar in het eerste geval zijn er meer dan nodig (333>150), dus het overschot (333-150=183) blijft in reserve, die ook gelijk wordt verdeeld over twee andere containers:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Het gevolg was dat de eerste container genoeg grondstoffen had, de tweede – niet genoeg grondstoffen, en de derde – niet genoeg grondstoffen. Dit is het resultaat van acties "eerlijke" planner in Linux - CVS. Via de toewijzing kan de werking ervan worden aangepast gewicht elk van de containers. Bijvoorbeeld zoals dit:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Laten we eens kijken naar het geval van een gebrek aan bronnen in de tweede container (php-fpm). Alle containerresources worden gelijkelijk verdeeld tussen processen. Als gevolg hiervan werkt het hoofdproces goed, maar alle werknemers vertragen en ontvangen minder dan de helft van wat ze nodig hebben:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Dit is hoe de CFS-planner werkt. De gewichten die we aan containers toekennen noemen we verder verzoeken. Waarom dit zo is - zie verder.

Laten we de hele situatie eens van de andere kant bekijken. Zoals u weet leiden alle wegen naar Rome, en in het geval van een computer naar de CPU. Eén CPU, veel taken - je hebt een stoplicht nodig. De eenvoudigste manier om bronnen te beheren is “verkeerslicht”: ze gaven het ene proces een vaste toegangstijd tot de CPU, vervolgens het volgende, enz.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Deze aanpak wordt harde quota genoemd (harde beperking). Laten we het eenvoudigweg onthouden als grenzen. Als u echter limieten over alle containers verdeelt, ontstaat er een probleem: mysql reed langs de weg en op een gegeven moment eindigde de behoefte aan CPU, maar alle andere processen worden gedwongen te wachten totdat de CPU inactief.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Laten we terugkeren naar de Linux-kernel en zijn interactie met de CPU - het algemene beeld is als volgt:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

cgroup heeft twee instellingen - in wezen zijn dit twee eenvoudige "wendingen" waarmee u kunt bepalen:

  1. gewicht voor container (aanvragen) is aandelen;
  2. percentage van de totale CPU-tijd voor het werken aan containertaken (limieten) is quotum.

Hoe CPU meten?

Er zijn verschillende manieren:

  1. Wat papegaaien, niemand weet het - je moet elke keer onderhandelen.
  2. interest duidelijker, maar relatief: 50% van een server met 4 cores en met 20 cores zijn compleet verschillende dingen.
  3. U kunt de reeds genoemde gebruiken gewicht, wat Linux weet, maar ze zijn ook relatief.
  4. De meest adequate optie is het meten van computerbronnen seconden. Die. in seconden processortijd ten opzichte van seconden realtime: er werd 1 seconde processortijd gegeven per 1 echte seconde - dit is één volledige CPU-kern.

Om het nog gemakkelijker te maken om te spreken, begonnen ze rechtstreeks in te meten kernels, wat betekent dat ze dezelfde CPU-tijd hebben als de echte. Omdat Linux gewichten begrijpt, maar niet zozeer CPU-tijd/cores, was er een mechanisme nodig om van de een naar de ander te vertalen.

Laten we een eenvoudig voorbeeld bekijken met een server met 3 CPU-kernen, waarbij drie pods gewichten krijgen (500, 1000 en 1500) die gemakkelijk kunnen worden omgezet naar de overeenkomstige delen van de kernen die eraan zijn toegewezen (0,5, 1 en 1,5).

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Als je een tweede server neemt, waar twee keer zoveel cores zullen zijn (6), en daar dezelfde pods plaatst, kan de verdeling van cores eenvoudig worden berekend door simpelweg te vermenigvuldigen met 2 (respectievelijk 1, 2 en 3). Maar een belangrijk moment doet zich voor wanneer een vierde pod op deze server verschijnt, waarvan het gewicht, voor het gemak, 3000 zal zijn. Het neemt een deel van de CPU-bronnen weg (de helft van de cores), en voor de resterende pods worden ze opnieuw berekend (gehalveerd):

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Kubernetes en CPU-bronnen

In Kubernetes worden CPU-bronnen meestal gemeten milliadrax, d.w.z. Als basisgewicht worden 0,001 kernen genomen. (Hetzelfde wordt in de Linux/cgroups-terminologie een CPU-share genoemd, hoewel, preciezer gezegd, 1000 millicores = 1024 CPU-shares.) K8s zorgt ervoor dat er niet meer pods op de server worden geplaatst dan er CPU-bronnen zijn voor de som van de gewichten van alle pods.

Hoe gebeurde dit? Wanneer u een server aan een Kubernetes-cluster toevoegt, wordt gerapporteerd hoeveel CPU-cores deze beschikbaar heeft. En bij het maken van een nieuwe pod weet de Kubernetes-planner hoeveel cores deze pod nodig heeft. De pod wordt dus toegewezen aan een server waar voldoende kernen zijn.

Wat gebeurt er als geen verzoek is opgegeven (dat wil zeggen dat de pod niet over een bepaald aantal kernen beschikt)? Laten we eens kijken hoe Kubernetes in het algemeen resources telt.

Voor een pod kunt u zowel verzoeken (CFS-planner) als limieten opgeven (herinner u zich het stoplicht?):

  • Als ze gelijk zijn opgegeven, wordt aan de pod een QoS-klasse toegewezen gegarandeerde. Dit aantal kernen dat altijd beschikbaar is, is gegarandeerd.
  • Als het verzoek kleiner is dan de limiet: QoS-klasse barstbaar. Die. We verwachten bijvoorbeeld dat een pod altijd 1 core gebruikt, maar deze waarde is daarvoor geen beperking: soms pod kan meer gebruiken (als de server hiervoor vrije bronnen heeft).
  • Er is ook een QoS-klasse beste poging — het omvat juist die peulen waarvoor het verzoek niet is gespecificeerd. De middelen worden als laatste aan hen gegeven.

Память

Met geheugen is de situatie vergelijkbaar, maar enigszins anders - de aard van deze bronnen is immers anders. Over het algemeen is de analogie als volgt:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Laten we eens kijken hoe verzoeken in het geheugen worden geïmplementeerd. Laat de pods op de server staan, waardoor het geheugengebruik verandert, totdat een van hen zo groot wordt dat er geen geheugen meer beschikbaar is. In dit geval verschijnt de OOM-killer en doodt het grootste proces:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Dit komt ons niet altijd uit en daarom is het mogelijk om te reguleren welke processen voor ons belangrijk zijn en niet mogen worden gedood. Gebruik hiervoor de parameter oom_score_adj.

Laten we terugkeren naar de QoS-klassen van de CPU en een analogie trekken met de oom_score_adj-waarden die de geheugenverbruikprioriteiten voor pods bepalen:

  • De laagste oom_score_adj-waarde voor een pod - -998 - betekent dat een dergelijke pod als laatste moet worden gedood. gegarandeerde.
  • Het hoogste – 1000 – is beste poging, worden dergelijke peulen eerst gedood.
  • Om de resterende waarden te berekenen (barstbaar) bestaat er een formule waarvan de essentie neerkomt op het feit dat hoe meer grondstoffen een peul heeft gevraagd, hoe kleiner de kans is dat hij wordt gedood.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

De tweede "draai" - limit_in_bytes - voor grenzen. Hiermee is alles eenvoudiger: we wijzen eenvoudigweg de maximale hoeveelheid uitgegeven geheugen toe, en hier (in tegenstelling tot de CPU) is er geen sprake van hoe we dit moeten meten (geheugen).

In totaal

Elke pod in Kubernetes wordt gegeven requests и limits - beide parameters voor CPU en geheugen:

  1. op basis van verzoeken werkt de Kubernetes-planner, die pods onder servers verdeelt;
  2. op basis van alle parameters wordt de QoS-klasse van de pod bepaald;
  3. Relatieve gewichten worden berekend op basis van CPU-verzoeken;
  4. de CFS-planner wordt geconfigureerd op basis van CPU-verzoeken;
  5. OOM killer wordt geconfigureerd op basis van geheugenverzoeken;
  6. er wordt een “verkeerslicht” geconfigureerd op basis van CPU-limieten;
  7. Op basis van geheugenlimieten wordt een limiet geconfigureerd voor de cgroup.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Over het algemeen beantwoordt dit beeld alle vragen over hoe het grootste deel van resourcebeheer plaatsvindt in Kubernetes.

Automatisch schalen

K8s cluster-autoscaler

Laten we ons voorstellen dat het hele cluster al bezet is en dat er een nieuwe pod moet worden gemaakt. Hoewel de pod niet kan verschijnen, blijft deze in status hangen In behandeling. Om het te laten verschijnen, kunnen we een nieuwe server met het cluster verbinden of... cluster-autoscaler installeren, die het voor ons doet: een virtuele machine bestellen bij de cloudprovider (met behulp van een API-verzoek) en deze verbinden met het cluster , waarna de pod wordt toegevoegd.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Dit is het automatisch schalen van het Kubernetes-cluster, wat prima werkt (naar onze ervaring). Maar net als elders zijn er hier enkele nuances...

Zolang we de clustergrootte vergrootten, was alles in orde, maar wat gebeurt er als het cluster begon zichzelf te bevrijden? Het probleem is dat het migreren van pods (om hosts vrij te maken) technisch gezien erg moeilijk en duur is in termen van middelen. Kubernetes hanteert een geheel andere aanpak.

Overweeg een cluster van drie servers met implementatie. Het heeft 3 pods: nu zijn er 6 voor elke server. Om de een of andere reden wilden we een van de servers uitschakelen. Om dit te doen zullen we het commando gebruiken kubectl drain, welke:

  • zal het verzenden van nieuwe pods naar deze server verbieden;
  • verwijdert bestaande pods op de server.

Omdat Kubernetes verantwoordelijk is voor het handhaven van het aantal pods (6), is dit eenvoudigweg het geval zal recreëren ze op andere knooppunten, maar niet op het knooppunt dat is uitgeschakeld, omdat het al is gemarkeerd als niet beschikbaar voor het hosten van nieuwe pods. Dit is een fundamenteel mechanisme voor Kubernetes.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Toch is er ook hier een nuance. In een vergelijkbare situatie zullen de acties voor StatefulSet (in plaats van Deployment) anders zijn. Nu hebben we al een stateful applicatie - bijvoorbeeld drie pods met MongoDB, waarvan er één een probleem heeft (de gegevens zijn beschadigd of een andere fout waardoor de pod niet correct kan opstarten). En we besluiten opnieuw één server uit te schakelen. Wat zal er gebeuren?

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

MongoDB kon sterven omdat er een quorum nodig is: voor een cluster van drie installaties moeten er minstens twee functioneren. Echter, dit gebeurt niet - dankzij PodVerstoringBudget. Deze parameter bepaalt het minimaal vereiste aantal werkpods. Wetende dat een van de MongoDB-pods niet meer werkt, en zien dat PodDisruptionBudget is ingesteld voor MongoDB minAvailable: 2, staat Kubernetes niet toe dat u een pod verwijdert.

Kort gezegd: om ervoor te zorgen dat de verplaatsing (en in feite het opnieuw maken) van pods correct werkt wanneer het cluster wordt vrijgegeven, is het noodzakelijk om PodDisruptionBudget te configureren.

Horizontale schaling

Laten we een andere situatie bekijken. Er draait een applicatie als Deployment in Kubernetes. Gebruikersverkeer komt naar de pods (er zijn er bijvoorbeeld drie) en we meten daarin een bepaalde indicator (bijvoorbeeld CPU-belasting). Wanneer de belasting toeneemt, registreren we dit volgens een schema en verhogen we het aantal pods om verzoeken te distribueren.

Tegenwoordig hoeft dit in Kubernetes niet handmatig te gebeuren: een automatische toename/afname van het aantal pods wordt geconfigureerd afhankelijk van de waarden van de gemeten belastingsindicatoren.

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

De belangrijkste vragen hier zijn: wat je precies moet meten и hoe te interpreteren verkregen waarden (voor het nemen van een beslissing over het wijzigen van het aantal pods). Je kunt veel meten:

Autoscaling en resourcebeheer in Kubernetes (overzicht en videorapport)

Hoe dit technisch te doen: verzamel statistieken, enz. — Ik heb er in het rapport uitvoerig over gesproken Monitoring en Kubernetes. En het belangrijkste advies voor het kiezen van de optimale parameters is experiment!

Er is GEBRUIK-methode (Gebruiksverzadiging en fouten), waarvan de betekenis als volgt is. Op welke basis is het zinvol om bijvoorbeeld php-fpm te schalen? Dit is gebaseerd op het feit dat de werknemers opraken benutting. En als de arbeiders voorbij zijn en nieuwe verbindingen niet worden geaccepteerd, is dit al het geval verzadiging. Beide parameters moeten worden gemeten en afhankelijk van de waarden moet er worden geschaald.

In plaats Output

Het rapport heeft een vervolg: over verticaal schalen en hoe je de juiste middelen selecteert. Ik zal hierover praten in toekomstige video's op onze YouTube - abonneer je zodat je niets mist!

Video's en dia's

Video van de voorstelling (44 minuten):

Presentatie van het rapport:

PS

Andere reportages over Kubernetes op onze blog:

Bron: www.habr.com

Voeg een reactie