Den hÀr historien handlar om hur vi anvÀnder containrar i produktionsmiljö, sÀrskilt under Kubernetes. Artikeln handlar om insamling av metrik och loggar frÄn containrar, samt byggande av bilder.

Vi kommer frÄn fintech-företaget Exness, som utvecklar tjÀnster för onlinehandel och fintech-produkter för B2B och B2C. I vÄr R&D finns det mÄnga olika team, och avdelningen för utveckling har över 100 anstÀllda.
Vi representerar teamet som ansvarar för plattformen för insamling och körning av kod av vĂ„ra utvecklare. Specifikt ansvarar vi för insamling, lagring och tillhandahĂ„llande av metrik, loggar och hĂ€ndelser frĂ„n applikationer. För nĂ€rvarande hanterar vi cirka tre tusen Docker-containrar i produktionsmiljö, upprĂ€tthĂ„ller vĂ„rt big data-lager pĂ„ 50 TB och tillhandahĂ„ller arkitekturlösningar som byggs runt vĂ„r infrastruktur: Kubernetes, Rancher och olika offentliga molnleverantörer.Â
VÄr motivation
Vad brinner? Ingen kan svara. Var Ă€r fokus? SvĂ„rt att förstĂ„. NĂ€r började det brinna? Det gĂ„r att ta reda pĂ„, men inte omedelbart.Â

Varför stÄr vissa containrar stilla medan andra har fallit? Vilken container orsakade det? UtifrÄn verkar containrarna likadana, men inuti har varje sin egen Neo.

VĂ„ra utvecklare Ă€r kompetenta personer. De skapar bra tjĂ€nster som ger företaget vinst. Men det uppstĂ„r ocksĂ„ problem nĂ€r containrarna med applikationerna sprider sig. En container förbrukar för mycket CPU, en annan nĂ€tverk, en tredje I/O-operationer, och en fjĂ€rde gör överhuvudtaget oklara saker med sockets. Allt detta faller och skeppet sjunker.Â
Agenter
För att förstÄ vad som hÀnder inuti beslutade vi att installera agenter direkt i containrarna.

Dessa agenter Ă€r kontrollprogram som hĂ„ller containrarna i ett sĂ„dant tillstĂ„nd sĂ„ att de inte förstör varandra. Agenterna Ă€r standardiserade, vilket gör att vi kan standardisera tillvĂ€gagĂ„ngssĂ€ttet för underhĂ„ll av containrar.Â
I vÄrt fall mÄste agenterna tillhandahÄlla loggar i ett standardformat, taggade och med throttling. Dessutom mÄste de ge oss standardiserade metrik som Àr utbyggbara ur affÀrsapplikationernas perspektiv.
Under agenter avser vi ocksÄ verktyg för drift och underhÄll som kan fungera i olika orkestreringssystem, och stöder olika images (Debian, Alpine, Centos osv.).
Ăntligen mĂ„ste agenter stödja en enkel CI/CD som inkluderar Docker-filer. Annars kommer skeppet att gĂ„ sönder eftersom containrarna börjar levereras pĂ„ "sneda" spĂ„r.
Byggprocess och uppbyggnad av mÄlimagen
För att allt ska vara standardiserat och hanterbart mÄste vi följa en standardiserad byggprocess. DÀrför har vi beslutat att bygga containrar med hjÀlp av containrar - sÄdan Àr vÄr rekursion.

