Production-ready images for k8s

Тази история разказва как използваме контейнери в продуктовата среда, особено под Kubernetes. Статията е посветена на събиране на метрики и логове от контейнерите, а също така и на изграждането на образи.

Production-ready images for k8s

Ние сме от финтех компанията Exness, която разработва услуги за онлайн търговия и финтех продукти за B2B и B2C. В нашето R&D имаме много различни екипи, в отдела за разработка работят над 100 души.

Представяме екипа, който отговаря за платформата за събиране и стартиране на код от нашите разработчици. В частност, ние отговаряме за събиране, съхранение и предоставяне на метрики, логове и събития от приложенията. В момента управляваме около три хиляди Docker контейнери в продуктовата среда, поддържаме нашето хранилище за big data с капацитет от 50 TB и предоставяме архитектурни решения, които се изграждат около нашата инфраструктура: Kubernetes, Rancher и различни публични облачни доставчици. 

Нашата мотивация

Какво гори? Никой не може да отговори. Где е центърът? Трудно е да се разбере. Кога е започнало да гори? Може да се установи, но не веднага. 

Production-ready images for k8s

Защо едни контейнери стоят, а други падат? Кой контейнер стана причина за това? Нали отвън контейнерите изглеждат еднакво, а отвътре всеки има свой собствен Neo.

Production-ready images for k8s

Нашите разработчици са компетентни момчета. Те правят добри услуги, които носят печалба на компанията. Но понякога се случват факапи, когато контейнерите с приложенията се разпръсват. Един контейнер консумира твърде много CPU, друг — мрежа, трети — операции за вход-изход, четвърти — изобщо не е ясно какво прави със сокетите. Всичко това пада и корабът потъва. 

Агенти

За да разберем какво се случва вътре, решихме да инсталираме агенти направо в контейнерите.

Production-ready images for k8s

Тези агенти са контролиращи програми, които поддържат контейнерите в такова състояние, че да не се счупят взаимно. Агентите са стандартизирани, което позволява стандартизиране на подхода към обслужването на контейнерите. 

В нашия случай агентите трябва да предоставят логове в стандартен формат, тагнати и с тротлинг. Също така те трябва да ни предоставят стандартизирани метрики, разширяеми от гледна точка на бизнес приложенията.

Под агентите също се разбират утилити за експлоатация и поддръжка, които могат да работят в различни оркестрационни системи, поддържащи различни образи (Debian, Alpine, Centos и т.н.).

Накрая, агентите трябва да поддържат прост CI/CD, включващ Docker файлове. В противен случай корабът ще се разпадне, защото контейнерите ще започнат да се доставят по "криви" релси.

Процес на изграждане и създаване на целевия образ

За да бъде всичко стандартно и управляемо, е нужно да се спазва някакъв стандартен процес на изграждане. Затова решихме да сглобяваме контейнери с помощта на контейнери — такава е рекурсията.

Production-ready images for k8s

Тук контейнерите са представени с плътни контури. Освен това решихме да положим в тях дистрибуции, за да "животът да не изглежда розов". Защо това беше направено, ще разкажем по-долу.
 
В резултат на това получихме инструмент за изграждане — контейнер с определена версия, който съдържа референции към определени версии на дистрибуции и определени версии на скриптове.

Как го използваме? Имаме Docker Hub, където съхраняваме контейнера. Ние го зеркалираме в нашата система, за да се освободим от външни зависимости. Получи се контейнер, обозначен с жълт цвят. Създаваме шаблон, за да инсталираме в контейнера всички нужни дистрибуции и скриптове. След това изграждаме готов за експлоатация образ: разработчиците поставят кода и някои свои специфични зависимости. 

Какви са предимствата на такъв подход? 

  • На първо място, пълен контрол на версиите на инструментите за изграждане – контейнер за изграждане, версии на скриптове и дистрибуции. 
  • На второ място, постигнахме стандартизация: създаваме шаблони, междинни и готови за експлоатация образи по един и същи начин. 
  • На трето място, контейнерите ни предоставят преносимост. Днес използваме GitLab, утре можем да преминем към TeamCity или Jenkins и точно така ще можем да стартираме нашите контейнери. 
  • На четвърто място, минимизация на зависимостите. Не е случайно, че сложихме дистрибуции в контейнера, тъй като това позволява да не ги сваляме всеки път от интернет. 
  • На пето място, увеличаване на скоростта на изграждане – наличието на локални копия на образите позволява да не губим време за сваляне, тъй като имаме локален образ. 

С други думи, постигнахме контролируем и гъвкав процес на изграждане. Използваме еднакви средства за изграждане на всякакви контейнери с пълен контрол на версиите. 

Как работи нашата процедура за изграждане

Production-ready images for k8s

Сглобяването започва с една команда, процесът се изпълнява в образа (подчертан в червено). Разработчикът разполага с Docker файл (подчертан в жълто), който рендерираме, заменяйки променливите с техните стойности. В същото време добавяме header’и и footer’и — те са нашите агенти. 

Header добавя дистрибуции от съответните образи. Footers инсталира нашите услуги, конфигурира стартирането на работното натоварване, логване и други агенти, заменя entrypoint и т.н. 

Production-ready images for k8s

Дълго време обсъждахме дали да поставим супервайзор. В крайна сметка решихме, че той ни е необходим. Избрахме S6. Супервайзорът осигурява управление на контейнера: позволява свързване с него в случай на спад на основния процес и дава ръчно управление на контейнера без повторно създаване. Логовете и метриките са процеси, изпълнявани в контейнера. Трябва да ги контролираме по някакъв начин, и правим това с помощта на супервайзора. Накрая, S6 поема задълженията за housekeeping, обработка на сигнали и други задачи.

Тъй като прилагаме различни системи за оркестрация, след сглобяването и стартирането контейнерът трябва да разбере в каква среда се намира и да реагира в съответствие. Например:
Това ни позволява да сглобим един образ и да го стартираме в различни системи за оркестрация, и той ще стартира с оглед на спецификите на тази система за оркестрация.

 Production-ready images for k8s

За един и същ контейнер получаваме различни дървета на процесите в Docker и Kubernetes:

Production-ready images for k8s

Полезното натоварване се изпълнява под супервайзора S6. Обърнете внимание на collector и events — това са нашите агенти, отговорни за логовете и метриките. В Kubernetes ги няма, а в Docker ги има. Защо? 

Ако погледнем спецификацията на 'пода' (тук и нататък – Kubernetes pod), ще видим, че контейнерът events се изпълнява в пода, в който има отделен контейнер collector, изпълняващ функцията за събиране на метрики и логове. Можем да използваме възможностите на Kubernetes: стартиране на контейнери в един pod, в единен процесен и/или мрежови пространства. Всъщност можем да внедряваме своите агенти и да изпълняваме определени функции. И ако същият контейнер стартира в Docker, той ще получи всичките тези възможности, а именно да доставя логове и метрики, тъй като агентите ще бъдат стартирани вътре. 

Метрики и логове

Доставката на метрики и логове е сложна задача. Свързани с нейното решение са няколко аспекта.
Инфраструктура се изгражда за изпълнение на полезен товар, а не за масово предаване на логове. Тоест, този процес трябва да се извършва с минимални изисквания към ресурсите на контейнерите. Ние се стремим да помогнем на нашите разработчици: "Вземете контейнер от Docker Hub, стартирайте и ние можем да предоставим логовете." 

Вторият аспект е ограничаването на обема на логовете. Ако в няколко контейнера възникне ситуация на увеличаване на обема на логовете (приложението в цикъл извежда stack-trace), натоварването на CPU, комуникационните канали и системата за обработка на логовете нараства, и това влияе на работата на хоста като цяло и на другите контейнери на хоста, което понякога води до "падане" на хоста. 

Третият аспект е необходимостта от поддръжка на колкото се може повече методи за събиране на метрики от самото начало. От четене на файлове и опитване на Prometheus-endpoint до използване на специфични протоколи на приложенията.

И последният аспект е необходимостта от минимизиране на потреблението на ресурси.

Ние избрахме open-source решение на Go, наречено Telegraf. Това е универсален конектор, който поддържа над 140 вида входни канали (input plugins) и 30 вида изходни канали (output plugins). Ние го подобрихме и сега ще ви разкажем как той се използва при нас на примера на Kubernetes. 

Production-ready images for k8s

Да предположим, че разработчик разгръща натоварване и Kubernetes получава запитване за създаване на под. В този момент автоматично се създава контейнер, наречен Collector (използваме mutation webhook) за всеки под. Collector е нашият агент. При стартиране, този контейнер се настройва да работи с Prometheus и системата за събиране на логове.

  • За целта той използва анотациите на пода, и в зависимост от съдържанието им, създава, да кажем, крайна точка end-point на Prometheus; 
  • На базата на спецификацията на пода и специфичните настройки на контейнерите решава как да се доставят логовете.

Логовете събираме чрез Docker API: на разработчиците им е достатъчно да ги поставят в stdout или stderr, а след това Collector ще се справи. Логовете се събират на парчета с определено забавяне, за да се предотврати евентуално пренатоварване на хоста. 

Метриките се събират по инстанции на работно натоварване (процеси) в контейнерите. Всичко се маркира с тагове: namespace, под и така нататък, а след това се конвертира в формат Prometheus – и става достъпно за събиране (освен логовете). Също така, логовете, метриките и събитията ги изпращаме в Kafka и после:

  • Логовете са достъпни в Graylog (за визуален анализ);
  • Логовете, метриките и събитията се изпращат в Clickhouse за дългосрочно съхранение.

Същото важи и при AWS, само заменяме Graylog с Kafka на Cloudwatch. Изпращаме там логовете и всичко е много удобно: веднага е ясно към кой клъстер и контейнер принадлежат. Същото важи и за Google Stackdriver. Тоест нашата схема работи както на място с Kafka, така и в облака. 

Ако нямаме Kubernetes с подове, схемата става малко по-сложна, но работи по същите принципи.

Production-ready images for k8s

Вътре в контейнера се изпълняват същите процеси, те се оркестрират с помощта на S6. Всички тези процеси са стартирани вътре в един контейнер.

В крайна сметка

Създадохме цялостно решение за изграждане и пускане на образи в експлоатация, с опции за събиране и доставяне на логове и метрики:

  • Разработихме стандартизиран подход за изграждане на образи, на базата на който разработихме CI шаблони;
  • Агентите за събиране на данни са нашите разширения Telegraf. Те са добре тествани в продукция;
  • Използваме mutation webhook за внедряване на контейнери с агенти в подовете; 
  • Интегрирали сме се в екосистемата Kubernetes/Rancher;
  • Можем да изпълняваме идентични контейнери в различни системи за оркестрация и да получим очаквания от нас резултат;
  • Създадохме напълно динамична конфигурация за управление на контейнерите. 

Съавтор: Иля Прудников

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster