Imatges preparades per a la producció per a k8s

Aquesta història tracta sobre com fem servir els contenidors en un entorn de producció, concretament Kubernetes. L'article està dedicat a recollir mètriques i registres dels contenidors, així com a crear imatges.

Imatges preparades per a la producció per a k8s

Som de l'empresa fintech Exness, que desenvolupa serveis de comerç en línia i productes fintech per a B2B i B2C. El nostre R+D té molts equips diferents, el departament de desenvolupament té més de 100 empleats.

Representem l'equip responsable de la plataforma perquè els nostres desenvolupadors recopilin i executin codi. En particular, som responsables de recopilar, emmagatzemar i informar mètriques, registres i esdeveniments de les aplicacions. Actualment operem aproximadament tres mil contenidors Docker en un entorn de producció, mantenim el nostre emmagatzematge de grans dades de 50 TB i oferim solucions arquitectòniques que es construeixen al voltant de la nostra infraestructura: Kubernetes, Rancher i diversos proveïdors de núvol públic. 

La nostra motivació

Què està cremant? Ningú pot respondre. On és la llar? És difícil d'entendre. Quan es va incendiar? Ho pots esbrinar, però no de seguida. 

Imatges preparades per a la producció per a k8s

Per què alguns contenidors estan parats mentre que altres han caigut? Quin contenidor tenia la culpa? Al cap i a la fi, l'exterior dels contenidors és el mateix, però dins cadascun té el seu Neo.

Imatges preparades per a la producció per a k8s

Els nostres desenvolupadors són nois competents. Fan bons serveis que aporten beneficis a l'empresa. Però hi ha errors quan els contenidors amb aplicacions es desvien. Un contenidor consumeix massa CPU, un altre consumeix la xarxa, el tercer consumeix operacions d'E/S i el quart no està del tot clar què fa amb els sòcols. Tot cau i el vaixell s'enfonsa. 

Agents

Per entendre què passa a dins, hem decidit col·locar els agents directament en contenidors.

Imatges preparades per a la producció per a k8s

Aquests agents són programes de contenció que mantenen els contenidors en un estat tal que no es trenquin entre ells. Els agents estan estandarditzats, i això permet un enfocament estandarditzat per donar servei als contenidors. 

En el nostre cas, els agents han de proporcionar registres en un format estàndard, etiquetats i accelerats. També haurien de proporcionar-nos mètriques estandarditzades que siguin extensibles des d'una perspectiva d'aplicació empresarial.

Els agents també signifiquen utilitats d'operació i manteniment que poden funcionar en diferents sistemes d'orquestració que suporten diferents imatges (Debian, Alpine, Centos, etc.).

Finalment, els agents han de suportar CI/CD senzills que incloguin fitxers Docker. En cas contrari, el vaixell es trencarà, perquè els contenidors es començaran a lliurar per rails "torçats".

Procés de creació i dispositiu d'imatge de destinació

Per mantenir tot estandarditzat i manejable, cal seguir algun tipus de procés de creació estàndard. Per tant, vam decidir recollir contenidors per contenidors, això és recursivitat.

Imatges preparades per a la producció per a k8s

Aquí els contenidors estan representats per contorns sòlids. Al mateix temps, van decidir posar-hi kits de distribució perquè “la vida no sembli gerds”. Per què es va fer això, explicarem a continuació.
 
El resultat és una eina de compilació: un contenidor específic de la versió que fa referència a versions de distribució específiques i versions d'script específiques.

Com el fem servir? Tenim un Docker Hub que conté un contenidor. Ho reflectim dins del nostre sistema per desfer-nos de les dependències externes. El resultat és un recipient marcat en groc. Creem una plantilla per instal·lar totes les distribucions i scripts que necessitem al contenidor. Després d'això, muntem una imatge llesta per utilitzar: els desenvolupadors hi posen codi i algunes de les seves pròpies dependències especials. 

Què té de bo aquest enfocament? 

  • En primer lloc, control complet de versions de les eines de compilació: versions de contenidors, scripts i distribució de creació. 
  • En segon lloc, hem aconseguit l'estandardització: creem plantilles, imatge intermèdia i llesta per utilitzar de la mateixa manera. 
  • En tercer lloc, els contenidors ens donen portabilitat. Avui fem servir Gitlab, i demà canviarem a TeamCity o Jenkins i podrem executar els nostres contenidors de la mateixa manera. 
  • En quart lloc, minimitzar les dependències. No ha estat casualitat que posem kits de distribució al contenidor, perquè això ens permet evitar en tot moment descarregar-los d'Internet. 
  • En cinquè lloc, la velocitat de creació ha augmentat: la presència de còpies locals d'imatges us permet evitar perdre el temps en la descàrrega, ja que hi ha una imatge local. 

És a dir, hem aconseguit un procés de muntatge controlat i flexible. Utilitzem les mateixes eines per construir qualsevol contenidor totalment versionat. 

Com funciona el nostre procediment de construcció

Imatges preparades per a la producció per a k8s

El conjunt es llança amb una ordre, el procés s'executa a la imatge (ressaltat en vermell). El desenvolupador té un fitxer Docker (ressaltat en groc), el renderitzem, substituint les variables per valors. I al llarg del camí afegim capçaleres i peus de pàgina: aquests són els nostres agents. 

La capçalera afegeix distribucions a partir de les imatges corresponents. I footer instal·la els nostres serveis a l'interior, configura el llançament de càrrega de treball, registre i altres agents, substitueix el punt d'entrada, etc. 

Imatges preparades per a la producció per a k8s

Vam pensar durant molt de temps si instal·lar un supervisor. Al final, vam decidir que el necessitàvem. Vam triar S6. El supervisor proporciona la gestió del contenidor: permet connectar-s'hi si el procés principal falla i proporciona la gestió manual del contenidor sense tornar-lo a crear. Els registres i les mètriques són processos que s'executen dins del contenidor. També s'han de controlar d'alguna manera, i ho fem amb l'ajuda d'un supervisor. Finalment, l'S6 s'encarrega de la neteja, el processament del senyal i altres tasques.

Com que fem servir diferents sistemes d'orquestració, després de construir i executar, el contenidor ha d'entendre en quin entorn es troba i actuar segons la situació. Per exemple:
Això ens permet construir una imatge i executar-la en diferents sistemes d'orquestració, i es llançarà tenint en compte les especificitats d'aquest sistema d'orquestració.

 Imatges preparades per a la producció per a k8s

Per al mateix contenidor obtenim diferents arbres de procés a Docker i Kubernetes:

Imatges preparades per a la producció per a k8s

La càrrega útil s'executa sota la supervisió de S6. Presta atenció al col·leccionista i als esdeveniments: aquests són els nostres agents responsables dels registres i mètriques. Kubernetes no en té, però Docker sí. Per què? 

Si ens fixem en l'especificació del "pod" (d'ara endavant - pod Kubernetes), veurem que el contenidor d'esdeveniments s'executa en un pod, que té un contenidor de col·lector independent que realitza la funció de recollir mètriques i registres. Podem utilitzar les capacitats de Kubernetes: executar contenidors en un pod, en un sol procés i/o espai de xarxa. Introduïu els vostres agents i realitzeu algunes funcions. I si es llança el mateix contenidor a Docker, rebrà totes les mateixes capacitats que la sortida, és a dir, podrà lliurar registres i mètriques, ja que els agents es llançaran internament. 

Mètriques i registres

El lliurament de mètriques i registres és una tasca complexa. Hi ha diversos aspectes en la seva decisió.
La infraestructura es crea per a l'execució de la càrrega útil, i no per al lliurament massiu de registres. És a dir, aquest procés s'ha de realitzar amb uns requisits mínims de recursos del contenidor. Ens esforcem per ajudar els nostres desenvolupadors: "Aconseguiu un contenidor Docker Hub, executeu-lo i podem lliurar els registres". 

El segon aspecte és limitar el volum de registres. Si es produeix un augment del volum de registres en diversos contenidors (l'aplicació produeix una traça de pila en un bucle), la càrrega de la CPU, els canals de comunicació i el sistema de processament de registres augmenta, i això afecta el funcionament de l'amfitrió com a contenidors sencers i altres a l'amfitrió, de vegades això condueix a la "caiguda" de l'amfitrió. 

El tercer aspecte és que és necessari donar suport a tants mètodes de recollida de mètriques com sigui possible. Des de la lectura de fitxers i la consulta de Prometheus-endpoint fins a l'ús de protocols específics de l'aplicació.

I l'últim aspecte és minimitzar el consum de recursos.

Vam triar una solució Go de codi obert anomenada Telegraf. Aquest és un connector universal que admet més de 140 tipus de canals d'entrada (connectors d'entrada) i 30 tipus de canals de sortida (connectors de sortida). L'hem finalitzat i ara us explicarem com l'utilitzem fent servir Kubernetes com a exemple. 

Imatges preparades per a la producció per a k8s

Suposem que un desenvolupador desplega una càrrega de treball i Kubernetes rep una sol·licitud per crear un pod. En aquest punt, es crea automàticament un contenidor anomenat Collector per a cada pod (utilitzem mutation webhook). El col·leccionista és el nostre agent. Al principi, aquest contenidor es configura per funcionar amb Prometheus i el sistema de recollida de registres.

  • Per fer-ho, utilitza anotacions de pod i, depenent del seu contingut, crea, per exemple, un punt final de Prometheus; 
  • En funció de l'especificació de la beina i de la configuració específica del contenidor, decideix com lliurar els registres.

Recopilem els registres mitjançant l'API de Docker: els desenvolupadors només han de posar-los a stdout o stderr i Collector ho resoldrà. Els registres es recullen en trossos amb cert retard per evitar una possible sobrecàrrega de l'amfitrió. 

Les mètriques es recullen a través de les instàncies de càrrega de treball (processos) als contenidors. Tot està etiquetat: espai de noms, sota, etc., i després es converteix al format Prometheus, i està disponible per a la recollida (excepte els registres). També enviem registres, mètriques i esdeveniments a Kafka i més:

  • Els registres estan disponibles a Graylog (per a l'anàlisi visual);
  • Els registres, mètriques i esdeveniments s'envien a Clickhouse per a l'emmagatzematge a llarg termini.

Tot funciona exactament igual a AWS, només que substituïm Graylog per Kafka per Cloudwatch. Hi enviem els registres i tot resulta molt convenient: de seguida queda clar a quin clúster i contenidor pertanyen. El mateix passa amb Google Stackdriver. És a dir, el nostre esquema funciona tant on-premise amb Kafka com al núvol. 

Si no tenim Kubernetes amb pods, l'esquema és una mica més complicat, però funciona amb els mateixos principis.

Imatges preparades per a la producció per a k8s

Els mateixos processos s'executen dins del contenidor, s'orquestren mitjançant S6. Tots els mateixos processos s'executen dins del mateix contenidor.

Com a resultat, els

Hem creat una solució completa per crear i llançar imatges, amb opcions per recopilar i lliurar registres i mètriques:

  • Hem desenvolupat un enfocament estandarditzat per a l'assemblatge d'imatges i, a partir d'ell, hem desenvolupat plantilles de CI;
  • Els agents de recollida de dades són les nostres extensions de Telegraf. Els vam provar bé en producció;
  • Utilitzem mutació webhook per implementar contenidors amb agents en pods; 
  • Integrat a l'ecosistema Kubernetes/Rancher;
  • Podem executar els mateixos contenidors en diferents sistemes d'orquestració i obtenir el resultat que esperem;
  • S'ha creat una configuració de gestió de contenidors completament dinàmica. 

Coautor: Ilya Prudnikov

Font: www.habr.com

Afegeix comentari