persistence volume что это
☸️ Распределенное хранение данных в Kubernetes
Kubernetes отлично подходит для приложений без учета их состояния.
Разверните свое приложение, масштабируйте его до сотен экземпляров, будьте счастливы.
Но как вы управляете хранилищем?
Как мы можем гарантировать, что каждое из наших сотен приложений получит надежное, быстрое и дешевое хранилище?
Давайте возьмем типичный кластер Kubernetes с несколькими узлами (серверами Linux), которые обеспечивают несколько копий нашего приложения:
Persistent Volume Claims
В Kubernetes мы определяем PersistentVolumeClaims, чтобы запросить нашу систему хранения.
Проще говоря, приложение «требует» немного памяти, и система отвечает настраиваемым способом:
App1 – > VolumeClaim
Введите Rook.io
Rook и Ceph
Rook – это система, которая находится в вашем кластере и отвечает на запросы на хранение, но сама она не является системой хранения.
Хотя это немного усложняет ситуацию, вы должны чувствовать себя хорошо, потому что, хотя Rook и новичок, система хранения, которую он использует под капотом, закалена и далека от бета-тестирования.
Мы будем использовать Ceph, которому около 15 лет, который используется и разрабатывается такими компаниями, как Canonical, CERN, Cisco, Fujitsu, Intel, Red Hat и SanDisk.
Это очень далеко от Kubernetes-Hipster, несмотря на то, как круто выглядит проект Rook!
Учитывая, что Rook версии 1.0 и Ceph поддерживают некоторые из самых важных в мире наборов данных, я бы сказал, что настало время обрести уверенность и вернуть контроль над нашим хранилищем данных!
Я буду строить RAID-массивы в 2020-х годах, и никто не сможет меня остановить!
Установка
Я не буду концентрироваться на первоначальной установке здесь, так как руководство по Rook простое.
После установки Rook мы создадим несколько компонентов:
Давайте начнем с CephCluster:
Мы подождем, пока наш CephCluster будет установлен – а вы уже можете взглянуть на созданный вами объект CephCluster:
Почему в Kubernetes так сложно с хранилищами?
Когда пришли оркестраторы контейнеров, вроде Kubernetes, подход к разработке и деплою приложений изменился кардинально. Появились микрослужбы, а для разработчика логика приложения больше не связана с инфраструктурой: создавай себе приложения и предлагай новые функции.
Kubernetes абстрагируется от физических компьютеров, которыми управляет. Только скажите ему, сколько надо памяти и вычислительной мощности, — и все получите. Ифраструктура? Не, не слыхали.
Управляя образами Docker, Kubernetes и приложения делает переносимыми. Разработав контейнерные приложения с Kubernetes, их можно деплоить хоть куда: в открытое облако, локально или в гибридную среду, — и при этом не менять код.
Мы любим Kubernetes за масштабируемость, переносимость и управляемость, но вот состояния он не хранит. А ведь у нас почти все приложения stateful, то есть им нужно внешнее хранилище.
В Kubernetes очень динамичная архитектура. Контейнеры создаются и уничтожаются в зависимости от нагрузки и указаний разработчиков. Поды и контейнеры самовосстанавливаются и реплицируются. Они, по сути, эфемерны.
Внешнему хранилищу такая изменчивость не по зубам. Оно не подчиняется правилам динамического создания и уничтожения.
Чуть только надо развернуть stateful-приложение в другую инфраструктуру: в другое облако там, локально или в гибридную модель, — как у него возникают проблемы с переносимостью. Внешнее хранилище можно привязать к конкретному облаку.
Вот только в этих хранилищах для облачных приложений сам черт ногу сломит. И поди пойми хитровыдуманные значения и смыслы терминологии хранилищ в Kubernetes. А еще есть собственные хранилища Kubernetes, опенсорс-платформы, управляемые или платные сервисы…
Казалось бы, разверни базу данных в Kubernetes — надо только выбрать подходящее решение, упаковать его в контейнер для работы на локальном диске и развернуть в кластер как очередную рабочую нагрузку. Но у базы данных свои особенности, так что мысля — не айс.
Контейнеры — они же так слеплены, что своё состояние не сохраняют. Потому-то их так легко запускать и останавливать. А раз нечего сохранять и переносить, кластер не возится с операциями чтения и копирования.
С базой данных состояние хранить придется. Если база данных, развернутая на кластер в контейнере, никуда не переносится и не запускается слишком часто, в игру вступает физика хранения данных. В идеале контейнеры, которые используют данные, должны находиться в одном поде с базой данных.
В некоторых случаях базу данных, конечно, можно развернуть в контейнер. В тестовой среде или в задачах, где данных немного, базы данных комфортно живут в кластерах.
Для продакшена обычно нужно внешнее хранилище.
Kubernetes общается с хранилищем через интерфейсы плоскости управления. Они связывают Kubernetes с внешним хранилищем. Привязанные к Kubernetes внешние хранилища называются плагинами томов. С ними можно абстрагировать хранение и переносить хранилища.
Раньше плагины томов создавались, привязывались, компилировались и поставлялись с помощью кодовой базы Kubernetes. Это очень ограничивало разработчиков и требовало дополнительного обслуживания: хочешь добавить новые хранилища — изволь менять кодовую базу Kubernetes.
Теперь деплой плагины томов в кластер — не хочу. И в кодовой базе копаться не надо. Спасибо CSI и Flexvolume.
Собственное хранилище Kubernetes
Как Kubernetes решает вопросы хранения? Решений несколько: эфемерные варианты, постоянное хранение в постоянных томах, запросы Persistent Volume Claim, классы хранилищ или StatefulSets. Поди разберись, в общем.
Постоянные тома (Persistent Volumes, PV) — это единицы хранения, подготовленные админом. Они не зависят от подов и их скоротечной жизни.
Persistent Volume Claim (PVC) — это запросы на хранилище, то есть PV. С PVC можно привязать хранилище к ноде, и эта нода будет его использовать.
С хранилищем можно работать статически или динамически.
При статическом подходе админ заранее, до запросов, готовит PV, которые предположительно понадобятся подам, и эти PV вручную привязаны к конкретным подам с помощью явных PVC.
На практике специально определенные PV несовместимы с переносимой структурой Kubernetes — хранилище зависит от среды, вроде AWS EBS или постоянного диска GCE. Для привязки вручную нужно указать на конкретное хранилище в файле YAML.
Статический подход вообще противоречит философии Kubernetes: ЦП и память не выделяются заранее и не привязываются к подам или контейнерам. Они выдаются динамически.
Для динамической подготовки мы используем классы хранилища. Администратору кластера не нужно заранее создавать PV. Он создает несколько профилей хранилища, наподобие шаблонов. Когда разработчик делает запрос PVC, в момент запроса один из этих шаблонов создается и привязывается к поду.
Вот так, в самых общих чертах, Kubernetes работает с внешним хранилищем. Есть много других вариантов.
CSI — Container Storage Interface
Есть такая штука — Container Storage Interface. CSI создан рабочей группой CNCF по хранилищам, которая решила определить стандартный интерфейс хранения контейнеров, чтобы драйверы хранилища работали с любым оркестратором.
Спецификации CSI уже адаптированы для Kubernetes, и есть куча плагинов драйвера для деплоя в кластере Kubernetes. Надо получить доступ к хранилищу через драйвер тома, совместимый с CSI, — используйте тип тома csi в Kubernetes.
С CSI хранилище можно считать еще одной рабочей нагрузкой для контейнеризации и деплоя в кластер Kubernetes.
Если хотите подробностей, послушайте, как Цзе Юй рассказывает о CSI в нашем подкасте.
Опенсорс-проекты
Инструменты и проекты для облачных технологий шустро плодятся, и изрядная доля опенсорс-проектов — что логично — решают одну из главных проблем продакшена: работа с хранилищами в облачной архитектуре.
Самые популярные из них — Ceph и Rook.
Ceph — это динамически управляемый, распределенный кластер хранилища с горизонтальным масштабированием. Ceph дает логическую абстракцию для ресурсов хранилища. У него нет единой точки отказа, он сам собой управляет и работает на базе ПО. Ceph предоставляет интерфейсы для хранения блоков, объектов и файлов одновременно для одного кластера хранилища.
У Ceph очень сложная архитектура с RADOS, librados, RADOSGW, RDB, алгоритмом CRUSH и разными компонентами (мониторы, OSD, MDS). Не будем углубляться в архитектуру, достаточно понимать, что Ceph — это распределенный кластер хранилища, который упрощает масштабируемость, устраняет единую точку отказа без ущерба для производительности и предоставляет единое хранилище с доступом к объектам, блокам и файлам.
Естественно, Ceph адаптирован для облака. Деплоить кластер Ceph можно по-разному, например с помощью Ansible или в кластер Kubernetes через CSI и PVC.
Архитектура Ceph
Rook — это еще один интересный и популярный проект. Он объединяет Kubernetes с его вычислениями и Ceph с его хранилищами в один кластер.
Rook — это оркестратор облачных хранилищ, дополняющий Kubernetes. С ним пакуют Ceph в контейнеры и используют логику управления кластерами для надежной работы Ceph в Kubernetes. Rook автоматизирует деплой, начальную загрузку, настройку, масштабирование, перебалансировку, — в общем все, чем занимается админ кластера.
С Rook кластер Ceph можно деплоить из yaml, как Kubernetes. В этом файле админ в общих чертах описывает, что ему нужно в кластере. Rook запускает кластер и начинает активно мониторить. Это что-то вроде оператора или контролера — он следит, чтобы все требования из yaml выполнялись. Rook работает циклами синхронизации — видит состояние и принимает меры, если есть отклонения.
У него нет своего постоянного состояния и им не надо управлять. Вполне в духе Kubernetes.
Rook, объединяющий Ceph и Kubernetes, — это одно из самых популярных облачных решений для хранения: 4000 звезд на Github, 16,3 млн загрузок и больше сотни контрибьюторов.
Проект Rook уже приняли в CNCF, а недавно он попал в инкубатор.
Больше о Rook вам расскажет Бассам Табара в нашем эпизоде о хранилищах в Kubernetes.
Если в приложении есть проблема, нужно узнать требования и создать систему или взять нужные инструменты. Это относится и к хранилищу в облачной среде. И хотя проблема не из простых, инструментов и подходов у нас завались. Облачные технологии продолжают развиваться, и нас обязательно ждут новые решения.
Хранилища данных (Persistent Volumes) в Kubernetes
В предыдущих статьях мы установили и немного научились работать с кластером kubernetes. При этом я не рассмотрел вопрос с хранением данных, а вынес его в отдельную тему. Сегодня как раз хранение данных в кластере Kubernetes я и рассмотрю. Настраиваются эти хранилища в кластере с помощью абстракции под названием Persistent Volumes.
Цели статьи
Работа с дисками в Kubernetes
Работа с дисковыми томами в Kubernetes проходит по следующей схеме:
Что такое Persistent Volumes
Условно Persistent Volumes можно считать аналогом нод в самом кластере Kubernetes. Допустим, у вас есть несколько разных хранилищ. К примеру, одно быстрое на SSD, а другое медленное на HDD. Вы можете создать 2 Persistent Volumes в соответствии с этим, а затем выделять подам место в этих томах. Кубернетис поддерживает огромное количество подключаемых томов с помощью плагинов.
Вот список наиболее популярных:
Полный список можно посмотреть в документации.
Persistent Volume Claim
PersistentVolumeClaim (PVC) есть не что иное как запрос к Persistent Volumes на хранение от пользователя. Это аналог создания Pod на ноде. Поды могут запрашивать определенные ресурсы ноды, то же самое делает и PVC. Основные параметры запроса:
Типы доступа у PVC могут быть следующие:
Ограничение на тип доступа может налагаться типом самого хранилища. К примеру, хранилище RBD или iSCSI не поддерживают доступ в режиме ReadWriteMany.
Один PV может использоваться только одним PVС. К примеру, если у вас есть 3 PV по 50, 100 и 150 гб. Приходят 3 PVC каждый по 50 гб. Первому будет отдано PV на 50 гб, второму на 100 гб, третьему на 150 гб, несмотря на то, что второму и третьему было бы достаточно и 50 гб. Но если PV на 50 гб нет, то будет отдано на 100 или 150, так как они тоже удовлетворяют запросу. И больше никто с PV на 150 гб работать не сможет, несмотря на то, что там еще есть свободное место.
Из-за этого нюанса, нужно внимательно следить за доступными томами и запросами к ним. В основном это делается не вручную, а автоматически с помощью PV Provisioners. В момент запроса pvc через api кластера автоматически формируется запрос к storage provider. На основе этого запроса хранилище создает необходимый PV и он подключается к поду в соответствии с запросом.
Storage Classes
StorageClass позволяет описать классы хранения, которые предлагают хранилища. Например, они могут отличаться по скорости, по политикам бэкапа, либо какими-то еще произвольными политиками. Каждый StorageClass содержит поля provisioner, parameters и reclaimPolicy, которые используются, чтобы динамически создавать PersistentVolume.
Можно создать дефолтный StorageClass для тех PVC, которые его вообще не указывают. Так же storage class хранит параметры подключения к реальному хранилищу. PVC используют эти параметры для подключения хранилища к подам.
Работа с PV в кластере
Проверим, есть ли у нас какие-то PV в кластере.
Ничего нет. Попробуем создать и применить какой-нибудь PVC и проверим, что произойдет. Для примера создаем pvc.yaml следующего содержания.
Просим выделить нам 1 гб пространства с типом доступа ReadWriteMany. Применяем yaml.
Ждем немного и проверяем статус pvc.
Статус pending. Проверяем почему так.
Все понятно. Запрос находится в ожидании, так как у нас в кластере нет ни одного PV, который бы удовлетворял запросу. Давайте это исправим и добавим одно хранилище для примера на основе внешнего nfs сервера.
NFS хранилище в качестве Persistence Volume
Для простоты я взял в качестве хранилища PV nfs сервер. Для него не существует встроенного Provisioner, как к примеру, для Ceph. Возможно в будущем я рассмотрю более сложный пример с применением хранилища на основе ceph. Но перед этим надо будет написать статью про установку и работу с ceph.
Создаем yaml файл pv-nfs.yaml с описанием Persistence Volume на основе NFS.
Reclaim Policy
Все остальное и так понятно, описывать не буду. Добавляем описанный pv в кластер kubernetes.
Проверяем список pv и pvc
Мы просили в pvc только 1 Гб хранилища, но в pv было только хранилище с 10 Гб и оно было выдано. Как я и говорил раньше. Так что в случае ручного создания PV и PVC нужно самим следить за размером PV.
Подключаем хранилище к поду
Теперь подключим наш PVC в виде volume к какому-нибудь поду. Опишем его в конфиге pod-with-nfs.yaml
Затем проверяйте статус запущенного пода.
У меня он не стартовал. Я решил посмотреть из-за чего.
Я сразу понял в чем проблема. На ноде, где стартовал под, не были установлены утилиты для работы с nfs. В моем случае система была Centos и я их установил.
После этого в течении минуты pod запустился. Зайдем в его консоль и посмотрим, подмонтировалась ли nfs шара.
Как видите, все в порядке. Попробуем теперь что-то записать в шару. Снова заходим на под и создаем текстовый файл.
Теперь запустим еще один под и подключим ему этот же pvc. Для этого просто немного изменим предыдущий под, обозвав его pod-with-nfs2.
Запускаем под и заходим в него.
Все в порядке, файл на месте. С внешними хранилищем в Kubernetes закончили. Расскажу дальше, как можно работать с локальными дисками нод, если вы хотите их так же пустить в работу.
Создаем SC sc-local.yaml.
Создаем вручную PV pv-local-node-1.yaml, который будет располагаться на kub-node-1 в /mnt/local-storage. Эту директорию необходимо вручную создать на сервере.
Создаем PVC pvc-local.yaml для запроса сторейджа, который передадим поду.
И в завершении создадим тестовый POD pod-with-pvc-local.yaml для проверки работы local storage.
Применяем все вышеперечисленное в строго определенном порядке:
После этого посмотрите статус всех запущенных абстракций.
Проверим, что Local Persistent Volume правильно работает. Зайдем в под и создадим тестовый файл.
Теперь идем на сервер kub-node-1 и проверяем файл.
Все в порядке. Файл создан.
Если у вас возникли какие-то проблемы с POD, то в PVC будет ошибка:
И в это же время в поде:
Возникли ошибки из-за того, что в описании PV я ошибся в названии сервера, где будет доступен local storage. В итоге pod запускался, проверял pvc, а pvc смотрел на pv и видел, что адрес ноды с pv не соответствует имени ноды, где будет запущен pod. В итоге все висело в ожидании разрешения этих несоответствий.
С локальным хранилищем разобрались, можно использовать в работе.
Заключение
На наглядных примерах я показал, как можно работать с данными в кластере Kubernetes. Можно использовать как отказоустойчивые внешние хранилища для размещения постоянных данных. А можно сырые диски на серверах и использовать кластер для работы какой-то распределенной базы данных или сервиса, которые сами следят за количеством копий данных и распределяют их по нодам.
В последнем случае можно использовать самое обычное железо для кластера Kубернетиса, без рейд контроллеров и дублирования дорогих и быстрых SSD дисков. Необходимо только следить за количеством реплик приложения на нодах, чтобы их количество было достаточно для стабильной работы системы.
Два этих подхода можно комбинировать. Внешние хранилища для холодных данных и внутренние SSD диски для кэшей.
Другие статьи на тему Kubernetes:
На этом у меня все. Надеюсь мой цикл статей по k8s был для вас полезен.
Что такое Pods, Nodes, Containers и Clusters в Kubernetes
Kubernetes (k8s) очень стремительно становится новым стандартом для деплоймента и менеджмента вашего кода в клауде. Вместе с тем, сколько фич предоставляет k8s, для новичка наступает высокий порог входа в новую технологии.
Документация по k8s достаточно обширна и довольно сложно пройти ее всю. Именно по этому эта статья служит неким обобщением для того, чтобы разобрать основные модули kubernetes.
Hardware
Nodes
Если обсуждать про машину как «ноду», можем разбавить это слоем абстракции, мы можем представлять ее как некий набор CPU, RAM ресурсов которые можно использовать. Таким образом любая такая машина может заменить любую другую машину как k8s кластер.
Cluster
Хотя работа с отдельными нодами может быть полезной, это не путь kubernetes. В общем, вы должны думать о кластере в целом, а не беспокоиться о состоянии отдельных нодов.
В Kubernetes ноды объединяют свои ресурсы для формирования более мощной машины. Когда вы развертываете программы в кластере, он балансирует нагрузку по индивидуальным нодам для вас. Если какие-либо nodes добавляются или удаляются, кластер будет перемещаться по мере необходимости. Для программы или девелопера не должно быть важно, на каких машинах выполняется код в k8s. Можно сравнить такую систему с улием.
Persistent Volumes
Поскольку программы, работающие в вашем кластере, не гарантированно выполняются на определенной ноде, данные не могут быть сохранены в любом произвольном месте в файловой системе. Если программа пытается сохранить данные в файл, но затем перемещается на новую ноду, файл больше не будет там, где программа ожидает его. По этой причине традиционное локальное хранилище, связанное с каждой нодой, рассматривается как временный кэш для хранения программ, но нельзя ожидать, что любые данные, сохраненные локально, сохранятся.
Software
Контейнеры
Программы, работающие на Kubernetes, упаковуются в контейнеры. Контейнеры являются общепринятым стандартом, поэтому уже есть много готовых образов, которые можно развернуть в Kubernetes.
Контейнеризация позволяет вам создавать self-contained environments. Любая программа и все ее зависимости могут быть объединены в один файл и затем опубликованы в Интернете. Любой может загрузить контейнер и развернуть его в своей инфраструктуре с минимальными настройками. Создание контейнера может быть сделано и скриптом, позволяя строить CI/CD пайплайны.
Несколько программ могут быть развернуты в одном контейнере, но вы должны ограничить себя одним процессом на контейнер, если это вообще возможно. Лучше иметь много маленьких контейнеров, чем один большой. Если каждый контейнер имеет четкую направленность, обновления легче развертывать, а проблемы легче диагностировать.
В отличие от других систем, которые вы, возможно, использовали в прошлом, Kubernetes не запускает контейнеры напрямую; вместо этого он упаковывает один или несколько контейнеров в структуру более высокого уровня, называемую pod. Любые контейнеры в одном pod’e будут использовать одни и те же ресурсы и локальную сеть. Контейнеры могут легко связываться с другими контейнерами в том же pod’e, как если бы они находились на одной машине, сохраняя степень изоляции от других pod’ов.
Pod’ы используются как единица репликации в Kubernetes. Если ваше приложение становится слишком популярным, и один экземпляр модуля не может нести нагрузку, Kubernetes можно настроить для развертывания новых реплик вашего модуля в кластере по мере необходимости. Даже если не под большой нагрузкой, в продакшинев любое время можно запустить несколько копий модуля в любое время, чтобы обеспечить балансировку нагрузки и устойчивость к сбоям.
Pod’ы могут содержать несколько контейнеров, но вы должны ограничивать их количество, когда это возможно. Поскольку контейнеры масштабируются как единое целое, все контейнеры в паке должны масштабироваться вместе, независимо от их индивидуальных потребностей. Это приводит к потраченным впустую ресурсам и дорогому счету. Чтобы решить эту проблему, Pod’ы должны оставаться меньше на сколько это возможно, обычно вмещая только основной процесс и его тесно связанные вспомогательные контейнеры (эти вспомогательные контейнеры обычно называют Side-cars).
Deployments
Основная цель юзать подход с deployment состоит в том, чтобы настроить, сколько реплик pod’а должно работать одновременно. Когда развертывание добавляется в кластер, оно автоматически деплоит требуемое количество pod’ов и отслеживает их. Если pod умирает, deployment автоматически пересоздает его.
Используя deployment, вам не нужно иметь дело с подами вручную. Вы можете просто объявить желаемое состояние системы, и оно будет управляться автоматически.
Ingress
Используя описанные выше концепции, вы можете создать кластер нодов и запустить деплоймент подов в кластере. Однако есть еще одна проблема, которую необходимо решить: разрешить внешний трафик вашему приложению. По умолчанию Kubernetes обеспечивает изоляцию между модулями и внешним миром. Если вы хотите общаться с сервисом, работающим в pod, вам нужно открыть канал для связи. Это называется Ingress.
Есть несколько способов добавить ingress в ваш кластер. Наиболее распространенными способами являются добавление либо ingress controller, либо LoadBalancer. Описание различий и что лучше выбрать выходит за рамки этой статьи, но вы должны держать в голове что вам нужно разобратся с доступом к сервису, если вы хотите работать с k8s.