HÀr representeras containrarna med solida konturer. Vi bestÀmde oss för att lÀgga in distributionerna i dem, sÄ att "livet inte kÀndes som en dans pÄ rosor". Varför detta gjordes, kommer vi att berÀtta nedan.
Â
Resultatet blev ett verktyg för byggande - en container av viss version som refererar till specifika versioner av distributionerna och specifika versioner av skripten.
Hur anvĂ€nder vi det? Vi har en Docker Hub dĂ€r containern finns. Vi speglar den in i vĂ„rt eget system för att bli av med externa beroenden. Vi fick en container som markerats med gult. Vi skapar en mall för att installera alla nödvĂ€ndiga distributioner och skript i containern. DĂ€refter bygger vi en fullstĂ€ndig bild som Ă€r redo för drift: utvecklarna lĂ€gger in sin kod och vissa egna specifika beroenden.Â
Vad Ă€r fördelarna med ett sĂ„dant tillvĂ€gagĂ„ngssĂ€tt?Â
- För det första, komplett versionskontroll av byggverktyg - byggcontainer, versioner av skript och distributioner.Â
- För det andra, har vi uppnĂ„tt standardisering: vi skapar mallar, mellanliggande och driftsklara bilder pĂ„ samma sĂ€tt.Â
- För det tredje ger containrarna oss portabilitet. Idag anvĂ€nder vi Gitlab, och imorgon byter vi till TeamCity eller Jenkins och kan pĂ„ samma sĂ€tt köra vĂ„ra containrar.Â
- För det fjĂ€rde, minimering av beroenden. Vi har inte av en slump lagt distributioner i containern, eftersom detta gör att vi inte behöver ladda ner dem varje gĂ„ng frĂ„n Internet.Â
- För det femte, har hastigheten pĂ„ byggprocessen ökat - tillgĂ„ngen pĂ„ lokala kopior av bilder gör att vi inte behöver lĂ€gga tid pĂ„ nedladdningar, eftersom det finns en lokal bild.Â
Med andra ord har vi uppnĂ„tt en kontrollerad och flexibel byggprocess. Vi anvĂ€nder samma verktyg för att bygga alla containrar med fullstĂ€ndig versionering.Â
Hur fungerar vÄr byggprocess?

Byggandet startar med ett kommando och processen körs i en bild (markerad med röd). Utvecklaren har en Docker-fil (markerad med gul), som vi renderar genom att byta ut variabler mot vĂ€rden. Samtidigt lĂ€gger vi till header och footer - detta Ă€r vĂ„ra agenter.Â
Headern lĂ€gger till distributioner frĂ„n motsvarande bilder. Och footern installerar vĂ„ra tjĂ€nster, konfigurerar belastningsstart, loggning och andra agenter, byter ut entrypoint osv.Â

Vi övervÀgde lÀnge om vi skulle anvÀnda en supervisor. Till slut bestÀmde vi att vi behövde en. Vi valde S6. Supervisorn möjliggör hantering av containern: den gör det möjligt att ansluta till den om huvudprocessen kraschar och ger manuell kontroll över containern utan att behöva Äterskapa den. Loggar och mÀtvÀrden Àr processer som körs inuti containern. Vi mÄste ocksÄ kontrollera dem, och det gör vi med hjÀlp av supervisorn. Slutligen tar S6 hand om housekeeping, signalbearbetning och andra uppgifter.
Eftersom vi anvÀnder olika orkestreringssystem, efter byggandet och startandet av containern, mÄste den förstÄ i vilken miljö den befinner sig och agera utifrÄn situationen. Till exempel:
Detta gör att vi kan bygga en bild och köra den i olika orkestreringssystem, dÀr den kommer att startas med hÀnsyn till specifika krav frÄn detta orkestreringssystem.
 
För samma container fÄr vi olika processtrÀd i Docker och Kubernetes:

Nyttolasten körs under supervisorn S6. Observera collector och events - detta Ă€r vĂ„ra agenter som ansvarar för loggar och mĂ€tvĂ€rden. I Kubernetes finns de inte, men i Docker finns de. Varför?Â
Om vi ser pĂ„ specifikationen för âpodâ (hĂ€refter Kubernetes pod) kommer vi att se att containern events körs i en pod dĂ€r det finns en separat container collector som utför funktionen av att samla mĂ€tvĂ€rden och loggar. Vi kan anvĂ€nda Kubernetes-funktioner: köra containrar i samma pod, i samma process- och/eller nĂ€tverksutrymmen. Faktiskt införa vĂ„ra agenter och utföra vissa funktioner. Och om samma container startas i Docker fĂ„r den alla samma möjligheter, det vill sĂ€ga kan leverera loggar och mĂ€tvĂ€rden, eftersom agenterna kommer att köras inuti.Â
MÀtvÀrden och loggar
Leverans av mÀtvÀrden och loggar Àr en komplex uppgift. Det finns flera aspekter kopplade till dess lösning.
Infrastrukturen skapas för att hantera nyttolast, inte för massdistribution av loggar. Det vill sĂ€ga att denna process bör utföras med minimala resurskrav för containrarna. Vi strĂ€var efter att hjĂ€lpa vĂ„ra utvecklare: "Ta en Docker Hub-container, starta den, sĂ„ kan vi leverera loggar."Â
Den andra aspekten Ă€r begrĂ€nsningen av loggvolymen. Om flera containrar genererar en ökning av loggvolymen (t.ex. en applikation som i en loop skriver stacktrace), ökar belastningen pĂ„ CPU, kommunikationskanaler och logghanteringssystemet, vilket pĂ„verkar vĂ€rdenheten och andra containrar pĂ„ vĂ€rdenheten, och ibland leder detta till att vĂ€rdenheten "fallerar".Â
Den tredje aspekten Àr att stödja sÄ mÄnga metoder för insamling av mÀtvÀrden som möjligt direkt frÄn starten. FrÄn att lÀsa filer och frÄga Prometheus-endpoint till att anvÀnda specifika applikationsprotokoll.
Och den sista aspekten Àr att minimera resursförbrukningen.
Vi har valt en open-source-lösning i Go kallad Telegraf. Det Ă€r en universell koppling som stödjer över 140 typer av ingĂ„ngskanaler (input plugins) och 30 typer av utgĂ„ngskanaler (output plugins). Vi har vidareutvecklat den och nu ska vi berĂ€tta hur den anvĂ€nds i vĂ„rt fall med Kubernetes.Â

