Fem misstag vid distributionen av den första applikationen pÄ Kubernetes

Fem misstag vid distributionen av den första applikationen pÄ KubernetesMisslyckande av Aris-Dreamer

MĂ„nga tror att det bara Ă€r att flytta applikationen till Kubernetes (antingen med hjĂ€lp av Helm eller manuellt) – sĂ„ blir allt bra. Men det Ă€r inte sĂ„ enkelt.

Team Mail.ru Cloud Solutions översatte artikel av DevOps-ingenjören Julian Gindi. Han beskriver vilka fallgropar hans företag stötte pÄ under migreringen, sÄ att ni inte gör samma misstag.

Steg ett: konfigurera pod-förfrÄgningar och begrÀnsningar

Vi börjar med att konfigurera en ren miljö dÀr vÄra pods ska fungera. Kubernetes hanterar planering av pods och felhantering utmÀrkt. Men det visade sig att schemalÀggaren ibland inte kan placera en pod om den har svÄrt att bedöma vilka resurser som krÀvs för att den ska fungera framgÄngsrikt. HÀr kommer förfrÄgningar om resurser och begrÀnsningar in. Det förekommer mÄnga diskussioner om den bÀsta metoden för att konfigurera dessa. Ibland kÀnns det som att det verkligen Àr mer en konst Àn en vetenskap. HÀr Àr vÄr metod.

Pod-förfrÄgningar (pod requests) Àr den grundlÀggande mÀngd som anvÀnds av schemalÀggaren för optimal placering av en pod.

Av dokumentationen för Kubernetes: vid filtreringssteget bestÀms en uppsÀttning noder dÀr en pod kan schemalÀggas. Till exempel kontrollerar filtret PodFitsResources om det finns tillrÀckligt med resurser pÄ noden för att uppfylla podens specifika resursförfrÄgningar.

Vi anvÀnder applikationsförfrÄgningar sÄ att vi kan bedöma hur mycket resurser som faktiskt behövs för applikationen för att fungera normalt. DÄ kan schemalÀggaren realistiskt placera noder. FrÄn början ville vi stÀlla in förfrÄgningar med marginal, för att sÀkerstÀlla att det fanns tillrÀckligt med resurser för varje pod, men vi mÀrkte att schemalÀggningstiden ökade avsevÀrt, och vissa pods blev aldrig helt schemalagda, som om inga resursförfrÄgningar hade kommit in för dem.

I det hÀr fallet "pressade" schemalÀggaren ofta ut pods och kunde inte schemalÀgga dem igen eftersom kontrollplanet inte visste hur mycket resurser applikationen skulle behöva, vilket Àr en nyckelkomponent i schemalÀggningsalgoritmen.

Pod-begrÀnsningar (pod limits) Àr ett mer tydligt tak för en pod. Det representerar den maximala mÀngd resurser som klustret kommer att avsÀtta för containern.

Återigen, frĂ„n den officiella dokumentationen: om minnesgrĂ€nsen för containern Ă€r satt till 4 GiB, kommer kubelet (och container-runtime) att tvinga den. Runtime tillĂ„ter inte containern att anvĂ€nda mer Ă€n den angivna resursgrĂ€nsen. Till exempel, nĂ€r en process i containern försöker anvĂ€nda mer Ă€n den tillĂ„tna mĂ€ngden minne, avslutar systemets kĂ€rna denna process med ett felmeddelande «out of memory» (OOM).

Containern kan alltid anvÀnda mer resurser Àn vad som anges i resursförfrÄgan, men fÄr aldrig anvÀnda mer Àn vad som anges i grÀnsen. Det Àr en svÄr avvÀgning att stÀlla in rÀtt vÀrde, men det Àr mycket viktigt.

Idealiskt sett vill vi att resursbehovet för podden ska förĂ€ndras under livscykeln för processen, utan att pĂ„verka andra processer i systemet — det Ă€r mĂ„let med att sĂ€tta grĂ€nser.

