Liveness-sonder i Kubernetes kan vara farliga

Notera. transl.: Ledande ingenjör från Zalando, Henning Jacobs, har upprepade gånger märkt problem bland Kubernetes-användare med att förstå syftet med liveness- (och beredskaps)prober och deras korrekta användning. Därför samlade han sina tankar i denna rymliga anteckning, som så småningom kommer att bli en del av K8s dokumentation.

Liveness-sonder i Kubernetes kan vara farliga

Hälsokontroller, känd i Kubernetes som livhetssonder (dvs. bokstavligen "viabilitetstester" - ungefärlig översättning), kan vara ganska farligt. Jag rekommenderar att du undviker dem om möjligt: ​​de enda undantagen är när de verkligen är nödvändiga och du är fullt medveten om detaljerna och konsekvenserna av deras användning. Den här publikationen kommer att tala om kontroller av livlighet och beredskap, och kommer också att berätta i vilka fall Kostnad och du ska inte använda dem.

Min kollega Sandor delade nyligen på Twitter de vanligaste felen han stöter på, inklusive de som är relaterade till användningen av beredskaps-/liveness-sonder:

Liveness-sonder i Kubernetes kan vara farliga

Felaktigt konfigurerad livenessProbe kan förvärra situationer med hög belastning (avstängning av snöboll + potentiellt lång starttid för behållare/applikationer) och leda till andra negativa konsekvenser såsom minskat beroende (se även min senaste artikel om att begränsa antalet förfrågningar i kombinationen K3s+ACME). Det är ännu värre när liveness-sonden kombineras med en hälsokontroll, som är en extern databas: ett enda DB-fel kommer att starta om alla dina behållare!

Allmänt meddelande "Använd inte livhetssonder" i det här fallet hjälper det inte mycket, så låt oss titta på vad beredskaps- och livlighetskontrollerna är till för.

Obs: Det mesta av testet nedan ingick ursprungligen i Zalandos interna utvecklardokumentation.

Beredskaps- och Liveness-kontroller

Kubernetes tillhandahåller två viktiga mekanismer som kallas livhetssonder och beredskapssonder. De utför med jämna mellanrum någon åtgärd – som att skicka en HTTP-begäran, öppna en TCP-anslutning eller utföra ett kommando i behållaren – för att bekräfta att programmet fungerar som förväntat.

Kubernetes använder beredskapssonderför att förstå när behållaren är redo att ta emot trafik. En pod anses vara klar att användas om alla dess behållare är klara. En användning av denna mekanism är att kontrollera vilka pods som används som backends för Kubernetes-tjänster (och speciellt Ingress).

Liveness prober hjälpa Kubernetes att förstå när det är dags att starta om behållaren. En sådan kontroll låter dig till exempel fånga ett dödläge när en applikation fastnar på ett ställe. Att starta om behållaren i detta tillstånd hjälper till att få applikationen igång trots fel, men det kan också leda till kaskadfel (se nedan).

Om du försöker distribuera en programuppdatering som inte klarar av kontrollerna av liveness/beredskap, kommer dess utrullning att stoppas när Kubernetes väntar på status Ready från alla baljor.

Exempel

Här är ett exempel på en beredskapssond som kontrollerar en väg /health via HTTP med standardinställningar (intervall: 10 sekunder, timeout: 1 sekund, framgångströskeln: 1, feltröskel: 3):

# часть общего описания deployment'а/стека
podTemplate:
  spec:
    containers:
    - name: my-container
      # ...
      readinessProbe:
        httpGet:
          path: /health
          port: 8080

Rekommendationer

  1. För mikrotjänster med HTTP-slutpunkt (REST, etc.) definiera alltid en beredskapssond, som kontrollerar om applikationen (podden) är redo att acceptera trafik.
  2. Se till att beredskapssonden täcker tillgängligheten för den faktiska webbserverporten:
    • använda portar för administrativa ändamål, kallade "admin" eller "hantering" (till exempel 9090), för readinessProbe, se till att slutpunkten endast returnerar OK om den primära HTTP-porten (som 8080) är redo att acceptera trafik*;

      *Jag känner till minst ett fall på Zalando där detta inte skett, d.v.s. readinessProbe Jag kollade "hantering"-porten, men själva servern började inte fungera på grund av problem med att ladda cachen.

    • att koppla en beredskapsprob till en separat port kan leda till att överbelastning på huvudporten inte kommer att återspeglas i hälsokontrollen (det vill säga trådpoolen på servern är full, men hälsokontrollen visar fortfarande att allt är OK ).
  3. Se till att beredskapssonden möjliggör initiering/migrering av databasen;
    • Det enklaste sättet att uppnå detta är att kontakta HTTP-servern först efter att initieringen är klar (till exempel migrera en databas från Flygväg och så vidare.); det vill säga, istället för att ändra status för hälsokontroll, starta helt enkelt inte webbservern förrän databasmigreringen är klar*.

      * Du kan också köra databasmigreringar från init-behållare utanför podden. Jag är fortfarande ett fan av fristående applikationer, det vill säga de där applikationsbehållaren vet hur man för databasen till önskat tillstånd utan extern samordning.

  4. användning httpGet för beredskapskontroller genom typiska hälsokontrollslutpunkter (t.ex. /health).
  5. Förstå standardkontrollparametrarna (interval: 10s, timeout: 1s, successThreshold: 1, failureThreshold: 3):
    • standardalternativen betyder att podden kommer att bli inte redo efter cirka 30 sekunder (3 misslyckade hälsokontroller).
  6. Använd en separat port för "admin" eller "hantering" om teknikstacken (t.ex. Java/Spring) tillåter det, för att separera hälso- och statistikhantering från vanlig trafik:
    • men glöm inte punkt 2.
  7. Vid behov kan beredskapssonden användas för att värma upp/ladda cachen och returnera en 503-statuskod tills behållaren värms upp:
    • Jag rekommenderar också att du läser den nya kontrollen startupProbe, dök upp i version 1.16 (vi skrev om det på ryska här - cirka. översätt.).

försiktighetsåtgärder

  1. Lita inte på externa beroenden (såsom datalager) när du kör beredskaps-/levenesstester - detta kan leda till kaskadfel:
    • Som ett exempel, låt oss ta en stateful REST-tjänst med 10 pods beroende på en Postgres-databas: när kontrollen beror på en fungerande anslutning till DB, kan alla 10 pods misslyckas om det finns en fördröjning på nätverks-/DB-sidan - vanligtvis allt slutar värre än det kunde;
    • Observera att Spring Data kontrollerar databasanslutningen som standard*;

      * Detta är standardbeteendet för Spring Data Redis (åtminstone var det sista gången jag kollade), vilket ledde till ett "katastrofalt" misslyckande: när Redis var otillgänglig under en kort tid, "kraschade" alla poddar.

    • "extern" i denna mening kan också betyda andra pods av samma applikation, det vill säga, idealiskt bör kontrollen inte bero på tillståndet för andra pods i samma kluster för att förhindra kaskadkrascher:
      • Resultaten kan variera för applikationer med distribuerat tillstånd (till exempel cachelagring i minnet i pods).
  2. Använd inte en livlighetssond för baljor (undantag är fall när de verkligen är nödvändiga och du är fullt medveten om detaljerna och konsekvenserna av deras användning):
    • En livlighetssond kan hjälpa till att återställa hängda behållare, men eftersom du har full kontroll över din applikation bör saker som hängda processer och dödlägen helst inte hända: det bästa alternativet är att avsiktligt krascha applikationen och föra tillbaka den till tidigare stationärt tillstånd;
    • en misslyckad liveness-sond kommer att få behållaren att starta om, vilket potentiellt förvärrar konsekvenserna av laddningsrelaterade fel: omstart av behållaren kommer att resultera i driftstopp (åtminstone under programmets start, säg 30 sekunder), vilket orsakar nya fel , öka belastningen på andra containrar och öka sannolikheten för att de misslyckas, etc.;
    • Liveness-kontroller kombinerat med ett externt beroende är den värsta möjliga kombinationen, som hotar kaskadfel: en liten fördröjning på databassidan kommer att leda till en omstart av alla dina behållare!
  3. Parametrar för kontroll av livlighet och beredskap måste vara annorlunda:
    • du kan använda en livlighetssond med samma hälsokontroll, men en högre svarströskel (failureThreshold), till exempel, tilldela statusen inte redo efter 3 försök och anse att liveness-sonden har misslyckats efter 10 försök;
  4. Använd inte exec-kontroller, eftersom de är förknippade med kända problem som leder till uppkomsten av zombieprocesser:

Sammanfattning

  • Använd beredskapssonder för att avgöra när en pod är redo att ta emot trafik.
  • Använd endast livhetssonder när de verkligen behövs.
  • Felaktig användning av beredskaps-/livenesssonder kan leda till minskad tillgänglighet och kaskadfel.

Liveness-sonder i Kubernetes kan vara farliga

Ytterligare material om ämnet

Uppdatering nr 1 från 2019-09-29

Om init-behållare för databasmigrering: Fotnot tillagd.

EJ påminde mig om det preliminära budgetförslaget: ett av problemen med kontroller av livlighet är bristen på samordning mellan baljor. Kubernetes har Pod Disruption Budgets (PDB) för att begränsa antalet samtidiga fel som en applikation kan uppleva, men kontrollerna tar inte hänsyn till det preliminära budgetförslaget. Helst skulle vi kunna säga till K8s att "Starta om en pod om testet misslyckas, men starta inte om dem alla för att undvika att göra saker värre."

Bryan uttryckte det perfekt: “Använd liveness probing när du vet exakt vad det bästa du kan göra är att avsluta applikationen"(igen, låt dig inte ryckas med).

Liveness-sonder i Kubernetes kan vara farliga

Uppdatering nr 2 från 2019-09-29

Angående att läsa dokumentationen före användning: Jag skapade motsvarande begäran (funktion begäran) för att lägga till dokumentation om livhetssonder.

PS från översättaren

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar