Облачная платформаAdvanced

Миграция из SFS Turbo в бакет OBS в кластере ССE


Вы можете перенести данные из файловой системы SFS Turbo в бакет OBS, смонтированный к кластеру CCE.

OBS монтируется в CCE через FUSE-драйвер obs.csi.everest.io и не является POSIX-совместимой файловой системой.

OBS подходит для:

  • статических файлов, медиа, бэкапов, логов, артефактов, ML-датасетов (последовательное чтение);

  • общего read-mostly доступа из многих подов;

  • больших объемов данных при низкой стоимости хранения.

OBS не подходит для:

  • баз данных и любых нагрузок с fsync/O_DIRECT/блокировками;

  • random write, работы с временными файлами, hard links;

  • нагрузок, чувствительным к задержкам (десятки мс на операцию).

В OBS сохраняется:

  • режим работы ReadWriteMany — мультинодовое монтирование к подам;

  • драйвер монтирования CSI obs.csi.everest.io.

Важно учитывать при работе с OBS PV/PVC:

  • Производительность: скорость ввода-вывода (I/O) зависит от типа инстанса бакета — стандартный бакет (Object Bucket) или параллельная файловая система (Parallel File System).

  • Лимиты емкости: в отличие от блочных хранилищ, расширение емкости (Scale-out) для OBS не требуется, так как объектное хранилище масштабируется автоматически.

  • Авторизация: монтирование PV требует привязки Kubernetes Secret, содержащего зашифрованные в Base64 ключи доступа Access Key и Secret Key.

  • Ограничения платформы:

    • При монтировании OBS PVC поддерживается только ReadWriteMany, режим readOnly: true не поддерживается.

    • Владелец и права точки монтирования не изменяются, chown / chmod внутри тома работают ограниченно.

    • На каждый смонтированный OBS-том создается резидентный процесс на ноде: число OBS-томов пода не должно превышать объем запрошенной им памяти в GiB (4 ГиБ памяти — не более 4 томов).

    • Hard links не поддерживаются на бакетах.

    • При массовом динамическом провижининге лимит 100 бакетов на аккаунт исчерпывается. В таких сценариях используйте OBS через SDK/API, а не через PV.

    • Поле storage в PVC номинальное (проверочное) — оно не задает квоту и не ограничивает емкость OBS.

Доступные типы инстанса OBS (указываются в аннотации csi.storage.k8s.io/fstype):

  • obsfs — parallel file system, приближенная к файловой семантика, заметно выше производительность на метаданных.

    Рекомендуемый вариант для миграции с SFS Turbo.

  • s3fs — обычный object bucket, классы Standard или Warm.

Проверьте наличие hard links, symlink-цепочек и sparse-файлов до миграции — при переносе на object bucket они теряются:

find /old -type l
find /old -links +1

Риски и рекомендации

Риск

Рекомендация

Приложение рассчитывает на POSIX (locks, hard links, атомарный rename).

Проверьте профиль I/O до миграции: для таких нагрузок оставьте SFS Turbo.

OOM ноды из-за резидентных процессов FUSE.

Соблюдайте правило «томов ≤ GiB memory request», задавайте явные requests/limits памяти.

Недоступность томов во всех подах из-за компрометации или отзыва AK/SK.

Используйте индивидуальные секреты на namespace, регламент ротации, мониторинг событий PVC.

Задержки и стоимость запросов при большом числе мелких файлов.

Используйте obsfs (PFS) вместо s3fs, агрегируйте мелкие файлы, кешируйте на стороне приложения.

Исчерпание лимита в 100 бакетов.

Используйте статические PV на общие бакеты с разделением по префиксам вместо динамического провижининга на каждый PVC.

Удаление бакета с данными из-за удаления PVC.

Используйте значения everest.io/reclaim-policy: retain-volume-only, persistentVolumeReclaimPolicy: Retain, версионирование в OBS.

Потеря метаданных файловой системы при переносе.

Выполните инвентаризацию symlink/hardlink/прав до миграции, при необходимости упакуйте в архивы.

Расхождение аннотаций PVC и полей PV при статическом биндинге.

Храните PV и PVC в одном файле, значения fsType / obs-volume-type / secret задавайте один раз через шаблонизацию (Helm/Kustomize).

1. Создайте OBS PVC для миграции

Создавать бакет для миграции можно динамически и статически:

Способ

Как задается

Квота на том

Особенности

dynamic OBS — автоматическое создание бакета под каждый PVC.

С помощью PVC на классе csi-obs с аннотациями csi.storage.k8s.io/fstype и ссылками на секрет с AK/SK. Бакет создается автоматически, название формируется из UID PVC или из префикса everest.io/csi.volume-name-prefix.

Нет жестких квот: поле storage номинальное.

При массовом использовании может быть исчерпан лимит бакетов на аккаунт. Способ удобен для изолированных нагрузок.

static OBS — статическое подключение существующего бакета через PV.

Через манифест PersistentVolume с драйвером obs.csi.everest.io и volumeHandle с названием бакета.

Нет жестких квот: capacity.storage указывается только для валидации Kubernetes.

Требует предварительно созданного бакета. Основной вариант при миграции: данные заливаются в бакет заранее, затем подключаются к кластеру.

Динамический провижининг

При динамическом способе бакет создается автоматически.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-app-a-obs
namespace: <ns>
annotations:
csi.storage.k8s.io/fstype: obsfs # obsfs (PFS) | s3fs (object bucket)
everest.io/obs-volume-type: STANDARD # только для s3fs: STANDARD | WARM
csi.storage.k8s.io/node-publish-secret-name: <secret> # access-key/secret-key конкретного IAM-пользователя
csi.storage.k8s.io/node-publish-secret-namespace: <ns>
everest.io/csi.volume-name-prefix: <prefix> # опционально, имя бакета = prefix-<PVC UID>
spec:
accessModes:
- ReadWriteMany # единственный допустимый режим
resources:
requests:
storage: 1Gi # номинально, всегда 1
storageClassName: csi-obs

Статический PV на существующий бакет

Для этого способа создайте бакет заранее в консоли OBS или используйте существующий бакет с данными.

apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-app-a-obs
annotations:
pv.kubernetes.io/provisioned-by: everest-csi-provisioner
everest.io/reclaim-policy: retain-volume-only # удалять PV, но не бакет
spec:
accessModes:
- ReadWriteMany
capacity:
storage: 1Gi
persistentVolumeReclaimPolicy: Retain
storageClassName: csi-obs
mountOptions: []
csi:
driver: obs.csi.everest.io
fsType: obsfs
volumeHandle: <имя_бакета>
volumeAttributes:
everest.io/obs-volume-type: STANDARD
everest.io/region: <region>
storage.kubernetes.io/csiProvisionerIdentity: everest-csi-provisioner
nodePublishSecretRef:
name: <secret>
namespace: <ns>
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-app-a-obs
namespace: <ns>
annotations:
csi.storage.k8s.io/fstype: obsfs # обязательно, иначе биндинг падает
everest.io/obs-volume-type: STANDARD
csi.storage.k8s.io/node-publish-secret-name: <secret>
csi.storage.k8s.io/node-publish-secret-namespace: <ns>
volume.beta.kubernetes.io/storage-provisioner: everest-csi-provisioner
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: csi-obs
volumeName: pv-app-a-obs

Примечания:

  • При статическом биндинге обязательны аннотации PVC, так как Everest валидирует статический PV по аннотациям PVC, а не по полям PV.

  • Без параметра csi.storage.k8s.io/fstype PVC остается в статусе «Pending» с ошибкой missing fsType definition on pvc's annotation.

  • Значения fsType, everest.io/obs-volume-type и имя/namespace секрета в PVC должны совпадать с соответствующими полями PV.

  • Тип бакета определяется при его создании в OBS и не изменяется: parallel file system –> obsfs, object bucket –> s3fs. Если в манифесте указан тип, не соответствующий бакету, это приведет к ошибке монтирования, а не биндинга — то есть проявится позже на запуске пода.

  • Параметр everest.io/region должен совпадать с регионом бакета ru-moscow-1.

  • Секрет с ключами доступа — тип cfe/secure-opaque с меткой secret.kubernetes.io/used-by: csi. Рекомендуется индивидуальный AK/SK на команду или namespace вместо глобального paas.longaksk, так как глобальный ключ не дает гранулярного разграничения доступа, а его ротация требует перезапуска всех подов, смонтировавших такие тома.

  • Аннотации на PVC, уже находящемся в статусе «Pending», не применятся, так как проверка выполняется в момент биндинга, а kubectl annotate состояние не меняет.

    В таком случае пересоздайте PVC, предварительно очистив claimRef:

    kubectl delete pvc pvc-app-a-obs -n <ns>
    kubectl patch pv pv-app-a-obs -p '{"spec":{"claimRef":null}}'
    # PV → Available kubectl apply -f obs-pv-pvc.yaml
    kubectl get pvc,pv -n <ns> | grep obs
  • При значениях persistentVolumeReclaimPolicy: Retain и everest.io/reclaim-policy: retain-volume-only данные в бакете не затрагиваются.

    Перед удалением PVC убедитесь, что установлена политика Retain, иначе при выполнении Delete удаление PVC удалит и бакет.

2. Мигрируйте данные

  1. Выполните миграцию в OBS одним из способов:

    • Прямая загрузка в бакет через утилиту obsutil или rclone (предпочтительный способ).

      Этот способ не требует монтирования OBS в кластер на время копирования и дает параллелизм:

      # копирование из пода с примонтированным исходным PVC либо с ECS, где смонтирован SFS Turbo
      obsutil sync /old/ obs://<bucket>/ -f -flat -j 20 -p 5
      # альтернатива, удобна при инкрементальных проходах
      rclone sync /old/ obs:<bucket> --transfers 32 --checkers 32 --s3-no-check-bucket
    • rsync-под между двумя PVC — оба тома RWX монтируются одновременно.

      Из-за FUSE обязательны флаги отключения атрибутов, иначе rsync завершится ошибками на chown / chmod / utime:

      apiVersion: v1
      kind: Pod
      metadata:
      name: rsync-obs-pod
      namespace: <ns>
      spec:
      restartPolicy: Never
      containers:
      - name: rsync
      image: eeacms/rsync:2.3
      command:
      - "sleep"
      - "infinity"
      resources:
      requests:
      memory: 2Gi # >= 1 GiB на каждый OBS-том
      volumeMounts:
      - name: old
      mountPath: /old
      - name: new
      mountPath: /new
      volumes:
      - name: old
      persistentVolumeClaim:
      claimName: <исходный-pvc>
      - name: new
      persistentVolumeClaim:
      claimName: pvc-app-a-obs
  2. Выполните синхронизацию:

    # --no-perms --no-owner --no-group --omit-dir-times обязательны для FUSE-тома
    # --inplace снижает объем временных записей, --size-only ускоряет повторные проходы
    kubectl exec -n <ns> rsync-obs-pod -- \
    rsync -rlD --no-perms --no-owner --no-group --omit-dir-times --inplace /old/ /new/
  3. Переключите нагрузку правкой claimName в манифесте нагрузки — с коротким простоем (scale 0 –> финальный проход –> правка –> scale N) или live-циклом синхронизации.

3. Проверьте статус PVC и PV

Выполните команды для проверки:

kubectl get pvc,pv -n <ns> | grep obs
kubectl exec -n <ns> <pod> -- ls -la /data
# проверка количества и суммарного размера объектов
obsutil stat obs://<bucket>
kubectl rollout status deploy/<app> -n <ns>

Также проверьте, что после переключения приложение выдерживает задержки OBS под реальной нагрузкой. Деградация может проявиться не сразу, а на пиковых операциях со списками директорий и мелкими файлами.