Det hÀr Àr en berÀttelse om hur vi anvÀnder containrar i produktion, sÀrskilt under Kubernetes. Artikeln handlar om att samla in mÀtvÀrden och loggar frÄn containrar, samt att bygga avbildningar.

Vi kommer frÄn fintech-företaget Exness, som utvecklar tjÀnster för onlinehandel och fintech-produkter för B2B och B2C. VÄr FoU har mÄnga olika team, och utvecklingsavdelningen har över 100 anstÀllda.
Vi Àr teamet som ansvarar för plattformen dÀr vÄra utvecklare kan samla in och köra kod. Mer specifikt ansvarar vi för att samla in, lagra och leverera mÀtvÀrden, loggar och hÀndelser frÄn applikationer. Vi driver för nÀrvarande cirka 50 XNUMX Docker-containrar i produktion, underhÄller vÄr XNUMX TB stora datalagring och tillhandahÄller arkitekturlösningar som Àr byggda kring vÄr infrastruktur: Kubernetes, Rancher och olika publika molnleverantörer.
VÄr motivation
Vad brinner? Ingen kan svara. Var Àr kÀllan? Det Àr svÄrt att förstÄ. NÀr fattade det eld? Det gÄr att ta reda pÄ det, men inte direkt.

Varför stÄr vissa containrar, medan andra har fallit? Vilken container var skyldig? Containrarna Àr trots allt identiska pÄ utsidan, men var och en har sin egen Neo pÄ insidan.

VÄra utvecklare Àr smarta killar. De skapar bra tjÀnster som ger företaget vinst. Men det blir problem nÀr containrar med applikationer gÄr i kras. En container förbrukar för mycket CPU, en annan - nÀtverket, den tredje - I/O-operationer, den fjÀrde Àr helt oklar vad den gör med sockets. Allt detta kraschar, och skeppet sjunker.
Agenter
För att förstÄ vad som försiggick inuti bestÀmde vi oss för att placera agenter direkt i containrarna.

Dessa agenter Àr de inneslutningsprogram som hÄller containrar i ett tillstÄnd som förhindrar att de bryter sönder varandra. Agenterna Àr standardiserade, vilket möjliggör en standardiserad metod för containrarunderhÄll.
I vÄrt fall bör agenter tillhandahÄlla loggar i ett standardformat, taggade och begrÀnsade. De bör ocksÄ förse oss med standardiserade mÀtvÀrden som Àr utökningsbara ur ett affÀrsapplikationsperspektiv.
ĐĐŸĐŽ Đ°ĐłĐ”ĐœŃĐ°ĐŒĐž ŃаĐșжД ĐżĐŸĐŽŃазŃĐŒĐ”ĐČаŃŃŃŃ ŃŃОлОŃŃ ĐŽĐ»Ń ŃĐșŃплŃаŃаŃОО Đž ĐŸĐ±ŃĐ»ŃжОĐČĐ°ĐœĐžŃ, ŃĐŒĐ”ŃŃОД ŃĐ°Đ±ĐŸŃаŃŃ ĐČ ŃĐ°Đ·ĐœŃŃ ŃĐžŃŃĐ”ĐŒĐ°Ń ĐŸŃĐșĐ”ŃŃŃĐžŃĐŸĐČĐ°ĐœĐžŃ, ĐżĐŸĐŽĐŽĐ”ŃжОĐČаŃŃОД ŃĐ°Đ·ĐœŃĐ” images (Debian, alpina, Centos och sĂ„ vidare).
Slutligen mÄste agenter stödja enkla CI/CD-filer som inkluderar Dockerfiles. Annars kommer fartyget att falla isÀr eftersom containrar börjar levereras pÄ "snedvÀndiga" rÀls.
Monteringsprocessen och mÄlbildens enhet
För att hĂ„lla allt standardiserat och hanterbart behöver man följa nĂ„gon standardiserad byggprocess. SĂ„ vi bestĂ€mde oss för att bygga container för container â det Ă€r rekursion.

HÀr representeras behÄllarna av heldragna konturer. Samtidigt bestÀmde vi oss för att placera fördelningar i dem, sÄ att "livet inte kÀnns som en dans pÄ rosor". Vi kommer att berÀtta nedan varför detta gjordes.
Resultatet Ă€r ett byggverktyg â en behĂ„llare för en specifik version som refererar till specifika versioner av distributioner och specifika versioner av skript.
Hur anvÀnder vi det? Vi har en Docker Hub, dÀr containern finns. Vi speglar den inuti vÄrt system för att bli av med externa beroenden. Resultatet Àr en container markerad med gult. Vi skapar en mall för att installera alla distributioner och skript vi behöver i containern. DÀrefter bygger vi en fÀrdig avbildning: utvecklare lÀgger in kod och nÄgra av sina speciella beroenden i den.
Vad Àr bra med den hÀr metoden?
- För det första, fullstĂ€ndig versionskontroll av byggverktyg â byggbehĂ„llare, versioner av skript och distributioner.
- För det andra har vi uppnÄtt standardisering: vi skapar mallar, mellanliggande och fÀrdiga bilder pÄ samma sÀtt.
- För det tredje ger containrar oss portabilitet. Idag anvÀnder vi Gitlab, och imorgon byter vi till TeamCity eller Jenkins och vi kan köra vÄra containrar pÄ samma sÀtt.
- För det fjÀrde, minimering av beroenden. Det Àr inte av en slump att vi placerar distributioner i en container, eftersom det gör att vi inte behöver ladda ner dem frÄn internet varje gÄng.
- För det femte har monteringshastigheten ökat - nÀrvaron av lokala kopior av bilder gör att du inte slösar tid pÄ nedladdning, 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 vilken container som helst med fullstÀndig versionshantering.
SÄ hÀr fungerar vÄr monteringsprocess

Bygget startas med ett kommando, processen körs i bilden (markerad i rött). Utvecklaren har en Docker-fil (markerad i gult), vi renderar den och ersĂ€tter variabler med vĂ€rden. Och lĂ€ngs vĂ€gen lĂ€gger vi till sidhuvuden och sidfot â dessa Ă€r vĂ„ra agenter.
Sidhuvudet lÀgger till distributioner frÄn motsvarande avbildningar. Och sidfoten installerar vÄra tjÀnster inuti, konfigurerar starten av arbetsbelastningen, loggning och andra agenter, ersÀtter startpunkten etc.

Vi funderade lÀnge pÄ om vi skulle installera en supervisor. Till slut bestÀmde vi oss för att vi behövde en. Vi valde S6. Supervisorn tillhandahÄller containerhantering: den lÄter dig ansluta till den om huvudprocessen kraschar och ger manuell kontroll över containern utan att Äterskapa den. Loggar och mÀtvÀrden Àr processer som körs inuti containern. De mÄste ocksÄ kontrolleras pÄ nÄgot sÀtt, och vi gör detta med hjÀlp av supervisorn. Slutligen tar S6 hand om hushÄllning, signalbehandling och andra uppgifter.
Eftersom vi anvÀnder olika orkestreringssystem mÄste containern, efter att den byggt och körts, förstÄ vilken miljö den befinner sig i och agera dÀrefter. Till exempel:
Detta gör att vi kan bygga en avbildning och köra den i olika orkestreringssystem, och den kommer att lanseras med hÀnsyn till orkestreringssystemets specifika egenskaper.

För samma container fÄr vi olika processtrÀd i Docker och Kubernetes:

Nyttolasten exekveras under S6-supervisorn. Notera insamlaren och hĂ€ndelserna â dessa Ă€r vĂ„ra agenter som ansvarar för loggar och mĂ€tvĂ€rden. Kubernetes har dem inte, men Docker har dem. Varför?
Om vi ââtittar pĂ„ "pod"-specifikationen (nedan kallad Kubernetes pod) ser vi att hĂ€ndelsebehĂ„llaren exekveras i en pod, som har en separat insamlarbehĂ„llare som utför funktionen att samla in mĂ€tvĂ€rden och loggar. Vi kan anvĂ€nda Kubernetes funktioner: starta containrar i en pod, i en enda process och/eller nĂ€tverksutrymme. Faktum Ă€r att vi kan implementera vĂ„ra agenter och utföra vissa funktioner. Och om samma container startas i Docker kommer den att fĂ„ samma funktioner vid utgĂ„ngen, det vill sĂ€ga den kommer att kunna leverera loggar och mĂ€tvĂ€rden, eftersom agenterna kommer att startas inuti.
MÀtvÀrden och loggar
Att leverera mÀtvÀrden och loggar Àr en komplex uppgift. Det finns flera aspekter involverade i att lösa den.
Infrastrukturen Àr byggd för att köra nyttolaster, inte för att leverera loggar i massor. Det betyder att det bör göras med minimala resurskrav för containrar. Vi vill hjÀlpa vÄra utvecklare: "Ta en Docker Hub-container, kör den, sÄ kan vi leverera loggar."
Den andra aspekten Àr att begrÀnsa loggvolymen. Om en loggvolymstopp intrÀffar i flera containrar (applikationen matar ut ett stackspÄr i en loop) ökar belastningen pÄ processorn, kommunikationskanalerna och loggbehandlingssystemet, och detta pÄverkar driften av vÀrden som helhet och andra containrar pÄ vÀrden, vilket ibland leder till en "krasch" av vÀrden.
Den tredje aspekten Àr att stödja sÄ mÄnga metoder för mÀtvÀrdensinsamling som möjligt direkt frÄn lÄdan. FrÄn att lÀsa filer och avfrÄga Prometheus-slutpunkten till att anvÀnda applikationsspecifika protokoll.
Och den sista aspekten Àr att det Àr nödvÀndigt att minimera resursförbrukningen.
Vi valde en öppen kÀllkodslösning pÄ Go som heter Telegraf. Det Àr en universell koppling som stöder mer Àn 140 typer av ingÄngskanaler (ingÄngsplugins) och 30 typer av utgÄngsplugins. Vi har förbÀttrat den och nu ska vi berÀtta hur vi anvÀnder den med Kubernetes som exempel.

LÄt oss sÀga att en utvecklare distribuerar en arbetsbelastning och Kubernetes fÄr en begÀran om att skapa en pod. Vid denna tidpunkt skapas en container som heter Collector automatiskt för varje pod (vi anvÀnder en mutationswebhook). Collector Àr vÄr agent. Vid start konfigurerar sig containern för att fungera med Prometheus och loggsamlingssystemet.
- För att göra detta anvÀnder den pod-annoteringarna, och beroende pÄ deras innehÄll skapar den, sÀg, en Prometheus-slutpunkt;
- Baserat pÄ Pod-specifikationen och behÄllarspecifika instÀllningar, bestÀmmer hur loggar ska levereras.
Vi samlar in loggar via Docker API: utvecklare behöver bara lÀgga dem i stdout eller stderr, sÄ sorterar Collector ut det. Loggar samlas in i bitar med viss fördröjning för att förhindra eventuell överbelastning av vÀrddatorn.
MÀtvÀrden samlas in av arbetsbelastningsinstanser (processer) i containrar. Allt taggas: namnrymd, pod, etc., och konverteras sedan till Prometheus-format - och blir tillgÀngligt för insamling (förutom loggar). Vi skickar Àven loggar, mÀtvÀrden och hÀndelser till Kafka och vidare:
- Loggar finns tillgÀngliga i Graylog (för visuell analys);
- Loggar, mÀtvÀrden och hÀndelser skickas till Clickhouse för lÄngtidslagring.
Allt fungerar exakt likadant i AWS, bara det att vi ersÀtter Graylog med Kafka och Cloudwatch. Vi skickar loggar dit, och allt blir vÀldigt bekvÀmt: det Àr omedelbart tydligt vilket kluster och container de tillhör. Detsamma gÀller för Google Stackdriver. Det vill sÀga, vÄrt schema fungerar bÄde on-premise med Kafka och i molnet.
Om vi ââinte har Kubernetes med poddar Ă€r schemat lite mer komplicerat, men fungerar enligt samma principer.

Samma processer exekveras inuti containern, de orkestreras med S6. Alla samma processer startas inuti samma container.
Som ett resultat,
Vi har skapat en komplett lösning för att bygga och lansera avbildningar i produktion, med alternativ för att samla in och leverera loggar och mÀtvÀrden:
- Vi utvecklade en standardiserad metod för att bygga bilder, och baserat pÄ den utvecklade vi CI-mallar;
- Datainsamlingsagenter Àr vÄra Telegraf-tillÀgg. Vi har testat dem vÀl i produktion;
- Vi anvÀnder mutationswebhook för att injicera behÄllare med agenter i poddar;
- Integrerad i Kubernetes/Rancher-ekosystemet;
- Vi kan exekvera samma containrar i olika orkestreringssystem och fÄ det resultat vi förvÀntar oss;
- Skapade en helt dynamisk konfiguration för containerhantering.
Medförfattare: Ilja Prudnikov
KĂ€lla: will.com
