Всем нравятся контейнеры. По крайней мере, операторов дата-центров, которые наотрез отказываются от внедрения контейнеризации, с каждым днём становится меньше. Контейнеры как легковесный метод виртуализации приложений очень хороши, пока взаимодействуют исключительно между собой в оперативной памяти. Однако как только возникает необходимость обратиться из контейнера к хранилищу данных — и особенно в ситуациях, связанных с обработкой больших данных, — легковесность и эфемерность (отсутствие состояния, stateless) контейнеров начинают играть с ними злую шутку. Для того, чтобы надёжно и с максимальной гибкостью сопрягать эфемерные виртуализованные программные модули с самыми разнообразными системами хранения данных, к каким только может иметься доступ из предоставляющего услугу контейнеризации ЦОДа, и был предложен интерфейс хранилищ для контейнеров — container storage interface, CSI.
Надёжная основа
Контейнеры — сравнительно недавнее веяние в области виртуализации, которое год от года приобретает всё большее распространение в самых различных по структуре и предназначению ЦОДах. Виртуализация абстрагирует исполнение приложений от конкретной аппаратной платформы (правда, здесь возникает необходимость в гипервизоре), тогда как контейнеризация превращает само приложение из монолитного целого в облако взаимодействующих один с другим модулей, каждый из которых обособленно виртуализирован и изолирован на уровне ОС — иными словами, помещён в свой собственный контейнер. Такой контейнер представляет собой эфемерный (stateless), существующий исключительно в оперативной памяти объект, который взаимодействует с внешними по отношению к нему объектами через заранее определённые интерфейсы. Для организации работы отдельных компонентов и уровней приложения необходима оркестровка контейнеров — налаживание их совместной продуктивной работы.
Конкретная реализация архитектуры и характеристики аппаратных компонентов хоста, на котором физически запускается контейнер, влияют на последний лишь опосредованно: больше ресурсов — выше производительность. Можно рассматривать контейнер как комплект программных элементов системы — библиотек, утилит, драйверов, необходимых для запуска данного приложения, упакованный в единый образ и формирующий изолированную среду. Изолированную от тех ресурсов (оперативной памяти, процессорных циклов, логических разделов), что использует сама порождающая контейнер ОС; при этом к ядру единственной исполняемой на хост-системе ОС для реализации базовых зависимостей может обращаться множество контейнеров.
Такие обращения необходимы, например, в ситуации, когда исполняемому в контейнере приложению требуется получить доступ к хранилищу данных в составе хоста либо иного подключённого по сети устройства. Средства контейнеризации, такие как Docker, и оркестраторы контейнеров, такие как Kubernetes, обеспечивают реализацию этих запросов должным образом (не допуская, скажем, одновременных запросов от двух или более контейнеризованных приложений на изменение какого-либо файла). Поскольку контейнеры, напомним ещё раз, эфемерны, изначально они вовсе не предусматривали возможности сохранять какие бы то ни было данные в постоянной памяти на физических носителях. Однако в последнее время начали появляться способы сохранять данные из контейнеров на логические тома — точно так же, как это делается для сущностных (stateful — в противоположность statless, эфемерным) приложений вроде баз данных, доступ к которым возможен и после прекращения работы взаимодействующего с ними процесса.
Постоянство по запросу
По умолчанию оркестратор выделяет для контейнера область физической памяти хоста, которую запущенное в нём приложение воспринимает как логический том на некоем абстрактном накопителе — но которая, однако, будет высвобождена (стёрта) в тот же самый момент, когда прекратит работать данный контейнер. Исходно контейнеризация развивалась в ответ на динамичные и слабопредсказуемые требования веб-приложений, чтобы помочь ЦОДам справляться с регулярно (и спонтанно) возникающими пиками клиентских запросов к веб-серверам. Для того, чтобы обработать такой запрос и выдать в ответ на него некую информацию, подлинно постоянного хранилища данных в составе контейнера действительно не требуется. Теперь же, когда область приложений контейнеризации значительно расширилась, разработчикам оркестраторов приходится искать способы обеспечивать контейнерам доступ к «настоящей» постоянной памяти — на самой хост-системе либо в её непосредственном сетевом окружении.
В частности, чрезвычайно популярный оркестратор с открытым кодом Kubernetes реализует доступ контейнеризованных приложений к файловым, блочным и объектным хранилищам данных — как локальным, так и облачным, а также к различным СУБД. В общем случае контейнер (точнее, в терминологии Kubernetes, кокон — pod, представляющий собой группу из одного или более контейнеров на данном узле, node) формирует запрос к постоянному хранилищу данных (persistent volume claim, PVC), а оркестратор перенаправляет его на соответствующее хранилище (persistent volume, PV).
Такой подход позволяет отделить то, каким образом физически хранятся данные, к которым происходит обращение, от самой функциональной реализации этого обращения — в полном соответствии с общей идеологией контейнеризации. Оркестратор ранжирует доступные хранилища по типам, производительности, ёмкости, времени доступа и прочим параметрам, подбирая в ответ на каждый PVC контейнеризованного приложения оптимальное PV. В Kubernetes для этой цели имеется специализированное средство выявления и оркестровки постоянных хранилищ данных под названием Rook; фактически, интегрированная программно-определяемая система хранения.
Что скрывает CSI
В недавнем обзоре на портале ComputerWeekly речь идет об интерфейсе хранилищ для контейнеров — плагинах для оркестраторов (не обязательно только Kubernetes), которые позволяют поставщикам систем хранения предлагать свои решения для приложений, запускаемых с использованием контейнеризации и нуждающихся в постоянных хранилищах данных. Таких CSI известно уже более шестидесяти, и они отличаются от штатных плагинов в составе оркестраторов (например, от FlexVolume для Kubernetes) упрощённостью спецификаций, в соответствии с которыми сторонние поставщики СХД должны писать свои собственные программные средства сопряжения (драйверы) для подключения к оркестраторам.
Функциональность наиболее популярных CSI достаточно широка. Помимо ожидаемых создания и конфигурирования постоянных внешних хранилищ для контейнерных приложений, эти плагины нередко предусматривают автоматизированное создание снэпшотов и клонирование записываемых на СХД данных для более надёжного их сбережения. Другой важный момент: спецификации сторонних CSI обычно весьма стабильны — и в любом случае не меняются вслед за каждым новым релизом совместимого оркестратора, что позволяет поставщикам СХД не переписывать регулярно драйверы под обновившиеся в очередной раз спецификации.
Главное же достоинство CSI — это эффективная организация взаимодействия между PV, типами хранилищ (storage classes) и PVC. СХД, подключаемые к хост-системе, на которой развёрнута оркестрация контейнеров, ранжируются по типам: например, «быстрое, локальное, с минимальными задержками на операциях записи» или «чрезвычайно ёмкое, облачное, со значительным временем доступа». Производя операцию динамического выделения ресурсов (dynamic provisioning) контейнерам, оркестратор посредством CSI анализирует их PVC и перенаправляет запросы на создание логического раздела и запись данных соответствующим PV. Запросы эти обрабатываются уже внешним хранилищем, что дополнительно высвобождает ресурсы хост-системы и сокращает времязатраты на служебные операции.
Официально CSI получили статус общедоступной функции (general availability status) совсем недавно, в версии Kubernetes 1.13, тогда как актуальная на данный момент — всего лишь 1.17. Но одно только их нынешнее количество показывает, насколько высоко оценили возможности этих плагинов поставщики СХД и заводчики ЦОДов, предоставляющие клиентам услуги контейнеризации приложений. В будущих версиях Kubernetes общедоступными должны стать такие функции, как обеспечение контейнерному приложению прямого доступа к «сырым» блокам на устройстве хранения данных, создание снэпшотов целых томов и даже определение физического расположения внешней СХД, которую система назначила данному приложению в качестве наиболее подходящей (по крайней мере, с точностью до часового пояса).