Прим. перев.: о так называемых плагинах хранилищ «вне дерева» Kubernetes (Out-of-Tree CSI Volume Plugins) мы впервые рассказывали в своём обзоре релиза K8s 1.9, где эта фича появилась в статусе альфа-версии. Автор нового материала — Anoop Vijayan Maniankara (ведущий DevOps-инженер финской компании Tuxera) — собрал ключевые сведения об идеях и устройстве CSI, что помогает быстро познакомиться с новой концепцией, которая, как утверждают некоторые наши сотрудники, «будет the next big thing». Для более подробного и технического изучения CSI в конце статьи приведены полезные ссылки, среди которых я особенно выделю презентацию одного из авторов этой спецификации (Jie Yu). Но начать всё равно стоит с «общей картины»…
Container Storage Interface (CSI) — инициатива, призванная унифицировать интерфейс хранилищ, таких как Ceph, Portworx, NetApp и т.п., в системах оркестровки контейнеров: Kubernetes, Mesos, Docker Swarm, Cloud Foundry и других. Идея в том, чтобы реализация одного CSI производителем хранилища гарантированно работала со всеми этими системами.
Источник изображения: доклад про CSI от Jie Yu на CloudNativeCon EU 2018
Обратите внимание: в этой статье будет рассказано только о динамическом provisioning'е. Предварительно настроенные тома и flex-тома выходят за её рамки. Если хотите лучше разобраться, о чём пойдёт речь, стоит предварительно прочитать документацию Kubernetes. Кроме того, в статье не будет глубокого погружения в детали реализации CSI. Я представлю высокоуровневый обзор CSI и заложу основу для создания CSI-тома. И последнее: для примеров и ссылок на подробности используется информация для Kubernetes.
До того, как погрузиться в тему, важно также знать, что такое sidecar-контейнеры в Kubernetes. Они расширяют возможности основного контейнера (main), существуя в том же поде, разделяя хранилище и сеть.
На момент написания статьи (13 августа 2018 г.) компоненты CSI имели следующие версии:
Первый релиз CSI — v0.1 — состоялся в декабре 2017 года. Конечно, сделать provisioning для внешнего хранилища в системах оркестровки можно было и до его появления. В случае Kubernetes за потребности в хранилищах отвечали плагины томов — volume plugins:
Как видно из картинки выше, такие плагины являются частью ядра системы оркестровки. Из-за этого возникали следующие проблемы, упомянутые в документе с архитектурой CSI:
Представляя CSI, команда Kubernetes выпустила внешние компоненты, не являющиеся частью ядра и предназначенные для взаимодействия с другими внешними компонентами, реализуемыми производителями. Между собой они общаются через сокеты домена (UNIX domain sockets — прим. перев.) с помощью gRPC.
Они полностью реализуются и поддерживаются командой Kubernetes и расширяют действия Kubernetes вне Kubernetes. Производителям можно совсем не волноваться об особенностях их реализации. Состоят из трёх частей:
Специфичная для вендора реализация. Каждый производитель реализует необходимые API в рамках функций gRPC-сервиса. Например, реализация GCE PD или Ceph и т.п. Они тоже состоят из трёх компонентов:
Появление CSI принесло очевидный плюс системам оркестровки и производителям хранилищ. К тому же, хорошо определённые интерфейсы помогают простой реализации и тестированию CSI как разработчикам, так и будущим системам оркестровки. Если вы решите начать реализацию своего CSI после прочтения этого материала, хорошей стартовой точкой станет статья «How to write a Container Storage Interface (CSI) plugin» от Fatih Arslan.
Читайте также в нашем блоге:
Container Storage Interface (CSI) — инициатива, призванная унифицировать интерфейс хранилищ, таких как Ceph, Portworx, NetApp и т.п., в системах оркестровки контейнеров: Kubernetes, Mesos, Docker Swarm, Cloud Foundry и других. Идея в том, чтобы реализация одного CSI производителем хранилища гарантированно работала со всеми этими системами.
Источник изображения: доклад про CSI от Jie Yu на CloudNativeCon EU 2018
Обратите внимание: в этой статье будет рассказано только о динамическом provisioning'е. Предварительно настроенные тома и flex-тома выходят за её рамки. Если хотите лучше разобраться, о чём пойдёт речь, стоит предварительно прочитать документацию Kubernetes. Кроме того, в статье не будет глубокого погружения в детали реализации CSI. Я представлю высокоуровневый обзор CSI и заложу основу для создания CSI-тома. И последнее: для примеров и ссылок на подробности используется информация для Kubernetes.
До того, как погрузиться в тему, важно также знать, что такое sidecar-контейнеры в Kubernetes. Они расширяют возможности основного контейнера (main), существуя в том же поде, разделяя хранилище и сеть.
На момент написания статьи (13 августа 2018 г.) компоненты CSI имели следующие версии:
До появления CSI
Первый релиз CSI — v0.1 — состоялся в декабре 2017 года. Конечно, сделать provisioning для внешнего хранилища в системах оркестровки можно было и до его появления. В случае Kubernetes за потребности в хранилищах отвечали плагины томов — volume plugins:
Как видно из картинки выше, такие плагины являются частью ядра системы оркестровки. Из-за этого возникали следующие проблемы, упомянутые в документе с архитектурой CSI:
- разработка плагина тома плотно связана с релизами Kubernetes и зависима от них;
- разработчики/сообщество Kubernetes ответственны за тестирование и поддержку всех плагинов вместо того, чтобы просто тестировать и поддерживать стабильный API для плагинов;
- баги в плагинах томов могут уронить не только сам плагин, но и критичные компоненты Kubernetes;
- плагины получают полные привилегии компонентов Kubernetes (kubelet и kube-controller-manager);
- разработчики плагинов вынуждены публиковать исходный код плагина и не могут выбрать путь бинарников.
Понимаем CSI
Представляя CSI, команда Kubernetes выпустила внешние компоненты, не являющиеся частью ядра и предназначенные для взаимодействия с другими внешними компонентами, реализуемыми производителями. Между собой они общаются через сокеты домена (UNIX domain sockets — прим. перев.) с помощью gRPC.
Внешние компоненты Kubernetes
Они полностью реализуются и поддерживаются командой Kubernetes и расширяют действия Kubernetes вне Kubernetes. Производителям можно совсем не волноваться об особенностях их реализации. Состоят из трёх частей:
- Driver registrar — sidecar-контейнер, регистрирующий CSI-драйвер в kubelet и добавляющий
NodeId
драйвера в лейбл объекта узла в Kubernetes API. Для этого взаимодействует с сервисом CSI-драйвера Identity (подробнее о нём см. ниже — прим. перев.) и вызываетGetNodeId
у CSI; - External provisioner — sidecar-контейнер, наблюдающий за объектами PersistentVolumeClaim в Kubernetes API и вызывающий команды
CreateVolume
иDeleteVolume
для endpoint'а драйвера; - External attacher — sidecar-контейнер, наблюдающий за объектами VolumeAttachment в Kubernetes API и вызывающий команды
ControllerPublish
иControllerUnpublish
для endpoint'а драйвера.
Внешний компонент от производителя хранилища/третьей стороны
Специфичная для вендора реализация. Каждый производитель реализует необходимые API в рамках функций gRPC-сервиса. Например, реализация GCE PD или Ceph и т.п. Они тоже состоят из трёх компонентов:
- CSI Identity — преимущественно для идентификации плагина: убедиться в том, что он функционирует, вернуть базовую информацию о плагине;
service Identity { // вернуть версию и название плагина rpc GetPluginInfo(GetPluginInfoRequest) returns (GetPluginInfoResponse) {} // сообщить, в состоянии ли плагин обслуживать интерфейс Controller rpc GetPluginCapabilities(GetPluginCapabilitiesRequest) returns (GetPluginCapabilitiesResponse) {} // вызывается системой оркестровки, чтобы проверить, запущен ли плагин rpc Probe (ProbeRequest) returns (ProbeResponse) {} }
(kubernetes-csi-identity.proto) - CSI Controller отвечает за контролирование томов и управление ими: создание, удаление, присоединение/отсоединение, снапшоты и т.п.;
service Controller { // выполнить provisioning тома rpc CreateVolume (CreateVolumeRequest) returns (CreateVolumeResponse) {} // удалить выделенный ранее том rpc DeleteVolume (DeleteVolumeRequest) returns (DeleteVolumeResponse) {} // сделать том доступным на требуемом узле rpc ControllerPublishVolume (ControllerPublishVolumeRequest) returns (ControllerPublishVolumeResponse) {} // сделать том недоступным на требуемом узле rpc ControllerUnpublishVolume (ControllerUnpublishVolumeRequest) returns (ControllerUnpublishVolumeResponse) {} // например, может использоваться для одновременного чтения/записи с нескольких узлов rpc ValidateVolumeCapabilities (ValidateVolumeCapabilitiesRequest) returns (ValidateVolumeCapabilitiesResponse) {} // вернуть все доступные тома rpc ListVolumes (ListVolumesRequest) returns (ListVolumesResponse) {} // полная емкость доступного пространства в пуле rpc GetCapacity (GetCapacityRequest) returns (GetCapacityResponse) {} // например, плагины могут не иметь реализации GetCapacity и Snapshotting rpc ControllerGetCapabilities (ControllerGetCapabilitiesRequest) returns (ControllerGetCapabilitiesResponse) {} // сделать снапшот rpc CreateSnapshot (CreateSnapshotRequest) returns (CreateSnapshotResponse) {} // удалить снапшот rpc DeleteSnapshot (DeleteSnapshotRequest) returns (DeleteSnapshotResponse) {} // вывести список снапшотов rpc ListSnapshots (ListSnapshotsRequest) returns (ListSnapshotsResponse) {} }
(kubernetes-csi-controller.proto) - CSI Node отвечает за контролирование действий тома на узле Kubernetes.
service Node { // временно примонтировать том к staging-пути rpc NodeStageVolume (NodeStageVolumeRequest) returns (NodeStageVolumeResponse) {} // отмонтировать том от staging-пути rpc NodeUnstageVolume (NodeUnstageVolumeRequest) returns (NodeUnstageVolumeResponse) {} // примонтировать том из staging к целевому пути rpc NodePublishVolume (NodePublishVolumeRequest) returns (NodePublishVolumeResponse) {} // отмонтировать том от целевого пути rpc NodeUnpublishVolume (NodeUnpublishVolumeRequest) returns (NodeUnpublishVolumeResponse) {} // статистика по тому rpc NodeGetVolumeStats (NodeGetVolumeStatsRequest) returns (NodeGetVolumeStatsResponse) {} // вернуть уникальный ID узла rpc NodeGetId (NodeGetIdRequest) returns (NodeGetIdResponse) { option deprecated = true; } // вернуть возможности (capabilities) узла rpc NodeGetCapabilities (NodeGetCapabilitiesRequest) returns (NodeGetCapabilitiesResponse) {} // схоже с NodeGetId rpc NodeGetInfo (NodeGetInfoRequest) returns (NodeGetInfoResponse) {} }
(kubernetes-csi-node.proto)
Заключение
Появление CSI принесло очевидный плюс системам оркестровки и производителям хранилищ. К тому же, хорошо определённые интерфейсы помогают простой реализации и тестированию CSI как разработчикам, так и будущим системам оркестровки. Если вы решите начать реализацию своего CSI после прочтения этого материала, хорошей стартовой точкой станет статья «How to write a Container Storage Interface (CSI) plugin» от Fatih Arslan.
Ссылки на литературу
- Спецификация CSI;
- Sidecar-контейнеры в Kubernetes;
- Доклад про CSI от Jie Yu на KubeCon EU: CloudNativeCon EU 2018 (а вот здесь доступно видео с этого выступления — прим. перев.);
- Документ по архитектуре CSI;
- Актуальная документация по CSI от Kubernetes;
- Устаревшая документация по CSI от Kubernetes.
P.S. от переводчика
Читайте также в нашем блоге:
- «Знакомимся с альфа-версией снапшотов томов в Kubernetes»;
- «Kubernetes 1.9: обзор основных новшеств»;
- «Понимаем RBAC в Kubernetes»;
- «Что происходит в Kubernetes при запуске kubectl run? Часть 1»;
- «Как на самом деле работает планировщик Kubernetes?»;
- «За кулисами сети в Kubernetes»;
- «Rook — „самообслуживаемое“ хранилище данных для Kubernetes»;
- «Наш опыт с Kubernetes в небольших проектах» (видео доклада, включающего в себя знакомство с техническим устройством Kubernetes).