10 veelgemaakte fouten bij het gebruik van Kubernetes

Opmerking. vert.: De auteurs van dit artikel zijn ingenieurs van een klein Tsjechisch bedrijf, pipetail. Ze zijn erin geslaagd een prachtige lijst samen te stellen van [soms banale, maar toch] zeer urgente problemen en misvattingen met betrekking tot de werking van Kubernetes-clusters.

10 veelgemaakte fouten bij het gebruik van Kubernetes

Door de jaren heen dat we Kubernetes gebruiken, hebben we met een groot aantal clusters gewerkt (zowel beheerd als onbeheerd - op GCP, AWS en Azure). Na verloop van tijd begonnen we te merken dat sommige fouten voortdurend werden herhaald. Dit is echter geen schande: het meeste hebben we zelf gedaan!

Het artikel bevat de meest voorkomende fouten en vermeldt ook hoe u deze kunt corrigeren.

1. Hulpmiddelen: verzoeken en limieten

Dit item verdient absoluut de meeste aandacht en de eerste plaats op de lijst.

CPU-verzoek meestal helemaal niet gespecificeerd of heeft een zeer lage waarde (om zoveel mogelijk pods op elk knooppunt te plaatsen). De knooppunten raken dus overbelast. In tijden van hoge belasting wordt de verwerkingskracht van het knooppunt volledig benut en ontvangt een bepaalde werklast alleen datgene waar het "gevraagd" door is. CPU-throttling. Dit leidt tot verhoogde applicatielatentie, time-outs en andere onaangename gevolgen. (Lees hierover meer in onze andere recente vertaling: “CPU-limieten en agressieve beperking in Kubernetes" - ca. vert.)

Beste poging (extreem geen aanbevolen):

resources: {}

Extreem laag CPU-verzoek (extreem geen aanbevolen):

   resources:
      Requests:
        cpu: "1m"

Aan de andere kant kan de aanwezigheid van een CPU-limiet leiden tot het onredelijk overslaan van klokcycli door pods, zelfs als de knooppuntprocessor niet volledig is geladen. Nogmaals, dit kan tot meer vertragingen leiden. De controverse rond de parameter blijft bestaan CPU CFS-quotum in de Linux-kernel en CPU-throttling afhankelijk van de ingestelde limieten, evenals het uitschakelen van de CFS-quota... Helaas kunnen CPU-limieten meer problemen veroorzaken dan ze kunnen oplossen. Meer informatie hierover vindt u via onderstaande link.

Overmatige selectie (te veel inzetten) Geheugenproblemen kunnen tot grotere problemen leiden. Het bereiken van de CPU-limiet houdt in dat klokcycli worden overgeslagen, terwijl het bereiken van de geheugenlimiet het doden van de pod met zich meebrengt. Heb je ooit waargenomen OOMmoord? Ja, dat is precies waar we het over hebben.

Wilt u de kans hierop zo klein mogelijk maken? Wijs niet te veel geheugen toe en gebruik gegarandeerde QoS (Quality of Service) door het geheugenverzoek op de limiet in te stellen (zoals in het onderstaande voorbeeld). Lees hierover meer in Henning Jacobs-presentaties (hoofdingenieur bij Zalando).

barstvast (grotere kans om door OOM gedood te worden):

   resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
      limits:
        memory: "256Mi"
        cpu: 2

Gegarandeerd:

   resources:
      requests:
        memory: "128Mi"
        cpu: 2
      limits:
        memory: "128Mi"
        cpu: 2

Wat kan mogelijk helpen bij het opzetten van hulpmiddelen?

Met metrische server u kunt het huidige CPU-bronverbruik en geheugengebruik per pods (en containers daarin) zien. Hoogstwaarschijnlijk gebruikt u het al. Voer gewoon de volgende opdrachten uit:

kubectl top pods
kubectl top pods --containers
kubectl top nodes

Ze tonen echter alleen het huidige gebruik. Het kan je een globaal idee geven van de orde van grootte, maar uiteindelijk zul je het nodig hebben geschiedenis van veranderingen in statistieken in de loop van de tijd (om vragen te beantwoorden als: “Wat was de maximale CPU-belasting?”, “Wat was de belasting gisterenochtend?”, enz.). Hiervoor kunt u gebruiken Prometheus, DataDog en andere hulpmiddelen. Ze halen eenvoudigweg de statistieken op van de metrics-server en slaan deze op, en de gebruiker kan ze opvragen en dienovereenkomstig in kaart brengen.

VerticalPodAutoscaler laat automatiseren dit proces. Het houdt de geschiedenis van het CPU- en geheugengebruik bij en stelt op basis van deze informatie nieuwe verzoeken en limieten in.

Het efficiënt gebruiken van rekenkracht is geen gemakkelijke taak. Het is alsof je de hele tijd Tetris speelt. Als u te veel betaalt voor rekenkracht met een laag gemiddeld verbruik (zeg ~10%), raden we u aan producten te bekijken die zijn gebaseerd op AWS Fargate of Virtual Kubelet. Ze zijn gebouwd op een serverloos/betalen-per-gebruik-factureringsmodel, dat onder dergelijke omstandigheden goedkoper kan uitvallen.

2. Liveness- en paraatheidssondes

Standaard zijn liveness- en gereedheidscontroles niet ingeschakeld in Kubernetes. En soms vergeten ze ze aan te zetten...

Maar hoe kunt u anders een serviceherstart starten in geval van een fatale fout? En hoe weet de load balancer dat een pod klaar is om verkeer te accepteren? Of dat het meer verkeer aankan?

Deze tests worden vaak met elkaar verward:

  • Levendigheid — “overlevingsvermogen”-controle, die de pod opnieuw opstart als deze faalt;
  • gereedheid — gereedheidscontrole, als deze mislukt, wordt de pod losgekoppeld van de Kubernetes-service (dit kan worden gecontroleerd met kubectl get endpoints) en er komt pas verkeer naar toe als de volgende controle met succes is voltooid.

Beide controles UITGEVOERD GEDURENDE DE HELE LEVENSCYCLUS VAN DE POD. Het is erg belangrijk.

Een veel voorkomende misvatting is dat gereedheidstests alleen worden uitgevoerd bij het opstarten, zodat de balancer kan weten dat de pod gereed is (Ready) en kan beginnen met het verwerken van verkeer. Dit is echter slechts een van de opties voor het gebruik ervan.

Een andere is de mogelijkheid om erachter te komen dat het verkeer op de pod buitensporig is overbelast het (of de pod voert resource-intensieve berekeningen uit). In dit geval helpt de gereedheidscontrole verminder de belasting van de pod en “koel” deze. Een succesvolle afronding van een gereedheidscontrole in de toekomst maakt dit mogelijk verhoog de belasting van de pod opnieuw. In dit geval (als de gereedheidstest mislukt) zou het mislukken van de liveness-test zeer contraproductief zijn. Waarom een ​​pod herstarten die gezond is en hard werkt?

Daarom is het in sommige gevallen beter om helemaal geen controles uit te voeren dan deze in te schakelen met onjuist geconfigureerde parameters. Zoals hierboven vermeld, als Levensduurcontrole Kopieën gereedheidscontrole, dan zit je in grote problemen. Mogelijke optie is configureren alleen gereedheidstestEn gevaarlijke levendigheid laten liggen.

Beide soorten controles mogen niet mislukken als algemene afhankelijkheden falen, anders zal dit leiden tot een trapsgewijze (lawine-achtige) mislukking van alle pods. Met andere woorden, doe jezelf geen kwaad.

3. LoadBalancer voor elke HTTP-service

Hoogstwaarschijnlijk heb je HTTP-services in je cluster die je graag wilt doorsturen naar de buitenwereld.

Als u de service opent als type: LoadBalancer, zal de controller (afhankelijk van de serviceprovider) een externe LoadBalancer leveren en erover onderhandelen (niet noodzakelijkerwijs draaiend op L7, maar eerder zelfs op L4), en dit kan van invloed zijn op de kosten (extern statisch IPv4-adres, rekenkracht, facturering per seconde ) vanwege de noodzaak om een ​​groot aantal van dergelijke hulpbronnen te creëren.

In dit geval is het veel logischer om één externe load balancer te gebruiken, waarbij services worden geopend als type: NodePort. Of beter nog: breid zoiets uit nginx-ingress-controller (Of Traefik), die de enige zal zijn Knooppuntpoort eindpunt dat is gekoppeld aan de externe load balancer en dat het verkeer in het cluster zal routeren met behulp van toegang-Kubernetes-bronnen.

Andere intra-cluster (micro)diensten die met elkaar communiceren, kunnen “communiceren” met behulp van diensten zoals ClusterIP en een ingebouwd servicedetectiemechanisme via DNS. Gebruik gewoon niet hun openbare DNS/IP, omdat dit de latentie kan beïnvloeden en de kosten van cloudservices kan verhogen.

4. Een cluster automatisch schalen zonder rekening te houden met de functies ervan

Wanneer u knooppunten toevoegt aan en verwijdert uit een cluster, moet u niet vertrouwen op bepaalde basisstatistieken, zoals het CPU-gebruik op die knooppunten. Bij de planning van pods moet met veel rekening worden gehouden beperkingen, zoals pod/node-affiniteit, besmettingen en toleranties, resourceverzoeken, QoS, enz. Het gebruik van een externe autoscaler die geen rekening houdt met deze nuances kan tot problemen leiden.

Stel je voor dat een bepaalde pod gepland zou moeten worden, maar alle beschikbare CPU-kracht wordt gevraagd/gedemonteerd en de pod vast komt te zitten in een staat Pending. Externe autoscaler ziet de gemiddelde huidige CPU-belasting (niet de gevraagde belasting) en initieert geen uitbreiding (uitvergroten) - voegt geen ander knooppunt toe. Als gevolg hiervan wordt deze pod niet gepland.

In dit geval omgekeerde schaling (inschalen) — het verwijderen van een knooppunt uit een cluster is altijd moeilijker te implementeren. Stel je voor dat je een stateful pod hebt (met aangesloten permanente opslag). Aanhoudende volumes behoort meestal tot specifieke beschikbaarheidszone en worden niet gerepliceerd in de regio. Als een externe autoscaler dus een knooppunt met deze pod verwijdert, kan de planner deze pod niet op een ander knooppunt plannen, omdat dit alleen kan worden gedaan in de beschikbaarheidszone waar de permanente opslag zich bevindt. De pod zit vast in de staat Pending.

Zeer populair in de Kubernetes-gemeenschap cluster-autoscaler. Het draait op een cluster, ondersteunt API’s van grote cloudproviders, houdt rekening met alle beperkingen en kan in bovengenoemde gevallen opschalen. Het is ook in staat om op te schalen met behoud van alle vastgestelde limieten, waardoor geld wordt bespaard (dat anders zou worden uitgegeven aan ongebruikte capaciteit).

5. Het verwaarlozen van IAM/RBAC-mogelijkheden

Pas op voor het gebruik van IAM-gebruikers met persistente geheimen voor machines en toepassingen. Organiseer tijdelijke toegang met behulp van rollen en serviceaccounts (serviceaccounts).

We komen vaak het feit tegen dat toegangssleutels (en geheimen) hardgecodeerd zijn in de applicatieconfiguratie, en dat we de rotatie van geheimen verwaarlozen ondanks toegang tot Cloud IAM. Gebruik indien nodig IAM-rollen en serviceaccounts in plaats van gebruikers.

10 veelgemaakte fouten bij het gebruik van Kubernetes

Vergeet kube2iam en ga direct naar IAM-rollen voor serviceaccounts (zoals beschreven in notitie met dezelfde naam Štěpán Vraný):

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-role
  name: my-serviceaccount
  namespace: default

Eén annotatie. Niet zo moeilijk, toch?

Geef ook geen serviceaccounts en instantieprofielrechten admin и cluster-adminals ze het niet nodig hebben. Dit is iets moeilijker te implementeren, vooral in RBAC K8s, maar zeker de moeite waard.

6. Vertrouw niet op automatische anti-affiniteit voor pods

Stel je voor dat je drie replica's van een bepaalde implementatie op een knooppunt hebt. Het knooppunt valt, en daarmee alle replica's. Onaangename situatie, toch? Maar waarom bevonden alle replica's zich op hetzelfde knooppunt? Moet Kubernetes geen hoge beschikbaarheid (HA) bieden?!

Helaas voldoet de Kubernetes-planner op eigen initiatief niet aan de regels van het gescheiden bestaan (anti-affiniteit) voor peulen. Ze moeten expliciet worden vermeld:

// опущено для краткости
      labels:
        app: zk
// опущено для краткости
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"

Dat is alles. Nu worden pods gepland op verschillende knooppunten (deze voorwaarde wordt alleen gecontroleerd tijdens de planning, maar niet tijdens hun werking - vandaar requiredDuringSchedulingIgnoredDuringExecution).

Hier hebben we het over podAntiAffinity op verschillende knooppunten: topologyKey: "kubernetes.io/hostname",- en niet over verschillende beschikbaarheidszones. Om een ​​volwaardige HA te implementeren, zul je dieper op dit onderwerp moeten ingaan.

7. PodDisruptionBudgets negeren

Stel je voor dat je een productiebelasting hebt op een Kubernetes-cluster. Van tijd tot tijd moeten knooppunten en het cluster zelf worden bijgewerkt (of buiten gebruik gesteld). PodDisruptionBudget (PDB) is zoiets als een servicegarantieovereenkomst tussen clusterbeheerders en gebruikers.

Met PDB kunt u serviceonderbrekingen voorkomen die worden veroorzaakt door een gebrek aan knooppunten:

apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: zookeeper

In dit voorbeeld zeg jij als gebruiker van het cluster tegen de beheerders: “Hé, ik heb een dierenverzorgerservice, en wat je ook doet, ik wil graag dat er altijd minimaal 2 replica’s van deze service beschikbaar zijn. .”

Hier kunt u meer over lezen hier.

8. Meerdere gebruikers of omgevingen in een gemeenschappelijk cluster

Kubernetes-naamruimten (naamruimten) bieden geen sterke isolatie.

Een veel voorkomende misvatting is dat als je een niet-prod-load in de ene naamruimte implementeert en een prod-load in een andere, deze zullen elkaar op geen enkele wijze beïnvloeden... Er kan echter een bepaald niveau van isolatie worden bereikt door middel van resourceverzoeken/beperkingen, het instellen van quota's en het instellen van prioriteitsklassen. Enige ‘fysieke’ isolatie op het datavlak wordt verzorgd door affiniteiten, toleranties, taints (of knooppuntselectors), maar een dergelijke scheiding is behoorlijk moeilijk implementeren.

Degenen die beide soorten werklasten in hetzelfde cluster moeten combineren, zullen te maken krijgen met complexiteit. Als zo'n behoefte niet bestaat en u het zich kunt veroorloven er een te hebben nog een cluster (bijvoorbeeld in een publieke cloud), dan is het beter om dat te doen. Hierdoor wordt een veel hoger isolatieniveau bereikt.

9. externVerkeersbeleid: Cluster

Heel vaak zien we dat al het verkeer binnen het cluster via een dienst als NodePort komt, waarvoor het standaardbeleid is ingesteld externalTrafficPolicy: Cluster... Het betekent dat Knooppuntpoort is geopend op elk knooppunt in het cluster en u kunt elk knooppunt gebruiken om te communiceren met de gewenste service (set peulen).

10 veelgemaakte fouten bij het gebruik van Kubernetes

Tegelijkertijd zijn echte pods die zijn gekoppeld aan de bovengenoemde NodePort-service meestal alleen op een bepaalde manier beschikbaar subset van deze knooppunten. Met andere woorden, als ik verbinding maak met een knooppunt dat niet over de vereiste pod beschikt, zal het verkeer doorsturen naar een ander knooppunt, een hop toevoegen en toenemende latentie (als knooppunten zich in verschillende beschikbaarheidszones/datacenters bevinden, kan de latentie behoorlijk hoog zijn; bovendien zullen de kosten van uitgaand verkeer toenemen).

Aan de andere kant, als er voor een bepaalde Kubernetes-service een beleid is ingesteld externalTrafficPolicy: Local, dan wordt NodePort alleen geopend op die knooppunten waar de vereiste pods daadwerkelijk worden uitgevoerd. Bij gebruik van een externe load balancer die de status controleert (gezondheidscontrole) eindpunten (hoe werkt het AWS ELB), Hij stuurt verkeer alleen naar de noodzakelijke knooppunten, wat een gunstig effect zal hebben op vertragingen, computerbehoeften en uitgaande rekeningen (en het gezond verstand dicteert hetzelfde).

De kans is groot dat je al zoiets gebruikt Traefik of nginx-ingress-controller als een NodePort-eindpunt (of LoadBalancer, dat ook NodePort gebruikt) om inkomend HTTP-verkeer te routeren, en het instellen van deze optie kan de latentie voor dergelijke verzoeken aanzienlijk verminderen.

В deze publicatie U kunt meer leren over externalTrafficPolicy en de voor- en nadelen ervan.

10. Laat je niet binden aan clusters en maak geen misbruik van het controlevlak

Voorheen was het gebruikelijk om servers met de juiste naam aan te roepen: Anton, HAL9000 en Colossus... Tegenwoordig zijn ze vervangen door willekeurig gegenereerde identificatiegegevens. De gewoonte bleef echter bestaan ​​en nu gaan eigennamen naar clusters.

Een typisch verhaal (gebaseerd op echte gebeurtenissen): het begon allemaal met een proof of concept, waardoor het cluster een trotse naam had het testen van... Jaren zijn verstreken en het wordt NOG STEEDS gebruikt in de productie, en iedereen is bang om het aan te raken.

Er is niets leuks aan clusters die in huisdieren veranderen, dus we raden aan ze tijdens het oefenen af ​​en toe te verwijderen herstel na een ramp (dit zal helpen chaos techniek — ca. vert.). Bovendien kan het geen kwaad om aan de controlelaag te werken (controlevlak). Bang zijn om hem aan te raken is geen goed teken. enz dood? Jongens, jullie zitten echt in de problemen!

Aan de andere kant moet je je niet laten meeslepen door het te manipuleren. Met tijd de controlelaag kan traag worden. Hoogstwaarschijnlijk komt dit doordat een groot aantal objecten wordt gemaakt zonder hun rotatie (een veel voorkomende situatie bij het gebruik van Helm met standaardinstellingen, en daarom wordt de status ervan in configmaps/secrets niet bijgewerkt - als resultaat accumuleren duizenden objecten in de besturingslaag) of met constante bewerking van kube-api-objecten (voor automatisch schalen, voor CI/CD, voor monitoring, gebeurtenislogboeken, controllers, enz.).

Daarnaast raden wij aan om de SLA/SLO afspraken met de beheerde Kubernetes provider te controleren en op de garanties te letten. De verkoper kan dit garanderen beschikbaarheid van de controlelaag (of de subcomponenten ervan), maar niet de p99-vertraging van verzoeken die u ernaar verzendt. Met andere woorden: je kunt binnenkomen kubectl get nodes, en ontvang pas na 10 minuten een antwoord, en dit is geen schending van de voorwaarden van de serviceovereenkomst.

11. Bonus: gebruik van de nieuwste tag

Maar dit is al een klassieker. De laatste tijd zijn we deze techniek minder vaak tegengekomen, omdat velen, na geleerd te hebben van bittere ervaringen, zijn gestopt met het gebruik van de tag :latest en begon versies vast te zetten. Hoera!

ECR handhaaft de onveranderlijkheid van afbeeldingstags; Wij raden u aan vertrouwd te raken met deze opmerkelijke functie.

Beknopt

Verwacht niet dat alles van de ene op de andere dag werkt: Kubernetes is geen wondermiddel. Slechte app zal zelfs in Kubernetes zo blijven (en het zal waarschijnlijk nog erger worden). Onzorgvuldigheid zal leiden tot overmatige complexiteit, langzaam en stressvol werk van de controlelaag. Bovendien loopt u het risico dat u geen noodherstelstrategie meer heeft. Verwacht niet dat Kubernetes out-of-the-box isolatie en hoge beschikbaarheid biedt. Besteed wat tijd om uw applicatie echt cloud-native te maken.

U kunt kennis maken met de mislukte ervaringen van verschillende teams in deze verzameling verhalen van Henning Jacobs.

Degenen die iets willen toevoegen aan de lijst met fouten in dit artikel, kunnen contact met ons opnemen via Twitter (@MarekBartik, @MstrsObserver).

PS van vertaler

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie