Как использовать S3-хранилище в Kubernetes: руководство с примерами

от автора

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. Клонируем его и вносим некоторые коррективы. Далее пошагово опишу, что нужно будет сделать.

  1. Клонируйте репозиторий к себе и перейдите в созданную папку:

#: git clone git@github.com:selectel/selectel-infra-examples.git && cd selectel-infra-examples 

  1. В main.tf закомментируйте все модули и ресурсы, кроме project-with-user, mks и s3-credentials.
  2. Если нужно, измените имя проекта, пользователя, регион и требуемую конфигурацию для системной группы нод.
  3. В качестве версии 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   ] } 

  1. Немного модифицируем код 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.

  1. Далее проверим конфигурацию — для этого выполним пару Terraform-команд. Инициализируем конфигурацию и проверим, какие изменения Terraform планирует внести в инфраструктуру:

#: terraform init #: terraform plan 

В конце вывода команды terraform plan вы должны увидеть, что будет создано n ресурсов:

... Plan: <n кол-во> to add, 0 to change, 0 to destroy. 

  1. Теперь применим конфигурацию и подтвердим изменения:

#: 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. Это делает хранилища доступными для приложений внутри кластера — без внесения изменений в код.

GitHub-репозиторий →

Неофициальный Helm-чарт →

Особенности

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.

GitHub-репозиторий →

Официальный Helm-чарт →

Особенности

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. Применим манифест:

Код запуска пода с 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/