Понимаем Container Storage Interface (в Kubernetes и не только)

в 6:29, , рубрики: csi, devops, kubernetes, Блог компании Флант, системное администрирование, хранилища данных

Прим. перев.: о так называемых плагинах хранилищ «вне дерева» 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 (в Kubernetes и не только) - 1

Container Storage Interface (CSI) — инициатива, призванная унифицировать интерфейс хранилищ, таких как Ceph, Portworx, NetApp и т.п., в системах оркестровки контейнеров: Kubernetes, Mesos, Docker Swarm, Cloud Foundry и других. Идея в том, чтобы реализация одного CSI производителем хранилища гарантированно работала со всеми этими системами.

Понимаем Container Storage Interface (в Kubernetes и не только) - 2
Источник изображения: доклад про CSI от Jie Yu на CloudNativeCon EU 2018

Обратите внимание: в этой статье будет рассказано только о динамическом provisioning'е. Предварительно настроенные тома и flex-тома выходят за её рамки. Если хотите лучше разобраться, о чём пойдёт речь, стоит предварительно прочитать документацию Kubernetes. Кроме того, в статье не будет глубокого погружения в детали реализации CSI. Я представлю высокоуровневый обзор CSI и заложу основу для создания CSI-тома. И последнее: для примеров и ссылок на подробности используется информация для Kubernetes.

До того, как погрузиться в тему, важно также знать, что такое sidecar-контейнеры в Kubernetes. Они расширяют возможности основного контейнера (main), существуя в том же поде, разделяя хранилище и сеть.

На момент написания статьи (13 августа 2018 г.) компоненты CSI имели следующие версии:

Понимаем Container Storage Interface (в Kubernetes и не только) - 3

До появления CSI

Первый релиз CSI — v0.1 — состоялся в декабре 2017 года. Конечно, сделать provisioning для внешнего хранилища в системах оркестровки можно было и до его появления. В случае Kubernetes за потребности в хранилищах отвечали плагины томов — volume plugins:

Понимаем Container Storage Interface (в Kubernetes и не только) - 4

Как видно из картинки выше, такие плагины являются частью ядра системы оркестровки. Из-за этого возникали следующие проблемы, упомянутые в документе с архитектурой CSI:

  • разработка плагина тома плотно связана с релизами Kubernetes и зависима от них;
  • разработчики/сообщество Kubernetes ответственны за тестирование и поддержку всех плагинов вместо того, чтобы просто тестировать и поддерживать стабильный API для плагинов;
  • баги в плагинах томов могут уронить не только сам плагин, но и критичные компоненты Kubernetes;
  • плагины получают полные привилегии компонентов Kubernetes (kubelet и kube-controller-manager);
  • разработчики плагинов вынуждены публиковать исходный код плагина и не могут выбрать путь бинарников.

Понимаем CSI

Представляя CSI, команда Kubernetes выпустила внешние компоненты, не являющиеся частью ядра и предназначенные для взаимодействия с другими внешними компонентами, реализуемыми производителями. Между собой они общаются через сокеты домена (UNIX domain sockets — прим. перев.) с помощью gRPC.

Понимаем Container Storage Interface (в Kubernetes и не только) - 5

Внешние компоненты 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.

Ссылки на литературу

  1. Спецификация CSI;
  2. Sidecar-контейнеры в Kubernetes;
  3. Доклад про CSI от Jie Yu на KubeCon EU: CloudNativeCon EU 2018 вот здесь доступно видео с этого выступления — прим. перев.);
  4. Документ по архитектуре CSI;
  5. Актуальная документация по CSI от Kubernetes;
  6. Устаревшая документация по CSI от Kubernetes.

P.S. от переводчика

Читайте также в нашем блоге:

Автор: Дмитрий Шурупов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js