Anta att en utvecklare deployar en belastning, och Kubernetes fÄr en begÀran om att skapa en pod. Vid detta ögonblick skapas automatiskt en container med namnet Collector för varje pod (vi anvÀnder mutation webhook). Collector Àr vÄr agent. Vid start konfigurerar denna container sig sjÀlv för att arbeta med Prometheus och logginsamlingssystemet.
- För detta anvĂ€nder den pod-annoteringar, och beroende pĂ„ innehĂ„llet skapar den till exempel en slutpunkt för Prometheus.Â
- Baserat pÄ pod-specifikationen och specifika konfigurationer för containrar beslutar den hur loggar ska levereras.
Loggar samlas in via Docker API: utvecklarna behöver bara skriva dem till stdout eller stderr, och sedan tar Collector hand om resten. Loggarna samlas in i chunkar med viss fördröjning för att förhindra eventuell överbelastning av vĂ€rdenheten.Â
MÀtvÀrden samlas in per instans av arbetsbelastningar (rocesser) i containrar. Allt mÀrks med taggar: namespace, pod och sÄ vidare, och konverteras sedan till Prometheus-format - och blir tillgÀngligt för insamling (förutom loggar). Dessutom skickar vi loggar, mÀtvÀrden och hÀndelser till Kafka och vidare:
- Loggar Àr tillgÀngliga i Graylog (för visuell analys);
- Loggar, mÀtningar och hÀndelser skickas till Clickhouse för lÄngsiktig lagring.
PĂ„ samma sĂ€tt fungerar allt i AWS, endast att vi byter ut Graylog med Kafka mot Cloudwatch. Vi skickar loggar dit, och allt blir mycket bekvĂ€mt: det Ă€r direkt klart vilket kluster och vilken container de hör till. Detsamma gĂ€ller för Google Stackdriver. SĂ„ vĂ„r lösning fungerar bĂ„de on-premise med Kafka och i molnet.Â
Om vi inte har Kubernetes med pods, blir systemet nÄgot mer komplicerat, men det fungerar enligt samma principer.

Inuti containern körs samma processer, de orkestreras med hjÀlp av S6. Samma processer har startats inuti en och samma container.
I slutÀndan
Vi har skapat en helhetslösning för att bygga och köra bilder i produktion, med alternativ för insamling och leverans av loggar och mÀtningar:
- Vi har utvecklat en standardiserad metod för att bygga bilder och utifrÄn den har vi utvecklat CI-mallar;
- Agenter för datainsamling Àr vÄra Telegraf-tillÀgg. Vi har testat dem ordentligt i produktion;
- Vi anvĂ€nder mutation webhook för att integrera containrar med agenter i pods;Â
- Vi har integrerat oss i Kubernetes/Rancher-ekosystemet;
- Vi kan köra identiska containrar i olika orkestreringssystem och fÄ det resultat vi förvÀntar oss;
- Vi har skapat en helt dynamisk konfiguration för hantering av containrar.Â
Medförfattare: Ilja Prudnikov
KĂ€lla: habr.com
