Настроить хранение данных приложений, запущенных в кластере Kubernetes, можно несколькими способами. Одни из них уже устарели, другие появились совсем недавно. В этой статье рассмотрим концепцию трёх вариантов подключения СХД, в том числе самый последний — подключение через Container Storage Interface.
Способ 1. Указание PV в манифесте пода
Типичный манифест, описывающий под в кластере Kubernetes:
Цветом выделены части манифеста, где описано, какой том подключается и куда.
В разделе volumeMounts указывают точки монтирования (mountPath) — в какой каталог внутри контейнера будет монтироваться постоянный том, а также имя тома.
В разделе volumes перечисляют все тома, которые используются в поде. Указывают имя каждого тома, а также тип (в нашем случае: awsElasticBlockStore) и параметры подключения. Какие именно параметры перечисляются в манифесте, зависит от типа тома.
Один и тот же том может быть смонтирован одновременно в несколько контейнеров пода. Таким образом разные процессы приложения могут иметь доступ к одним и тем же данным.
Этот способ подключения придумали в самом начале, когда Kubernetes только зарождался, и на сегодня способ устарел.
При его использовании возникает несколько проблем:
все тома надо создавать вручную, Kubernetes не сможет создать ничего за нас;
параметры доступа к каждому из томов уникальные, и их надо указывать в манифестах всех подов, которые используют том;
чтобы поменять систему хранения (например, переехать из AWS в Google Cloud), надо менять настройки и тип подключённых томов во всех манифестах.
Всё это очень неудобно, поэтому в реальности подобным способом пользуются для подключения только некоторых специальных типов томов: configMap, secret, emptyDir, hostPath:
configMap и secret — служебные тома, позволяют создать в контейнере том с файлами из манифестов Kubernetes.
emptyDir — временный том, создаётся только на время жизни пода. Удобно использовать для тестирования или хранения временных данных. Когда pod удаляется, том типа emptyDir тоже удаляется и все данные пропадают.
hostPath — позволяет смонтировать внутрь контейнера с приложением любой каталог локального диска сервера, на котором работает приложение, — в том числе /etc/kubernetes. Это небезопасная возможность, поэтому обычно политики безопасности запрещают использовать тома этого типа. Иначе приложение злоумышленника сможет замонтировать внутрь своего контейнера каталог HTC Kubernetes и украсть все сертификаты кластера. Как правило, тома hostPath разрешают использовать только системным приложениям, которые запускаются в namespace kube-system.
Альтернативный способ подключения — концепция Storage class, PersistentVolumeClaim, PersistentVolume.
Storage class хранит параметры подключения к системе хранения данных.
PersistentVolumeClaim описывает требования к тому, который нужен приложению. PersistentVolume хранит параметры доступа и статус тома.
Суть идеи: в манифесте пода указывают volume типа PersistentVolumeClaim и указывают название этой сущности в параметре claimName.
В манифесте PersistentVolumeClaim описывают требования к тому данных, который необходим приложению. В том числе:
размер диска;
способ доступа: ReadWriteOnce или ReadWriteMany;
ссылка на Storage class — в какой системе хранения данных мы хотим создавать том.
В манифесте Storage class хранятся тип и параметры подключения к системе хранения данных. Они нужны кублету, чтобы смонтировать том к себе на узел.
В манифестах PersistentVolume указывается Storage class и параметры доступа к конкретному тому (ID тома, путь, и т. д.).
Создавая PVC, Kubernetes смотрит, том какого размера и из какого Storage class потребуется, и подбирает свободный PersistentVolume.
Если таких PV нет в наличии, Kubernetes может запустить специальную программу — Provisioner (её название указывают в Storage class). Эта программа подключается к СХД, создаёт том нужного размера, получает идентификатор и создает в кластере Kubernetes манифест PersistentVolume, который связывается с PersistentVolumeClaim.
Всё это множество абстракций позволяет убрать информацию о том, с какой СХД работает приложение, с уровня манифеста приложений на уровень администрирования.
Все параметры подключения к системе хранения данных находятся в Storage class, за который отвечают администраторы кластера. Всё, что надо сделать при переезде из AWS в Google Cloud, — это в манифестах приложения изменить название Storage class в PVC. Persistance Volume для хранения данных будут созданы в кластере автоматически, с помощью программы Provisioner.
Способ 3. Container Storage Interface
Весь код, который взаимодействует с различными системами хранения данных, является частью ядра Kubernetes. Выпуск исправлений ошибок или нового функционала привязан к новым релизам, код приходится изменять для всех поддерживаемых версий Kubernetes. Всё это тяжело поддерживать и добавлять новый функционал.
Чтобы решить проблему, разработчики из Cloud Foundry, Kubernetes, Mesos и Docker создали Container Storage Interface (CSI) — простой унифицированный интерфейс, который описывает взаимодействие системы управления контейнерами и специального драйвера (CSI Driver), работающего с конкретной СХД. Весь код по взаимодействию с СХД вынесли из ядра Kubernetes в отдельную систему.
Как правило, CSI Driver состоит из двух компонентов: Node Plugin и Controller plugin.
Node Plugin запускается на каждом узле и отвечает за монтирование томов и за операции на них. Controller plugin взаимодействует с СХД: создает или удаляет тома, назначает права доступа и т. д.
Пока в ядре Kubernetes остаются старые драйверы, но пользоваться ими уже не рекомендуют и всем советуют устанавливать CSI Driver конкретно для той системы, с которой предстоит работать.
Нововведение может напугать тех, кто уже привык настраивать хранение данных через Storage class, но на самом деле ничего страшного не случилось. Для программистов точно ничего не меняется — они как работали только с именем Storage class, так и продолжат. Для администраторов добавилась установка helm chart и поменялась структура настроек. Если раньше настройки вводились в Storage class напрямую, то теперь их сначала надо задать в helm chart, а потом уже в Storage class. Если разобраться, ничего страшного не произошло.
Давайте, на примере, рассмотрим какие преимущества можно получить, перейдя на подключение СХД Ceph с помощью CSI драйвера.
При работе с Ceph плагин CSI даёт больше возможностей для работы с СХД, чем встроенные драйверы.
Динамическое создание дисков. Обычно диски RBD используются только в режиме RWO, а CSI для Ceph позволяет использовать их в режиме RWX. Несколько pod'ов на разных узлах могут смонтировать один и тот же RDB-диск к себе на узлы и работать с ними параллельно. Справедливости ради, не всё так лучезарно — этот диск можно подключить только как блочное устройство, то есть придётся адаптировать приложение под работу с ним в режиме множественного доступа.
Создание снапшотов. В кластере Kubernetes можно создать манифест с требованием создать снапшот. Плагин CSI его увидит и сделает снапшот с диска. На его основании можно будет сделать либо бэкап, либо копию PersistentVolume.
Увеличение размера диска на СХД и PersistentVolume в кластере Kubernetes.
Квоты. Встроенные в Kubernetes драйверы CephFS не поддерживают квоты, а свежие CSI-плагины со свежим Ceph Nautilus умеют включать квоты на CephFS-разделы.
Метрики. CSI-плагин может отдавать в Prometheus множество метрик о том, какие тома подключены, какие идут взаимодействия и т. д.
Topology aware. Позволяет указать в манифестах, как географически распределён кластер, и избежать подключения к подам, запущенным в Лондоне системы хранения данных, расположенной в Амстердаме.