Imagini gata de producție pentru k8s

Această poveste este despre modul în care folosim containerele într-un mediu de producție, în special Kubernetes. Articolul este dedicat colectării valorilor și jurnalelor din containere, precum și construirii de imagini.

Imagini gata de producție pentru k8s

Suntem de la compania fintech Exness, care dezvoltă servicii de tranzacționare online și produse fintech pentru B2B și B2C. Cercetarea noastră și dezvoltarea are multe echipe diferite, departamentul de dezvoltare are peste 100 de angajați.

Reprezentăm echipa care este responsabilă de platformă pentru ca dezvoltatorii noștri să colecteze și să ruleze cod. În special, suntem responsabili pentru colectarea, stocarea și raportarea valorilor, jurnalelor și evenimentelor din aplicații. În prezent, operam aproximativ trei mii de containere Docker într-un mediu de producție, ne menținem stocarea de date mari de 50 TB și oferim soluții arhitecturale care sunt construite în jurul infrastructurii noastre: Kubernetes, Rancher și diverși furnizori de cloud public. 

Motivația noastră

Ce arde? Nimeni nu poate răspunde. Unde este vatra? E greu de înțeles. Când a luat foc? Puteți afla, dar nu imediat. 

Imagini gata de producție pentru k8s

De ce stau unele containere în timp ce altele au căzut? Ce container a fost de vină? La urma urmei, exteriorul containerelor este același, dar în interior fiecare are propriul său Neo.

Imagini gata de producție pentru k8s

Dezvoltatorii noștri sunt băieți competenți. Ei fac servicii bune care aduc profit companiei. Dar există eșecuri când containerele cu aplicații se rătăcesc. Un container consumă prea mult CPU, altul consumă rețeaua, un al treilea consumă operațiuni I/O, iar al patrulea este complet neclar ce face cu socket-urile. Totul cade și nava se scufundă. 

Agenți

Pentru a înțelege ce se întâmplă în interior, am decis să plasăm agenți direct în containere.

Imagini gata de producție pentru k8s

Acești agenți sunt programe de reținere care țin containerele într-o astfel de stare încât să nu se rupă unul pe celălalt. Agenții sunt standardizați, iar acest lucru permite o abordare standardizată a deservirii containerelor. 

În cazul nostru, agenții trebuie să furnizeze jurnalele într-un format standard, etichetate și accelerate. De asemenea, ar trebui să ne ofere valori standardizate care sunt extensibile din perspectiva aplicației de afaceri.

Agenții înseamnă, de asemenea, utilitare pentru operare și întreținere care pot funcționa în diferite sisteme de orchestrare care acceptă diferite imagini (Debian, Alpine, Centos etc.).

În cele din urmă, agenții trebuie să accepte CI/CD simplu care include fișiere Docker. În caz contrar, nava se va prăbuși, deoarece containerele vor începe să fie livrate de-a lungul șinelor „strâmbe”.

Procesul de construcție și dispozitivul de imagine țintă

Pentru a menține totul standardizat și gestionabil, trebuie urmat un fel de proces standard de construire. Prin urmare, am decis să colectăm containere cu containere - aceasta este recursivitate.

Imagini gata de producție pentru k8s

Aici containerele sunt reprezentate prin contururi solide. În același timp, au decis să pună în ele truse de distribuție, astfel încât „viața să nu pară zmeură”. De ce s-a făcut acest lucru, vom explica mai jos.
 
Rezultatul este un instrument de compilare — un container specific versiunii care face referire la versiuni specifice de distribuție și versiuni specifice de script.

Cum îl folosim? Avem un Docker Hub care conține un container. O oglindim în interiorul sistemului nostru pentru a scăpa de dependențele externe. Rezultatul este un recipient marcat cu galben. Creăm un șablon pentru a instala toate distribuțiile și scripturile de care avem nevoie în container. După aceea, asamblam o imagine gata de utilizare: dezvoltatorii pun cod și unele dintre propriile dependențe speciale în ea. 

Ce este bun la această abordare? 

  • În primul rând, controlul complet al versiunilor instrumentelor de compilare - versiuni de container, script și distribuție de compilare. 
  • În al doilea rând, am realizat standardizarea: creăm șabloane, imagine intermediară și gata de utilizare în același mod. 
  • În al treilea rând, containerele ne oferă portabilitate. Astăzi folosim Gitlab, iar mâine vom trece la TeamCity sau Jenkins și ne vom putea rula containerele în același mod. 
  • În al patrulea rând, minimizarea dependențelor. Nu întâmplător am pus truse de distribuție în container, pentru că acest lucru ne permite să evităm de fiecare dată să le descarcăm de pe Internet. 
  • În al cincilea rând, viteza de construire a crescut - prezența copiilor locale ale imaginilor vă permite să evitați pierderea timpului la descărcare, deoarece există o imagine locală. 

Cu alte cuvinte, am realizat un proces de asamblare controlat și flexibil. Folosim aceleași instrumente pentru a construi orice containere complet versiune. 

Cum funcționează procedura noastră de construcție

Imagini gata de producție pentru k8s

Ansamblul este lansat cu o singură comandă, procesul se execută în imagine (evidențiat cu roșu). Dezvoltatorul are un fișier Docker (evidențiat cu galben), îl redăm, înlocuind variabilele cu valori. Și pe parcurs adăugăm anteturi și subsoluri - aceștia sunt agenții noștri. 

Antetul adaugă distribuții din imaginile corespunzătoare. Și footer instalează serviciile noastre în interior, configurează lansarea volumului de lucru, logare și alți agenți, înlocuiește punctul de intrare etc. 

Imagini gata de producție pentru k8s

Ne-am gândit mult timp dacă să instalăm un supervizor. Până la urmă, am decis că avem nevoie de el. Am ales S6. Supervizorul asigură managementul containerului: vă permite să vă conectați la acesta dacă procesul principal se blochează și oferă gestionarea manuală a containerului fără a-l recrea. Jurnalele și valorile sunt procese care rulează în interiorul containerului. De asemenea, trebuie să fie controlați cumva și facem asta cu ajutorul unui supervizor. În cele din urmă, S6 se ocupă de menaj, procesarea semnalului și alte sarcini.

Deoarece folosim diferite sisteme de orchestrare, după construcție și rulare, containerul trebuie să înțeleagă în ce mediu se află și să acționeze în funcție de situație. De exemplu:
Acest lucru ne permite să construim o singură imagine și să o rulăm în diferite sisteme de orchestrare, iar aceasta va fi lansată ținând cont de specificul acestui sistem de orchestrare.

 Imagini gata de producție pentru k8s

Pentru același container obținem arbori de proces diferiți în Docker și Kubernetes:

Imagini gata de producție pentru k8s

Sarcina utilă este executată sub supravegherea lui S6. Acordați atenție colectorului și evenimentelor - aceștia sunt agenții noștri responsabili pentru jurnalele și valorile. Kubernetes nu le are, dar Docker le are. De ce? 

Dacă ne uităm la specificația „pod-ului” (în continuare – pod Kubernetes), vom vedea că containerul de evenimente este executat într-un pod, care are un container colector separat care îndeplinește funcția de colectare a metricilor și a jurnalelor. Putem folosi capacitățile Kubernetes: rularea containerelor într-un singur pod, într-un singur proces și/sau spațiu de rețea. Introduceți-vă agenții și îndepliniți unele funcții. Și dacă același container este lansat în Docker, acesta va primi aceleași capabilități ca și ieșire, adică va putea livra jurnalele și valorile, deoarece agenții vor fi lansați intern. 

Metrici și jurnalele

Furnizarea valorilor și a jurnalelor este o sarcină complexă. Există mai multe aspecte ale deciziei ei.
Infrastructura este creată pentru execuția sarcinii utile și nu pentru livrarea în masă a buștenilor. Adică, acest proces trebuie efectuat cu cerințe minime de resurse pentru container. Ne străduim să ajutăm dezvoltatorii noștri: „Obțineți un container Docker Hub, rulați-l și putem livra jurnalele.” 

Al doilea aspect este limitarea volumului de bușteni. Dacă în mai multe containere are loc o creștere a volumului de jurnal (aplicația scoate o urmărire a stivei într-o buclă), sarcina pe CPU, canalele de comunicare și sistemul de procesare a jurnalelor crește, iar acest lucru afectează funcționarea gazdei ca un containere întregi și alte pe gazdă, apoi uneori acest lucru duce la „căderea” gazdei. 

Al treilea aspect este că este necesar să se susțină cât mai multe metode de colectare a valorilor din cutie. De la citirea fișierelor și sondarea Prometheus-endpoint până la utilizarea protocoalelor specifice aplicației.

Iar ultimul aspect este reducerea la minimum a consumului de resurse.

Am ales o soluție Go open-source numită Telegraf. Acesta este un conector universal care acceptă peste 140 de tipuri de canale de intrare (pluginuri de intrare) și 30 de tipuri de canale de ieșire (pluginuri de ieșire). L-am finalizat și acum vă vom spune cum îl folosim folosind Kubernetes ca exemplu. 

Imagini gata de producție pentru k8s

Să presupunem că un dezvoltator implementează o sarcină de lucru și Kubernetes primește o solicitare de a crea un pod. În acest moment, un container numit Collector este creat automat pentru fiecare pod (folosim mutation webhook). Colectionarul este agentul nostru. La început, acest container se configurează pentru a funcționa cu Prometheus și cu sistemul de colectare a buștenilor.

  • Pentru a face acest lucru, folosește adnotări pod și, în funcție de conținutul său, creează, să zicem, un punct final Prometheus; 
  • Pe baza specificațiilor podului și a setărilor specifice ale containerului, acesta decide cum să livreze jurnalele.

Colectăm jurnalele prin API-ul Docker: dezvoltatorii trebuie doar să le pună în stdout sau stderr, iar Collector le va rezolva. Jurnalele sunt colectate în bucăți cu o oarecare întârziere pentru a preveni o posibilă supraîncărcare a gazdei. 

Valorile sunt colectate pe instanțele de încărcare de lucru (procese) în containere. Totul este etichetat: spațiu de nume, sub și așa mai departe, apoi convertit în formatul Prometheus - și devine disponibil pentru colectare (cu excepția jurnalelor). De asemenea, trimitem jurnalele, valorile și evenimentele către Kafka și mai departe:

  • Jurnalele sunt disponibile în Graylog (pentru analiză vizuală);
  • Jurnalele, valorile, evenimentele sunt trimise la Clickhouse pentru stocare pe termen lung.

Totul funcționează exact la fel în AWS, doar că înlocuim Graylog cu Kafka cu Cloudwatch. Trimitem jurnalele acolo și totul se dovedește foarte convenabil: este imediat clar cărui cluster și container aparțin. Același lucru este valabil și pentru Google Stackdriver. Adică, schema noastră funcționează atât on-premise cu Kafka, cât și în cloud. 

Dacă nu avem Kubernetes cu pod-uri, schema este puțin mai complicată, dar funcționează pe aceleași principii.

Imagini gata de producție pentru k8s

Aceleași procese sunt executate în interiorul containerului, sunt orchestrate folosind S6. Toate aceleași procese rulează în același container.

Ca urmare,

Am creat o soluție completă pentru construirea și lansarea imaginilor, cu opțiuni pentru colectarea și livrarea jurnalelor și a valorilor:

  • Am dezvoltat o abordare standardizată a asamblarii imaginilor și, pe baza acesteia, am dezvoltat șabloane CI;
  • Agenții de colectare a datelor sunt extensiile noastre Telegraf. Le-am testat bine în producție;
  • Folosim mutație webhook pentru a implementa containere cu agenți în pod-uri; 
  • Integrat în ecosistemul Kubernetes/Rancher;
  • Putem executa aceleași containere în diferite sisteme de orchestrare și obținem rezultatul pe care îl așteptăm;
  • A creat o configurație complet dinamică de gestionare a containerelor. 

Coautor: Ilya Prudnikov

Sursa: www.habr.com

Adauga un comentariu