- PVSM.RU - https://www.pvsm.ru -
Как DevOps-инженер я часто сталкиваюсь с необходимостью глубокого понимания тонких аспектов Kubernetes. Одним из таких ключевых элементов является управление хранилищем данных. Хотя этот элемент иногда остаётся в тени других задач, его важность для успешного развёртывания и поддержки приложений велика.
Накопленный мною опыт в этой области стал основой для этой статьи.
Я сфокусируюсь на трёх ключевых элементах управления хранилищем в Kubernetes:
Эти компоненты играют важную роль не только в выборе подходящих типов хранилищ, но и в их эффективном управлении, особенно в сценариях высокой нагрузки.
Так, при развёртывании масштабируемого веб-приложения, которое обрабатывает большие объёмы пользовательских данных и транзакций, хорошо настроенное управление хранилищем заметно повышает производительность и доступность данных. И тогда при увеличении нагрузки на приложение доступ к данным остаётся быстрым и надёжным, задержки уменьшаются, общее взаимодействие пользователя с приложением улучшается.
Например, у нас была задача обеспечить надёжное и масштабируемое хранение данных в веб-приложении для управления клиентскими заказами. Мы настроили в Kubernetes Storage Class на основе SSD для базы данных (что не является хорошей практикой): это помогло обеспечить быстрый доступ и обработку транзакций. А для логов и нечасто применяемых данных использовали отдельный Storage Class с HDD, и это позволило снизить затраты.
А главное, Storage в Kubernetes — это такая штука, которую ты сделал и забыл, дальше оно там само работает.
Рассказываю детально.
Подсистемы PV представляют собой абстракции реальных хранилищ данных, которые размещаются на физических или виртуальных дисках. PV предоставляют интерфейс для управления жизненным циклом данных независимо от того, на каком уровне инфраструктуры они фактически хранятся (например, NFS, iSCSI, cloudstorage и т. д.).
Когда вы работаете с подами в Kubernetes, одним из первых вопросов, который приходит в голову, является: «Куда деваются мои данные после завершения пода?»
Именно здесь на сцену выходят PV. Они как бы говорят вашим данным: «Не волнуйтесь, я сохраню вас». Это не просто хранилище — это хранилище, спроектированное так, чтобы выжить в условиях постоянных изменений, характерных для кластеров Kubernetes.
Создание PV может быть статическим или динамическим, и это одна из его наиболее привлекательных особенностей. В статическом режиме администратор заранее создаёт ряд PV с различными характеристиками. Это как заранее приготовленный шкаф с разными ящиками для хранения. В динамическом режиме PV создаётся «на лету» на основе требований, указанных в PersistentVolumeClaim (PVC). Это как если бы у вас был магический шкаф, который сам создаёт нужный вам ящик, когда вы его запросите.
Один из наиболее интересных аспектов PV — это его жизненный цикл и политики восстановления. Когда PVC удаляется, что происходит с PV? Он может быть сохранён для будущего использования, может быть полностью удалён или даже «рециклирован» для очистки данных. Это даёт администраторам гибкость в управлении ресурсами и обеспечивает высокую степень контроля над данными.
Affinity узлов в PV позволяет вам уточнить, на каких узлах этот конкретный PV может быть использован. Это особенно полезно в больших и разнородных кластерах, где у разных узлов могут быть разные характеристики хранилища. С помощью аффинности узлов вы можете гарантировать, что ваш PV будет размещён там, где это наиболее эффективно с точки зрения производительности и надёжности.

На этой схеме показан процесс работы с PV в Kubernetes:
YAML для Persistent Volume:
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-local-pv
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: my-local-sc
hostPath:
path: "/mnt/local-storage"
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: "kubernetes.io/hostname"
operator: In
values:
- node1
- node2
В этом примере:
PersistentVolumes в Kubernetes — не просто механизм хранения данных. Это продуманный и гибкий инструмент, который позволяет администраторам и разработчикам сосредоточиться на своей основной работе, не беспокоясь о данных. Они обеспечивают уровень абстракции и управления, который делает работу с хранилищем не только возможной, но и эффективной.
PersistentVolumeClaims (PVC) — это как заявки на аренду недвижимости в мире Kubernetes.
Если PersistentVolumes (PV) являются зданиями, готовыми к заселению, то PVC — это ваша анкета, в которой вы указываете, какие условия вам нужны: количество комнат, наличие балкона и так далее.
PVC — это запрос на выделение хранилища из общего пула PV. Когда приложение в кластере нуждается в постоянном хранилище, оно не обращается напрямую к PV. Вместо этого оно создаёт PVC, в котором описывает свои требования к хранилищу. Это абстракция, которая позволяет разработчикам фокусироваться на коде, не задумываясь о деталях инфраструктуры.
Как только PVC создан, Kubernetes начинает поиск подходящего PV. Этот процесс называется «связыванием». Если подходящий PV найден, то он «связывается» с PVC, и приложение может начать использовать этот том для хранения данных. Если подходящего PV нет, то PVC остаётся в состоянии Pending до тех пор, пока не появится соответствующий PV или пока не будет выполнено динамическое выделение хранилища.
Принципы работы PVC:
В Kubernetes PersistentVolumeClaim (PVC) предоставляет различные режимы доступа к хранилищу. Эти режимы определяют, как поды могут взаимодействовать с соответствующим
PersistentVolume (PV). Вот подробное описание каждого режима:
Представляет собой способ описания классов хранилища, которые можно использовать для динамического выделения PersistentVolumes (PV) при создании PersistentVolumeClaims (PVC).
Storage Class определяет, какой провайдер хранилища будет использоваться, какие параметры будут применены и другие специфические для провайдера настройки.
Селекторы в PVC позволяют вам фильтровать и выбирать PersistentVolumes (PV) на основе меток. Это предоставляет дополнительный уровень контроля при привязке PVC к PV, позволяя вам удостовериться, что выбранный том соответствует определённым требованиям или политикам. Селекторы в PVC используют метки, которые были присвоены PV. Когда PVC создаётся с определённым селектором, он будет привязан только к тем PV, которые соответствуют меткам селектора.
Определяет, что произойдёт с PersistentVolume (PV) после удаления соответствующего PersistentVolumeClaim (PVC). Это важный аспект управления жизненным циклом хранилища в Kubernetes.
Виды политик восстановления:
1. Retain (сохранить).
2. Delete (удалить).
3. Recycle (переработать).
Вот диаграмма, которая поможет понять ключевые компоненты и взаимодействия, связанные с PersistentVolumeClaim:

На диаграмме:
Пример YAML для PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
Использование PVC в Pod:
apiVersion: v1
kind: Pod
metadata:
name: "myapp"
namespace: default
labels:
app: "myapp"
spec:
volumes:
- name: my-storage
persistentVolumeClaim:
claimName: my-pvc
containers:
- name: myapp
image: "debian-slim:latest"
volumeMounts:
- name: my-storage
mountPath: "/data"
Управление жизненным циклом:
Это нечто вроде каталога аренды жилья, где каждый класс представляет собой набор характеристик и условий для хранилища. Это ключевой элемент, который управляет динамическим выделением хранилища в кластере. Этот механизм описывает различные классы хранилища, которые предлагаются в кластере. Каждый класс имеет свои уникальные характеристики, такие, как тип диска, скорость IOPS и параметры шифрования.
SC определяет, как должны быть созданы PersistentVolumes (PV) при динамическом выделении хранилища на основе PersistentVolumeClaims (PVC). Возможность динамического выделения, когда приложение создаёт PVC и указывает в нём Storage Class, Kubernetes автоматически создаёт PV с нужными характеристиками.
Ключевые аспекты Storage Class:
Пример YAML для Storage Class:
apiVersion: v1
kind: StorageClass
metadata:
name: my-local-sc
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
В этом примере:
Storage Class особенно полезен в многофункциональных и разнородных кластерах. Например, для базы данных вы можете создать класс с высокопроизводительным SSD, а для архива данных — класс с более дешёвым и медленным хранилищем. Это позволяет оптимизировать затраты и производительность.
Вот диаграмма, которая поможет вам понять ключевые компоненты и взаимодействия, связанные со Storage Class:

На диаграмме:
В целом Storage Class в Kubernetes является инструментом, который добавляет дополнительный уровень абстракции и гибкости при работе с хранилищем данных. Он не только упрощает задачи управления, но и открывает новые возможности для оптимизации ресурсов и повышения эффективности. Эта функциональность становится особенно ценной в сложных и динамичных средах, где требования к хранилищу могут быстро меняться.
Описывает определённые оптимизации, которые могут быть внедрены в системе для ускорения процесса привязки между PersistentVolumeClaims (PVC) и PersistentVolumes (PV). Эти оптимизации обычно заключаются в том, чтобы избежать повторных проверок возможности привязки, когда такая информация уже известна или кэширована.
Система привязки в Kubernetes достаточно сложна, и она включает в себя несколько этапов:
В больших и динамичных кластерах этот процесс может быть дорогостоящим в плане производительности и задержек. Вот тут и могут быть применены различные методы кэширования и оптимизации:
1. Кэширование списка доступных PV: система может кэшировать список PV, которые еще не привязаны, чтобы ускорить поиск.
2. Кэширование атрибутов PV и PVC: атрибуты, такие, как `storageClassName`, `accessModes` и `requests`, которые часто используются при привязке, могут быть кэшированы.
3. Кэширование результатов проверок: результаты выполненных проверок (например, соответствие политикам безопасности) могут быть кэшированы для последующего использования. Тем не менее важно учесть, что кэширование может привести к некоторым проблемам:
Для примера давайте предположим, что у вас есть RESTAPI, который управляет привязкой между PV и PVC. Основная идея заключается в том, чтобы использовать кэширование для ускорения этого процесса.
from flask import Flask, request, jsonify
from collections import deque
app = Flask(__name__)
# Кэш для хранения свободных PV
free_pv_cache = deque(maxlen=100)
# Кэш для хранения атрибутов PVC
pvc_attribute_cache = {}
# Список всех доступных PV (обычно это будет храниться в базе данных)
all_pv_list = [
{'name': 'pv1', 'storageClass': 'fast', 'size': 100},
{'name': 'pv2', 'storageClass': 'slow', 'size': 200},
]
@app.route('/bind', methods=['POST'])
def bind():
pvc_data = request.json
pvc_name = pvc_data.get('name')
# Обновление кэша атрибутов PVC
pvc_attribute_cache[pvc_name] = pvc_data.get('attributes', {})
# Использование кэша для ускорения поиска
for pv in list(free_pv_cache):
if is_suitable(pv, pvc_data):
free_pv_cache.remove(pv)
return jsonify({"status": "bound", "pv": pv}), 200
# Если подходящий PV не найден в кэше, выполнить обычный поиск
for pv in all_pv_list:
if is_suitable(pv, pvc_data):
return jsonify({"status": "bound", "pv": pv}), 200
return jsonify({"status": "not found"}), 404
@app.route('/add_pv', methods=['POST'])
def add_pv():
pv_data = request.json
free_pv_cache.append(pv_data)
return jsonify({"status": "added", "pv": pv_data}), 201
def is_suitable(pv, pvc):
# Использование кэшированных атрибутов PVC для ускорения проверки
pvc_attributes = pvc_attribute_cache.get(pvc.get('name'), {})
# Пример проверки совместимости
if pv.get('storageClass') != pvc_attributes.get('storageClass'):
return False
if pv.get('size') < pvc_attributes.get('size', 0):
return False
return True
if __name__ == '__main__':
app.run(debug=True)
Компоненты программы:
1. Кэш свободных PV (`free_pv_cache`): это кэш, который хранит информацию о свободных (непривязанных) PV. Он реализован как очередь с ограниченным размером, чтобы избежать переполнения.
2. Кэш атрибутов PVC (`pvc_attribute_cache`): этот кэш хранит атрибуты PVC, которые часто используются при привязке, такие, как `storageClassName`, `accessModes` и `requests`.
3. API-методы:
4. Функция `is_suitable`: эта функция проверяет, подходит ли данный PV для данного PVC на основе их атрибутов.
Принцип работы программы:
Ввод-вывод (I/O) — одна из ключевых характеристик производительности в любой системе хранения данных. В контексте Kubernetes и PersistentVolumes (PV) I/O-операции играют важную роль в общей эффективности и отзывчивости приложений. Здесь стоит рассмотреть несколько ключевых аспектов:
Типы I/O-операций:
Влияние на производительность:
Оптимизация:
Проблемы и решения:
Это типы PersistentVolumes (PV), которые позволяют нескольким подам одновременно подключаться к одному и тому же тому хранения данных. Это полезно в случаях, когда несколько инстансов приложения должно иметь доступ к общим данным. Такие сценарии часто встречаются в распределённых базах данных, системах кэширования и других приложениях, которые требуют высокой доступности и отказоустойчивости.
Технические особенности:
Проблемы и решения:
Допустим, что у нас есть приложение для обработки изображений, которое использует общий том для хранения изображений. Этот том должен быть доступен для нескольких подов, которые обрабатывают изображения параллельно.
Давайте рассмотрим схему:

MultiAttachVolume — это класс, представляющий Multi-Attach Volume. У него есть следующие атрибуты:
1. ReadWriteMany (RWX) Access Mode: режим доступа, который позволяет нескольким подам читать и писать на одном томе одновременно.
2. Storage Backend: система хранения данных, которая поддерживает множественное подключение (например, NFS, Ceph).
3. Coordination: механизмы координации для управления I/O-операциями между различными подами.
4. Pod1, Pod2, Pod3: это классы, представляющие различные поды, которые подключены к Multi-AttachVolume. У каждого из них есть атрибут:
А вот пример YAML-конфигурации:
apiVersion: v1
kind: PersistentVolume
metadata:
name: image-storage
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
path: /mnt/data
server: nfs-server.example.com
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: image-storage-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: image-processor-1
spec:
volumes:
- name: image-storage
persistentVolumeClaim:
claimName: image-storage-pvc
containers:
- name: image-processor
image: image-processor:latest
volumeMounts:
- mountPath: /app/images
name: image-storage
---
apiVersion: v1
kind: Pod
metadata:
name: image-processor-2
spec:
volumes:
-name: image-storage
persistentVolumeClaim:
claimName: image-storage-pvc
containers:
-name: image-processor
image: image-processor:latest
volumeMounts:
-mountPath: /app/images
name: image-storage
PersistentVolume (PV): создаём PV с режимом доступа ReadWriteMany и указываем NFS-сервер.
PersistentVolumeClaim (PVC): создаём PVC, который будет использовать этот PV.
Pods: создаём два пода (image-processor-1 и image-processor-2), которые будут использовать этот общий том для чтения и записи изображений.
Теперь оба пода могут читать и записывать данные в общий том, что делает этот пример интересным и легко читаемым.
Это концепция, которая описывает тенденцию больших наборов данных «притягивать» к себе различные приложения, сервисы и даже другие данные. Этот термин был введён Дэвидом Маккрори (Dave McCrory), и он описывает феномен, с которым сталкиваются многие организации в эпоху больших данных и облачных вычислений.
Технические аспекты:
Проблемы и решения:
Рассмотрим пример Data Gravity: «Большая Библиотека». Представьте, что у нас есть большая библиотека, которая хранит огромное количество книг, журналов и статей.
Эта библиотека привлекает различные группы людей:

Проблемы и решения:
Таким образом, «Большая Библиотека» становится центром притяжения не только для книг, но и для различных групп людей, которые взаимодействуют с этими данными.
Это ситуация, при которой разные клиенты или компоненты системы могут видеть различные версии одних и тех же данных в разное время. Это может происходить из-за различных факторов, включая кэширование, асинхронную репликацию, недостаточную синхронизацию и другие.
Технические аспекты:
Проблемы и решения:
Это процесс оценки и определения технических ресурсов (например, вычислительных мощностей, хранилища, сетевых ресурсов), необходимых для обеспечения удовлетворительного уровня производительности и доступности приложения или системы.
Технические аспекты:
Это процесс первоначального «прогрева» блочных хранилищ или файловых систем перед их активным использованием. Этот процесс особенно актуален в облачных средах, где динамические ресурсы могут быть не полностью «горячими» прямо изначально.
Технические аспекты:
Это механизм, позволяющий управлять и оптимизировать производительность и доступность хранилища данных. Это особенно актуально в средах с общим использованием ресурсов, где одно приложение или процесс может негативно влиять на другие.
Технические аспекты:
Это искажение или потеря данных, которые могут произойти из-за различных причин, таких, как аппаратные сбои, программные ошибки или человеческие факторы. Подобные проблемы могут проявляться на разных уровнях — от отдельных файлов до целых баз данных или хранилищ.
Технические аспекты:
Иногда планировщик Kubernetes может сделать неоптимальные решения при размещении подов, которые зависят от PV, особенно если различные PV имеют разные характеристики производительности или стоимости.
Технические аспекты:
В начале пути управление хранилищами данных в Kubernetes может казаться сложным.
Однако, освоив ключевые элементы, такие, как PersistentVolume, PersistentVolumeClaim и Storage Class, и уловив их взаимосвязь, вы обнаружите, что задачи становятся более простыми.
Я надеюсь, что эта статья не только поможет вам разобраться с основными принципами работы с хранилищами в Kubernetes, но и повысит эффективность и понятность вашей работы с этой платформой.
Автор: Дмитрий Колесников
Источник [1]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/kubernetes/388867
Ссылки в тексте:
[1] Источник: https://habr.com/ru/companies/T1Holding/articles/781368/?utm_source=habrahabr&utm_medium=rss&utm_campaign=781368
Нажмите здесь для печати.