TyvÀrr kan jag inte ge specifika riktlinjer för vilka vÀrden som ska stÀllas in, men vi följer sjÀlva dessa regler:

  1. Med ett belastningstestverktyg modellerar vi en grundlÀggande trafiknivÄ och observerar resursanvÀndningen för podden (minne och CPU).
  2. Vi sÀtter poddens förfrÄgningar pÄ ett godtyckligt lÄgt vÀrde (med resursgrÀnsen ungefÀr 5 gÄnger högre Àn förfrÄgningsvÀrdet) och observerar. NÀr förfrÄgningarna Àr för lÄga kan processen inte starta, vilket ofta orsakar mystiska körningsfel i Go.

Jag vill notera att högre resursgrÀnser komplicerar planeringen, eftersom podden behöver en mÄlnod med tillrÀckligt med tillgÀngliga resurser.

FörestÀll dig en situation dÀr du har en lÀttvikts webbserver med en mycket hög resursgrÀns, till exempel 4 GB minne. Troligtvis kommer denna process att behöva skalas horisontellt, och varje ny modul mÄste planeras pÄ en nod med minst 4 GB tillgÀngligt minne. Om en sÄdan nod inte finns, mÄste klustret introducera en ny nod för att hantera denna pod, vilket kan ta en stund. Det Àr viktigt att uppnÄ en minimal skillnad mellan resursförfrÄgningar och grÀnser för att sÀkerstÀlla snabb och smidig skalning.

Steg tvÄ: konfigurera Liveness och Readiness tester

Det hÀr Àr ett annat subtilt Àmne som ofta diskuteras inom Kubernetes-gemenskapen. Det Àr viktigt att ha en god förstÄelse för livstest (Liveness) och beredskapstest (Readiness), eftersom de erbjuder en mekanism för stabil drift av programvaran och minimerar stillestÄndstiden. Men de kan allvarligt pÄverka prestandan för din applikation om de inte Àr korrekt konfigurerade. Nedan följer en sammanfattning av vad bÄda testerna innebÀr.

Liveness visar om containern fungerar. Om det misslyckas dödar kubelet containern och en Ă„terstartspolicy aktiveras. Om containern inte har en Liveness-check, anses det vara framgĂ„ng som standard—sĂ„ stĂ„r det i dokumentationen för Kubernetes.

Liveness-tester bör vara billiga, det vill sÀga de ska inte konsumera mycket resurser, eftersom de körs ofta och ska informera Kubernetes om att applikationen Àr igÄng.

Om du stÀller in parametern att köra varje sekund, kommer det att lÀgga till 1 begÀran per sekund, sÄ tÀnk pÄ att ytterligare resurser behövs för att hantera denna trafik.

PÄ vÄrt företag testar Liveness-tester kÀrnkomponenterna i applikationen, Àven om data (som frÄn en fjÀrrdatabas eller cache) inte Àr helt tillgÀngliga.

Vi har konfigurerat en "livskraft"-endpoint i applikationerna som helt enkelt returnerar statuskod 200. Detta Àr en indikation pÄ att processen Àr igÄng och kan hantera begÀrningar (men inte Ànnu trafik).

Test Readiness indikerar om containern Àr redo att hantera begÀrningar. Om beredskapstesten misslyckas, tar kontrolleraren bort poddens IP-adress frÄn alla tjÀnsters endpoints som motsvarar podden. Detta stÄr ocksÄ i Kubernetes-dokumentationen.

Readiness-tester konsumerar mer resurser, eftersom de mÄste nÄ backend pÄ ett sÀtt som visar att applikationen Àr redo att ta emot begÀrningar.

Det pÄgÄr mÄnga diskussioner i samhÀllet om huruvida man ska direkt kontakta databasen. Med hÀnsyn till overheadkostnader (kontroller görs ofta, men de kan regleras), har vi bestÀmt att för vissa applikationer rÀknas beredskapsresponsen endast efter att det har verifierats att databasen returnerar poster. VÀl genomtÀnkta beredskapskontroller har sÀkerstÀllt en högre tillgÀnglighet och eliminerat driftstopp under distributionen.

Om du beslutar dig för att göra en databasfrÄga för att kontrollera applikationens beredskap, se till att den Àr sÄ kostnadseffektiv som möjligt. LÄt oss ta följande frÄga:

SELECT small_item FROM table LIMIT 1

HÀr Àr ett exempel pÄ hur vi konfigurerar dessa tvÄ vÀrden i Kubernetes:

livenessProbe: 
 httpGet:   
   path: /api/liveness    
   port: http 
readinessProbe:  
 httpGet:    
   path: /api/readiness    
   port: http  periodSeconds: 2

Du kan lÀgga till vissa ytterligare konfigurationsparametrar:

  • initialDelaySeconds — hur mĂ„nga sekunder som gĂ„r frĂ„n att containern startar tills beredskapskontroller börjar.
  • periodSeconds — vĂ€ntetiden mellan körningar av kontroller.
  • timeoutSeconds — antalet sekunder efter vilket en pod anses vara i ett felaktigt tillstĂ„nd. Vanlig tidsgrĂ€ns.
  • failureThreshold — antal felade kontroller innan en signal om omstart skickas till podden.
  • successThreshold — antal lyckade kontroller innan podden övergĂ„r till beredskapslĂ€ge (efter ett fel, nĂ€r podden startas eller Ă„terstĂ€lls).

Steg tre: konfigurera standard nÀtverkspolicys för podden

I Kubernetes Àr nÀtverkstopologin "platt", vilket innebÀr att alla poddar per standard interagerar direkt med varandra. I vissa fall Àr detta oönskat.

Ett potentiellt sÀkerhetsproblem Àr att en angripare kan anvÀnda en enda sÄrbar applikation för att skicka trafik till alla poddar i nÀtverket. Som i mÄnga sÀkerhetsfrÄgor gÀller hÀr principen om minimiÄtkomst. Idealiskt sett bör nÀtverkspolicys tydligt ange vilka anslutningar mellan poddar som Àr tillÄtna och vilka som inte Àr det.

Till exempel nedan Àr en enkel policy som förbjuder all inkommande trafik för ett specifikt namnrum:

---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:  
 name: default-deny-ingress
spec:  
 podSelector: {}  
 policyTypes:  
   - Ingress

Visualisering av denna konfiguration:

Fem misstag vid distributionen av den första applikationen pÄ Kubernetes
(https://miro.medium.com/max/875/1*-eiVw43azgzYzyN1th7cZg.gif)
Mer i detalj hÀr.

Steg fyra: Anpassat beteende med hjÀlp av hooks och init-containrar

En av vÄra huvuduppgifter var att sÀkerstÀlla utplaceringar i Kubernetes utan driftstopp för utvecklarna. Detta Àr svÄrt pÄ grund av att det finns mÄnga sÀtt för applikationer att avsluta och frigöra sina resurser.

Speciella svÄrigheter uppstod med Nginx. Vi mÀrkte att aktiva kopplingar bröts under den sekventiella utplaceringen av dessa pods innan de kunde avslutas framgÄngsrikt.

Efter omfattande undersökningar pÄ internet visade det sig att Kubernetes inte vÀntar pÄ att Nginx-anslutningarna ska ta slut innan den stÀnger av podden. Med hjÀlp av pre-stop hook införde vi denna funktionalitet och eliminerade helt driftstoppet:

lifecycle: 
 preStop:
   exec:
     command: ["/usr/local/bin/nginx-killer.sh"]

Och hÀr Àr nginx-killer.sh:

#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
   echo "Waiting while shutting down nginx..."
   sleep 10
done

En annan oerhört anvÀndbar paradigm Àr att anvÀnda init-containrar för att hantera starten av specifika applikationer. Detta Àr sÀrskilt anvÀndbart om du har en resurskrÀvande databas migreringsprocess som bör köras innan applikationen startar. För denna process kan du ocksÄ ange en högre resursgrÀns utan att sÀtta en sÄdan grÀns för huvudapplikationen.

Ett annat vanligt mönster Àr att komma Ät hemligheter i init-containern, som tillhandahÄller dessa autentiseringsuppgifter till huvudmodulen, vilket förhindrar obehörig Ätkomst till hemligheterna frÄn sjÀlva huvudmodulen i applikationen.

Som vanligt, ett citat frÄn dokumentationen: Init-containrar kör sÀkert anvÀndarkod eller verktyg som annars skulle sÀnka sÀkerheten i applikationens containerbild. Genom att lagra onödiga verktyg separat begrÀnsar du angreppsyta för applikationens containerbild.

Steg fem: KÀrninstÀllningar

Avslutningsvis ska vi tala om en mer avancerad teknik.

Kubernetes Àr en utomordentligt flexibel plattform som gör det möjligt att köra arbetsbelastningar pÄ det sÀtt du anser lÀmpligt. Vi har en rad högpresterande applikationer som krÀver extremt mycket resurser. Efter omfattande belastningstestning upptÀckte vi att en av applikationerna har svÄrt att hantera den förvÀntade trafikbelastningen om standardinstÀllningarna för Kubernetes Àr aktiva.

Kubernetes gör det dock möjligt att köra en privilegierad container som Àndrar kÀrnparametrar endast för en specifik pod. HÀr Àr vad vi anvÀnde för att Àndra det maximala antalet öppna anslutningar:

initContainers:
  - name: sysctl
     image: alpine:3.10
     securityContext:
         privileged: true
      command: ['sh', '-c', "sysctl -w net.core.somaxconn=32768"]

Detta Àr en mer avancerad teknik som ofta inte behövs. Men om din applikation knappt klarar av hög belastning kan du försöka justera nÄgra av dessa parametrar. Mer information om denna process och justering av olika vÀrden finns alltid i den officiella dokumentationen.

Avslutningsvis

Även om Kubernetes kan verka som en fĂ€rdig lösning "ur lĂ„dan", krĂ€vs det flera viktiga steg för att sĂ€kerstĂ€lla att applikationerna fungerar utan avbrott.

Under hela migrationen till Kubernetes Àr det viktigt att följa "cykeln för belastningstestning": du startar applikationen, testar den under belastning, observerar metrik och beteende vid skalning, justerar konfigurationen baserat pÄ dessa data och upprepar sedan cykeln igen.

Gör en realistisk bedömning av den förvÀntade trafiken och försök att överskrida den för att se vilka komponenter som gÄr sönder först. Med en sÄdan iterativ metod kan det rÀcka med nÄgra av de nÀmnda rekommendationerna för att uppnÄ framgÄng. Alternativt kan mer detaljerad justering krÀvas.

StÀll alltid dig sjÀlv sÄdana frÄgor:

  1. Hur mycket resurser förbrukar applikationerna och hur kommer det hÀr beloppet att förÀndras?
  2. Vad Àr de verkliga kraven för skalning? Hur mycket trafik kommer applikationen att hantera i genomsnitt? Och hur Àr det med den maximala trafiken?
  3. Hur ofta behöver tjÀnsten horisontell skalning? Hur snabbt behöver nya pods sÀttas i drift för att ta emot trafik?
  4. Hur korrekt stÀngs pods av? Behövs detta överhuvudtaget? GÄr det att Ästadkomma distribution utan nedtid?
  5. Hur kan man minimera sÀkerhetsrisker och begrÀnsa skador frÄn eventuellt komprometterade pods? Har nÄgra tjÀnster rÀttigheter eller Ätkomst som de inte behöver?

Kubernetes erbjuder en fantastisk plattform som möjliggör de bĂ€sta metoderna för att distribuera tusentals tjĂ€nster i en kluster. ÄndĂ„ Ă€r alla applikationer olika. Ibland krĂ€ver implementering en aning mer arbete.

Lyckligtvis erbjuder Kubernetes de nödvÀndiga instÀllningarna för att uppnÄ alla tekniska mÄl. Genom att anvÀnda en kombination av resursförfrÄgningar och begrÀnsningar, Liveness- och Readiness-prober, init-containrar, nÀtverkspolicyer och skrÀddarsydd kÀrninstÀllning kan du uppnÄ hög prestanda tillsammans med driftsÀkerhet och snabb skalbarhet.

Vad mer att lÀsa:

  1. BÀsta praxis och rekommendationer för att köra containrar och Kubernetes i produktionsmiljöer.
  2. 90+ anvÀndbara verktyg för Kubernetes: distribution, hantering, övervakning, sÀkerhet och mer.
  3. VÄr kanal Om Kubernetes pÄ Telegram.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster