Здравейте, Хабр!
Напомняме ви, че излезе нова изключително интересна и полезна статия за шаблоните на Kubernetes. Всичко започна с "" на Брендан Бърнс и, всъщност, работата в този сегмент у нас . Днес ви предлагаме да прочетете статия от блога на MinIO, която накратко изложи тенденциите и спецификата на шаблоните за съхранение на данни в Kubernetes.
Kubernetes коренно промени традиционните шаблони за разработка и разгръщане на приложения. Сега на екипа му могат да отнемат само броени дни за разработка, тестване и разгръщане на приложение – в различни среди, и всичко това в рамките на Kubernetes клъстери. Такъв подход с технологии от предишните поколения обикновено отнемаше цели седмици, ако не и месеци.
Това ускорение стана възможно благодарение на абстракцията, предоставяна от Kubernetes – тоест, благодарение на факта, че Kubernetes сам осъществява взаимодействието с ниско ниво детайли на физически или виртуални машини, позволявайки на потребителите да обявяват наред с другите параметри необходимия процесор, необходимия обем памет и броя на инстанциите на контейнерите. Тъй като в поддръжката на Kubernetes е ангажирана огромна общност, а обхватът на приложението на Kubernetes постоянно се разширява, той е с голяма преднина пред всички платформи за оркестрация на контейнери.
С разширяването на използването на Kubernetes нараства и объркването относно прилаганите в него шаблони за съхранение на данни.
При всеобщата конкуренция за парче от пая (тоест, за хранилище на данни), когато се заговори за съхранение на данни, сигналът тук потъва в силен шум.
Kubernetes олицетворява съвременната модел на разработка и разгръщане на приложения, както и управлението им. Такъв съвременен модел открепя съхранението на данни от изчисленията. За да разберем напълно такава открепеност в контекста на Kubernetes, също е нужно да разберем какво представляват приложенията с и без запазено състояние, а също как съхранението на данни се интегрира с това. Именно тук подходът REST API, прилаган S3, има явни предимства в сравнение с подхода POSIX/CSI, характерен за другите решения.
В тази статия ще обсъдим моделите за съхранение на данни в Kubernetes и отделно ще се спрем на спора за приложенията, които работят с и без съхранение на състояние, за да разберем каква е разликата между тях и защо тя е важна. По-нататък в текста ще разгледаме приложенията и използваните в тях модели за съхранение на данни в светлината на най-добрите практики при работа с контейнери и Kubernetes.
Контейнери без съхранение на състояние
Контейнерите по природа са леки и ефимерни. Те могат лесно да бъдат спирани, изтривани или разгръщани на друг възел - всичко това отнема броени секунди. В голяма система за оркестрация на контейнери такива операции се извършват постоянно, а потребителите дори не забелязват тези промени. Въпреки това, преместванията са възможни, само ако контейнерът няма зависимости от възела, на който се намира. За такива контейнери се казва, че работят без съхранение на състояние.
Контейнери със съхранение на състояние
Ако контейнерът съхранява данни на локално свързани устройства (или на блочно устройство), хранилището, на което е разположен, трябва да бъде преместено на нов възел заедно с контейнера в случай на отказ. Това е важно, тъй като в противен случай приложението, работещо в контейнера, няма да може да функционира правилно, тъй като е необходимо да получава достъп до данните, съхранени на локалните носители. За такива контейнери се казва, че работят съхранение на състояние.
От чисто техническа гледна точка контейнерите със съхранение на състояние също могат да бъдат прехвърляни на други възли. Обикновено това се осигурява с помощта на разпределени файлови системи или блочни мрежови хранилища, прикрепени към всички възли, на които работят контейнерите. По този начин контейнерите получават достъп до томове за персистентно съхранение на данни, а информацията се съхранява на дискове, разположени в цялата мрежа. Този метод ще нарека "контейнерен подход със съхранение на състояние", и в оставащата част от статията ще го именувам така за единообразие.

При типичния контейнерен подход с опазване на състоянието всички приложения се прикрепят към една разпределена файлова система - така се получава своеобразно споделено хранилище, където се съхраняват всички данни на приложенията. Възможни са някои вариации, но това е високоприет подход.
Сега нека да разгледаме защо контейнерният подход с опазване на състоянието в облачно-ориентирания свят е антипатерн.
Облачно-ориентирано проектиране на приложенията
Традиционно приложенията използваха бази данни за структурирано съхранение на информация и локални дискове или разпределени файлssystemи, където се съхраняваха всички неструктурирани или дори полуструктурирани данни. С нарастващия обем на неструктурирани данни, разработчиците осъзнаха, че POSIX е твърде "балаклив", свързан е с значителни разходи и в крайна сметка пречи на работата на приложенията при реални големи мащаби.
Това основно допринесе за появата на нов стандарт за съхранение на данни, а именно облачно-ориентирани хранилища, които работят основно на основата на REST API и освобождават приложението от тежестта на поддържане на локалното хранилище. В такъв случай приложението всъщност преминава в режим на работа без опазване на състоянието (тъй като състоянието се намира в отдалечено хранилище). Съвременните приложения се изграждат от нулата, като се има предвид този фактор. Като правило, всяко съвременно приложение, което обработва данни от всякакъв вид (логове, метаданни, блобове и т.н.) е построено по облачно-ориентирана парадигма, където състоянието се прехвърля в специално отделена софтуерна система за неговото съхранение.
Контейнерният подход с опазване на състоянието връща цялата тази парадигма точно до началото, откъдето е започнала!
При използване на POSIX интерфейси за съхранение на данни, приложенията функционират по същия начин, както ако запазваха състояние, и поради това отстъпват от най-важните постулати за облачно проектиране, а именно възможността да се променят размерите на работните потоци на приложението в зависимост от входящото натоварване, да се прехвърлят на нов възел, веднага щом актуалният възел се провали и т.н.
Ако разгледаме тази ситуация по-внимателно, ще открием, че при избора на хранилище за данни отново и отново се сблъскваме с дилемата "POSIX срещу REST API", НО с допълнително утежняване на проблемите с POSIX, обусловено от разпределената природа на Kubernetes обстановките. По-специално,
- POSIX е многословен: семантиката на POSIX изисква да бъде свързана с всяка операция метаданни и дескриптори на файлове, които помагат за поддържане на състоянието на операцията. Това води до значителни разходи, които нямат реална стойност. API за обектно съхранение, по-специално S3 API, премахнаха тези изисквания, позволявайки на приложението да извърши операцията и след това да "забрави" за извикването. Отговорът на системата за съхранение на данни показва дали действието е било успешно или не. В случай на неуспех приложението може да извърши повторна опит.
- Мрежови ограничения: В разпределена система е подразбирано, че може да съществуват множество приложения, опитващи се да записват данни на една и съща прикрепена съхранение. Затова, освен че приложенията ще конкурират помежду си за пропускателната способност (за да предават данни на носителя), самата система за съхранение на данни ще конкурира за тази пропускателна способност, разпределяйки данни по физическите дискове. Поради многословността на POSIX, броят на мрежовите извиквания нараства многократно. От друга страна, S3 API осигурява ясно разграничение между мрежовите извиквания, които идват от клиента към сървъра и тези, които се случват в рамките на сървъра.
- Сигурност: Моделите на сигурност POSIX разчитат на активно участие на хората: администраторите конфигурират конкретни нива на достъп за всеки потребител или група. Такава парадигма трудно се адаптира към облачно-ориентирания свят. Съвременните приложения зависят от модели на сигурност, свързани с API, където правата на достъп се определят като набор от политики, се предоставят сервизни акаунти, временни удостоверителни данни и т.н.
- Управляемост: Контейнерите с запазено състояние водят до определени разходи, свързани с управлението. Става дума за синхронизация на паралелен достъп до данни, осигуряване на консистентност на данните; всичко това изисква внимателно обмисляне на патерните на достъп до данни, които да се използват. Трябва да се инсталират, контролират и конфигурират допълнителни програми, да не говорим за допълнителните усилия, вложени в разработката.
Контейнерен интерфейс за съхранение на данни
Докато контейнерният интерфейс за съхранение на данни (CSI) значително помогна за разпространението на нивото на томове в Kubernetes, частично прехвърляйки го на трети страни доставчици на данни, той също така случайно допринесе за убеждението, че контейнерният подход с запазено състояние е препоръчителен метод за съхранение на данни в Kubernetes.
CSI е разработен като стандарт за предоставяне на произволни системи за блочно и файлово съхранение на наследени приложения при работа с Kubernetes. Както бе показано в тази статия, единствената ситуация, в която контейнерният подход с запазено състояние (и CSI в настоящата му форма) е целесъобразен, е когато самото приложение е наследена система, в която не може да се добави поддръжка на API за обектно съхранение на данни.
Важно е да разберем, че, използвайки CSI в настоящата му форма, т.е. монтирайки томове при работа с съвременни приложения, ние ще се сблъскаме с приблизително същите проблеми, които възникваха и в системите, където съхранението на данни е организирано в стил POSIX.
По-качествен подход
В този случай е важно да се разбере, че повечето приложения по същността си не са проектирани специално за работа със запазване на състояние или без запазване на състояние. Такова поведение зависи от общата архитектура на системата и от конкретните опции, избрани при проектирането. Нека поговорим малко за приложенията, които запазват състояние.
В принципе, всички данни на приложенията могат да бъдат класифицирани в няколко широки типа:
- Данни от логове
- Данни от времеви марки
- Данни от транзакции
- Метаданни
- Образи на контейнери
- Данни на блобове (големи двоични обекти)
Всички тези типове данни са много добре поддържани в съвременните платформи за съхранение на данни и съществуват няколко облачно-ориентирани платформи, приспособени за доставка на данни в всеки от тези конкретни формати. Например, данните от транзакции и метаданните могат да се съхраняват в съвременна облачно-ориентирана база данни, като CockroachDB, YugaByte и др. Образите на контейнерите или данните на блобове могат да се съхраняват в Docker регистър, базиран на MinIO. Данните от времевите марки могат да се съхраняват в база данни на времеви редове, например InfluxDB и др. Няма да навлизаме в детайлите на всеки тип данни и свързаните приложения, но общата идея е да се избегне персистентното съхранение на данни, основано на локално монтиране на дискове.

Освен това, често е ефективно да се предостави ниво на временно кеширане, което служи на приложенията като своеобразно хранилище на временни файлове, но приложенията не бива да разчитат на това ниво като на източник на истина.
Съхранение за приложения със запазване на състояние
Докато в повечето случаи е полезно да се държат приложенията без запазване на състояние, тези приложения, които са предназначени за съхранение на данни – например, бази данни, обектни хранилища, хранилища на ключ-стойност – трябва да запазват състояние. Нека разгледаме защо тези приложения се внедряват в Kubernetes. В пример ще вземем MinIO, но подобни принципи са приложими и за всякакви други значими облачно-ориентирани системи за съхранение на данни.
Облачните приложения са проектирани с мисъл за максимално ефективно използване на гъвкавостта, характерна за контейнерите. Това означава, че не се правят предположения относно средата, в която ще бъдат внедрени. Например, в MinIO се използва вътрешен механизъм за излишно кодиране (erasure coding), който осигурява на системата достатъчна устойчивост, за да остане функционираща дори при отказ на половината от дисковете. MinIO също така управлява целостта и сигурността на данните, използвайки собствено хеширане и криптиране от страната на сървъра.
За такива облачно ориентирани приложения, локалните персистентни томове (PV) са най-удобни като резервно хранилище. Локалният PV предоставя възможност за съхранение на сурови данни, докато приложенията, работещи върху тези PV, сами събират информация, позволяваща мащабиране на данните и управление на нарастващите изисквания към данните.
Този подход е много по-прост и значително по-добре мащабируем в сравнение с PV на базата на CSI, които въвеждат свои собствени нива на управление на данните и излишък; проблемът е, че тези нива обикновено конфликтуват с приложения, проектирани на принципа за запазване на състоянието.
Увереното движение към отделяне на данните от изчисленията
В тази статия разгледахме как приложенията се преориентират към работа без запазване на състояние, или с други думи, съхранението на данните се отделя от изчисленията върху тях. В заключение, нека разгледаме няколко реални примера на тази тенденция.
, известната платформа за анализ на данни, традиционно се използваше със запазване на състояние и внедряване в файловата система HDFS. Въпреки това, с прехода на Spark в облачно ориентирания свят, тази платформа все по-активно се използва без запазване на състояние чрез `s3a`. Spark използва s3a за предаване на състоянието в други системи, докато самите контейнери Spark работят изцяло без запазване на състояние. Други големи предприятия в областта на анализа на големи данни, по-специално , , също преминават към работа с разделение на съхранението на данните и изчисленията върху тях.
Подобни модели могат да бъдат видени и на други големи аналитични платформи, включително Presto, Tensorflow to R, Jupyter. Изнасяйки състоянието в отдалечени облачни системи за съхранение на данни, управлението на вашето приложение и неговото мащабиране става много по-лесно. Освен това, това улеснява преносимостта на приложението в различни среди.
Източник: habr.com
