S3 — не самое быстрое хранилище и подходит не для всех задач. Но это отличный вариант, если нужно организовать надежное и масштабируемое пространство для данных большого объема. По этой причине S3 часто используют в качестве хранилища для приложений, развернутых в Kubernetes.
Привет, Хабр! Меня зовут Филипп, я DevOps-инженер в Selectel. В своей обзорной статье хочу разобрать, какие есть решения для работы с объектным хранилищем из K8s. Соберу тестовый стенд из кластера Managed Kubernetes и покажу, как установить и настроить нужные компоненты через Terraform. Начинаем!
Используйте навигацию, если не хотите читать текст полностью:
→ Знакомство с CSI: что это и когда использовать
→ Подготовка инфраструктуры
→ Обзор сtrox/csi-s3
→ Обзор yandex-cloud/k8s-csi-s3
→ Выводы и заключение
Знакомство с CSI: что это и когда использовать
Container Storage Interface (CSI) — это стандартный интерфейс, который позволяет Kubernetes взаимодействовать с различными системами хранения данных. Он унифицирует доступ к хранилищам данных и упрощает интеграцию различных систем хранения в кластере. Тем самым — обеспечивает гибкость и масштабируемость.
CSI полезен для администраторов и разработчиков, которые стремятся автоматизировать и упростить управление хранилищами данных в облачных и локальных средах. Это особенно актуально для крупных проектов с высокими требованиями к масштабируемости и надежности, где необходимо использовать разнообразные системы хранения без создания уникальных решений. CSI позволяет легко добавлять или менять хранилища данных по мере развития инфраструктуры.
Кроме того, CSI-драйверы развиваются независимо от ядра Kubernetes и работают в пользовательском пространстве. Это значит, что они не требуют изменений в коде K8s для добавления новых функций или исправлений. Такой подход снижает риски безопасности, так как уязвимости в CSI-драйверах напрямую не влияют на Kubernetes. А еще это позволяет быстро реагировать на изменения в требованиях к хранению данных, развивать и обновлять драйверы отдельно от основного кода K8s.
Из чего состоит CSI
CSI можно разделить на компоненты, которые разрабатывают Kubernetes и сторонние поставщики хранилищ. Подробнее архитектура описана в другой статье.
Компоненты от Kubernetes
- Driver registrar — регистрирует CSI-драйверы в kubelet.
- External provisioner — обрабатывает запросы на создание и удаление томов.
- External attacher — управляет монтированием и размонтированием томов.
Компоненты от сторонних поставщиков
- CSI Identity — проверяет и возвращает информацию о плагине.
- CSI Controller — управляет жизненным циклом томов.
- CSI Node — управляет монтированием и размонтированием томов на узлах.
Но как работает CSI на практике? Подготовим инфраструктуру и протестируем подключение к S3 из Kubernetes.
Подготовка инфраструктуры
До настройки и использования CSI необходимо подготовить инфраструктуру, которая будет включать кластер Kubernetes и S3-хранилище. В качестве основного IaC-инструмента я выбрал Terraform. Именно с помощью него буду создавать инфраструктуру и устанавливать Helm-чарты в кластер.
Первым делом нужно создать сервисного пользователя в панели управления Selectel. И установить роли «Администратор аккаунта» и «Администратор пользователей». О том, как это сделать, мы подробно рассказали в документации. Этот этап нужен для инициализации Terraform-провайдера Selectel, в который далее передадим логин и пароль.
Чтобы не писать самостоятельно большие портянки с кодом Terraform, воспользуемся кодом из публичного репозитория GitHub. Клонируем его и вносим некоторые коррективы. Далее пошагово опишу, что нужно будет сделать.
- Клонируйте репозиторий к себе и перейдите в созданную папку:
#: git clone git@github.com:selectel/selectel-infra-examples.git && cd selectel-infra-examples
- В main.tf закомментируйте все модули и ресурсы, кроме project-with-user, mks и s3-credentials.
- Если нужно, измените имя проекта, пользователя, регион и требуемую конфигурацию для системной группы нод.
- В качестве версии Managed Kubernetes укажите доступную версию. По завершении должен получиться главный файл main.tf следущего вида:
# Создаем проект с пользователем module "project-with-user" { source = "./modules/os_project_with_user" os_project_name = "csi_test_project" # Имя проекта os_username = "csi_test_project_user" # Имя для нового проектного сервисного пользователя } # Создаем S3-ключ для пользователя module "s3-creds" { source = "./modules/s3/s3-credentials" os_user_id = module.project-with-user.user_id os_project_id = module.project-with-user.project_id credentials_name = "csi-s3-creds" # Важный блок, без него данный модуль пойдет вперед создания # проекта и пользователя и упадет с ошибкой! depends_on = [ module.project-with-user ] } # Создаем MKs module "mks" { source = "./modules/mks/k8s-cluster-standalone" cluster_name = "csi-test-cluster" # Имя кластера kube_version = "1.28.9" # Версия кластера os_availability_zone = "ru-9a" # Регион и зона os_region = "ru-9" # Регион os_project_id = module.project-with-user.project_id # Для теста оставьте как есть nodegroups = 1 ng_nodes_count = [2] ng_cpus = [4] ng_ram_mb = [8192] ng_volume_gb = [100] ng_volume_type = ["fast"] ng_labels = [{ "role" : "system" }] # Для того чтобы отключить gpu группы нод, # необходимо передать gpu_nodegroups = 0 gpu_nodegroups = 0 gpu_ng_nodes_count = [0] gpu_ng_volume_gb = [100] gpu_ng_volume_type = ["fast"] gpu_ng_labels = [{ "role" : "gpu" }] gpu_ng_flavor = ["3031"] nat_subnet_cidr = "10.222.0.0/16" enable_autorepair = false network_id = "" # Важный блок, без него данный модуль пойдет вперед создания # проекта и пользователя и упадет с ошибкой! depends_on = [ module.project-with-user ] }
- Немного модифицируем код Terraform, чтобы мы могли устанавливать компоненты (по сути, Helm-чарты), используя Terraform-провайдер Helm. Добавим в файл providers.tf инициализацию helm-tf-провайдера:
provider "helm" { kubernetes { host = module.mks.kube_config.server client_certificate = base64decode(module.mks.kube_config.client_cert) client_key = base64decode(module.mks.kube_config.client_key) cluster_ca_certificate = base64decode(module.mks.kube_config.cluster_ca_cert) } }
На мой взгляд это очень удобно для тестирования, ведь мы можем описывать все в одном месте в коде Terraform.
- Далее проверим конфигурацию — для этого выполним пару Terraform-команд. Инициализируем конфигурацию и проверим, какие изменения Terraform планирует внести в инфраструктуру:
#: terraform init #: terraform plan
В конце вывода команды terraform plan вы должны увидеть, что будет создано n ресурсов:
... Plan: <n кол-во> to add, 0 to change, 0 to destroy.
- Теперь применим конфигурацию и подтвердим изменения:
#: terraform apply
В результате Terraform развернет все необходимое для тестового стенда: проект, сервисного пользователя, S3-контейнер, S3-ключ, кластер и ноды MKs и сеть для MKs.
Для выполнения команды kubectl и, например, доступа к кластеру через Lens, понадобится kube_config файл, который можно получать через панель управления. По готовности можно перейти дальше и начать уже знакомиться с CSI-драйверами для S3. Как и отмечал ранее, рекомендую устанавливать чарты с помощью terraform provider helm — так вы получите описание проекта в одном месте. Но никто не запрещает устанавливать Helm-чарты через сам Helm.
Обзор сtrox/csi-s3
Ctrox/csi-s3 — это CSI-драйвер, который позволяет использовать S3-совместимые хранилища в кластерах Kubernetes. Основная идея заключается в обеспечении возможности монтирования S3-контейнеров как файловых систем внутри подов Kubernetes. Это делает хранилища доступными для приложений внутри кластера — без внесения изменений в код.
Особенности
1. Инструмент поддерживает различные S3-совместимые хранилища.
2. Ctrox/csi-s3 позволяет монтировать S3-контейнеры в виде файловой системы. Это хорошо, если нужно обеспечить прямой доступ к данным в хранилище с подов в Kubernetes, например, для обработки или анализа данных в реальном времени. Без предварительного скачивания и локального хранения этих данных.
3. Поддерживает «маунтеры»: rclone, s3fs, goofys и s3backer. Вы можете выбрать наиболее подходящий инструмент.
- rclone — универсальный инструмент для синхронизации и монтирования различных облачных хранилищ.
- s3fs — позволяет монтировать S3-хранилища как файловую систему, используя FUSE.
- goofys — оптимизирован для высокопроизводительного чтения данных из S3. Далее будем тестировать этот вариант.
- s3backer (experimental*) — позволяет использовать S3 как блочное устройство.
4. Ctrox/csi-s3 редко обновляется. Крайние апдейты были около двух лет назад.
5. Нет официального Helm-чарта, но можно использовать компонент от Cloudve.
Установка
1. Добавим ресурс helm_release и опишем переменную values. Достаточно в main.tf вписать следующий код Terraform:
resource "helm_release" "ctrox-csi-s3" { name = "ctrox-csi-s3" repository = "<https://github.com/CloudVE/helm-charts/raw/master>" chart = "ctrox-csi-s3" version = "0.1.0" atomic = true wait = true wait_for_jobs = true namespace = "ctrox-csi-s3" create_namespace = true values = [ <<-EOT attacher: image: repository: "quay.io/k8scsi/csi-attacher" pullPolicy: IfNotPresent tag: v3.1.0 # По умолчанию ставится v2.2.0 secret: create: true name: "csi-s3-secret" # Имя секрета accessKey: ${module.s3-creds.s3_credentials_access_key} secretKey: ${module.s3-creds.s3_credentials_secret_key} endpoint: "https://s3.ru-1.storage.selcloud.ru" storageClass: mounter: goofys # Выбираем маунтер из доступных rclone, s3fs, goofys. EOT ] depends_on = [ module.mks ] }
Важно: данные для подключения к S3 можно получить из вывода модуля s3-creds. Но помните, что они хранятся в стейте и никак не защищены.
2. Далее применим код Terraform и дождемся, пока все запустится:
#: terraform apply
kubectl --namespace ctrox-csi-s3 get pods -w -o wide
3. Также понадобится подправить cluster-role с именем external-attacher-runner и добавить в него api-group. Выполним команду kubectl:
kubectl patch clusterrole external-attacher-runner --type='json' -p='[{"op": "add", "path": "/rules/-", "value": {"apiGroups": ["storage.k8s.io"], "resources": ["volumeattachments/status"], "verbs": ["patch"]}}]'
Тестирование
Для тестирования будем использовать утилиту fio в поде. К контейнеру с ней смонтируем PVC по пути /mnt.
Вот пример создания PVC и пода с запуском fio:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: csi-s3-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: csi-s3 --- apiVersion: v1 kind: Pod metadata: name: csi-s3-test namespace: default spec: containers: - name: csi-s3-test-container image: xridge/fio command: ["/bin/sh"] args: ["-c", "fio --name=write_test --filename=/mnt/test-file --size=5G --time_based --runtime=60 --rw=write --bs=4k --ioengine=sync --group_reporting && fio --name=read_test --filename=/mnt/test-file --size=5G --time_based --runtime=60 --rw=read --bs=4k --ioengine=sync --group_reporting"] volumeMounts: - mountPath: /mnt name: storage volumes: - name: storage persistentVolumeClaim: claimName: csi-s3-pvc readOnly: false
Результаты тестирования можно посмотреть в логах пода:
kubectl logs csi-s3-test
Результаты
Преобразуем вывод команды fio в таблицу, в которой укажем следующие параметры.
- Пропускная способность (BW, Bandwidth) — скорость передачи данных, измеряемая в MiB/s (мебибайтах в секунду) или MB/s (мегабайтах в секунду). Указывает, сколько данных можно передать за определенный промежуток времени.
- Средняя задержка (clat) — среднее время задержки (latency) для выполнения операций ввода-вывода, измеряемое в микросекундах (мкс) или наносекундах (нс). Чем ниже значение, тем быстрее система обрабатывает запросы.
- Пиковая задержка (max clat) — максимальное время задержки, зарегистрированное во время теста. Пиковое значение показывает наихудший случай времени ожидания для операции ввода-вывода.
- BS-size (размер блока) — размер блока данных, используемый в тесте ввода-вывода. Например, 4k (килобайты) или 2M (мегабайты). Различные размеры блоков могут влиять на производительность системы в зависимости от конфигурации и типов рабочих нагрузок.
# | Операция | Пропускная способность (BW) | Средняя задержка (clat) | Пиковая задержка (max clat) | BS-size |
ctrox/csi-s3 (Goofys) | Чтение | 355 MiB/s (372 MB/s) | 10,24 мкс | 300,555 мс | 4k |
ctrox/csi-s3 (Goofys) | Запись | 44,1 MiB/s (46,3 MB/s) | 87,78 мкс | 121,541 мс | 4k |
Первое тестирование ctrox/csi-s3 с маунтером Goofys показало хорошие результаты для чтения. CSI достигла скорости 355 MiB/s (372 MB/s) и 10,24 мкс avg clat. Однако запись оказалась медленнее: 44,1 MiB/s (46,3 MB/s) и 87,78 мкс avg clat.
Обзор yandex-cloud/k8s-csi-s3
Это решение от Яндекс, которое является форком ctrox/csi-s3. В него добавлена поддержка маунтера GeeseFS, основанного на goofys.
Особенности
GeeseFS — высокопроизводительный файловый монтировщик через FUSE для S3-совместимых хранилищ. И все особенности завязаны на нем.
- Производительность. GeeseGS быстрее традиционных монтировщиков вроде s3fs. Все это — благодаря оптимизированному коду, который минимизирует количество операций чтения и записи. Подробнее о тестах производительности читайте в репозитории на GitHub.
- Частичное изменение и дозапись объектов. Вы можете хранить в контейнере данные, например логи, в виде единого файла, периодически дописывая информацию. Также упрощается работа с большими файлами.
Остальные особенности хорошо описаны в документации.
Установка
Важно: перед установкой необходимо удалить все, что связано с ctrox.
1. Клонируем репозиторий и при описании helm_release укажем локальное расположение Helm-чарта:
#: git clone https://github.com/yandex-cloud/k8s-csi-s3.git yandex-csi-s3
resource "helm_release" "yandex-csi-s3" { name = "yandex-csi-s3" chart = "./yandex-csi-s3/deploy/helm/csi-s3" atomic = true wait = true wait_for_jobs = true namespace = "yandex-csi-s3" create_namespace = true values = [ <<-EOT secret: accessKey: "${module.s3-creds.s3_credentials_access_key}" secretKey: "${module.s3-creds.s3_credentials_secret_key}" endpoint: "https://s3.ru-1.storage.selcloud.ru" region: "ru-1" EOT ] depends_on = [ module.mks ] }
2. Применим код Terraform и проверим, что поды успешно запустились:
kubectl --namespace ctrox-csi-s3 get pods -w -o wide
Если все поды успешно запустились, можем переходить к тестированию.
Тестирование
Выполним тест с запуском пода c fio. Применим манифест:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: csi-s3-pvc namespace: default spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: csi-s3 --- apiVersion: v1 kind: Pod metadata: name: csi-s3-test namespace: default spec: containers: - name: csi-s3-test-container image: xridge/fio command: ["/bin/sh"] args: ["-c", "fio --name=write_test --filename=/mnt/test-file --size=5G --time_based --runtime=60 --rw=write --bs=4k --ioengine=sync --group_reporting && fio --name=read_test --filename=/mnt/test-file --size=5G --time_based --runtime=60 --rw=read --bs=4k --ioengine=sync --group_reporting"] volumeMounts: - mountPath: /mnt name: storage volumes: - name: storage persistentVolumeClaim: claimName: csi-s3-pvc readOnly: false
Вытащим из логов контейнера необходимые значения и зафиксируем их в таблице:
kubectl logs csi-s3-test
# | Операция | Пропускная способность (BW) | Средняя задержка (clat) | Пиковая задержка (max clat) | BS-size |
yandex-csi-s3 (GeeseFS) | Чтение | 446 MiB/s (468 MB/s) | 8,04 мкс | 16,91 мс | 4k |
yandex-csi-s3 (GeeseFS) | Запись | 24,7 MiB/s (25,9 MB/s) | 157,36 мкс | 8,982 мс | 4k |
GeeseFs показал себя лучше в чтении, где скорость достигла 446 MiB/s (468 MB/s) и 8,04 мкс avg clat. Однако запись оказалась в 2 раза медленней: 24,7 MiB/s (25,9 MB/s) и 157,36 мкс avg clat.
Выводы и заключение
Давайте объединим результаты операций чтения/записи маунтерами Goofys и GeeseFS и сделаем общие выводы.
# | Операция | Пропускная способность (BW) | Средняя задержка (clat) | Пиковая задержка (max clat) | BS-size |
ctrox/csi-s3 (Goofys) | Чтение | 355 MiB/s (372 MB/s) | 10,24 мкс | 300,555 мс | 4k |
ctrox/csi-s3 (Goofys) | Запись | 44,1 MiB/s (46.3 MB/s) | 87,78 мкс | 121,541 мс | 4k |
yandex-csi-s3 (GeeseFS) | Чтение | 446 MiB/s (468 MB/s) | 8,04 мкс | 16,91 мс | 4k |
yandex-csi-s3 (GeeseFS) | Запись | 24.7 MiB/s (25.9 MB/s) | 157,36 мкс | 8,982 мс | 4k |
Общий анализ
Пропускная способность (BW)
- Чтение. GeeseFS показал лучшую пропускную способность по сравнению с Goofys. Показатель GeeseFS достиг 446 MiB/s (468 MB/s), в то время как для Goofys он же составляет 355 MiB/s (372 MB/s).
- Запись. Снова GeeseFS показал лучшие результаты с пропускной способностью: 24,7 MiB/s (25.9 MB/s) против 44,1 MiB/s (46,3 MB/s). Это указывает на лучшую оптимизацию чтения у GeeseFS.
Средняя задержка (clat)
- Чтение. GeeseFS показал более низкую среднюю задержку (8,04 мкс) по сравнению с Goofys (10,24 мкс), что свидетельствует о более быстрой обработке запросов чтения.
- Запись. Goofys показал лучшую производительность с задержкой 87,78 мкс против 157,36 мкс у GeeseFS. Это может быть связано с оптимизацией записи у Goofys.
Пиковая задержка (max clat):
демонстрировал более стабильную производительность с пиковым значением 16,91 мс против 300,555 мс у Goofys.Запись. В этом случае GeeseFS показал лучшие результаты. Пиковым значение составило 8,982 мс по сравнению с 121,541 мс у Goofys.
Заключение
Благодаря CSI-реализации в kubernetes и маунтеров мы можем легко использовать S3-контейнер для различных целей. Например, для хранения резервных копий, больших данных или любых других артефактов, с которым работает ваше приложение.
Что думаете насчет рассмотренных инструментов? Может, использовали их на практике? Поделитесь своим мнением в комментариях!
Возможно, эти тексты тоже вас заинтересуют:
→ Как тестировать UX-сценарии в сложных продуктах? Метод «домашки» для пользователей
→ СХД в реестре Минпромторга, новые AMD Ryzen и другое железо июня
→ Всего два месяца — и новый релиз: Linux 6.10 уже готов
ссылка на оригинал статьи https://habr.com/ru/articles/832768/
Добавить комментарий