Стадия жизненного цикла модуля: Экспериментальная версия
У модуля есть требования для установки
На этой странице приведены основные сценарии работы с модулем: от базовой настройки до дополнительных возможностей хранилищ и бакетов.
Быстрый старт
Следующие шаги позволяют включить модуль, создать объектное хранилище и получить доступ к бакету.
Включение модуля
Модуль находится в стадии Experimental. Перед включением разрешите использование экспериментальных модулей в ModuleConfig deckhouse:
d8 k patch moduleconfig deckhouse --type=merge --patch '{"spec":{"settings":{"allowExperimentalModules":true}}}'Включите модуль с помощью ModuleConfig:
d8 k apply -f - <<EOF
apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
name: sds-object
spec:
enabled: true
version: 1
EOFСоздание хранилища
Хранилище представляет data plane. Для каждого поддерживаемого бэкенда используется отдельный Kind.
Пример создания хранилища SeaweedFS поверх существующего StorageClass с использованием бэкенда SeaweedFSStore:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: SeaweedFSStore
metadata:
name: default
spec:
masters: 3
volumeServers: 3
replication: "001" # Одна дополнительная копия на другом volume-сервере.
storage:
sizePerNode: 50Gi
class: localpath
EOFКоличество компонентов и код репликации SeaweedFS должны быть согласованы. Третья цифра кода репликации задаёт количество дополнительных копий на других volume-серверах. Поэтому значение volumeServers должно быть как минимум на единицу больше этого значения. Иначе SeaweedFS не сможет завершать запись данных.
Чтобы использовать несколько filer, задайте в spec SeaweedFSStore поля filers и metadataStore: значение LevelDB, которое metadataStore принимает по умолчанию, хранит метаданные на локальном томе каждого filer и не поддерживает совместное использование несколькими filer.
spec:
filers: 3
metadataStore: Postgres # Требуется модуль managed-postgres.Создание класса объектного хранилища
ObjectStore определяет доступный пользователям класс объектного хранилища. Он содержит ссылку на хранилище и значения по умолчанию для создаваемых бакетов.
Пример создания ObjectStore, ссылающегося на SeaweedFSStore:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: ObjectStore
metadata:
name: standard
spec:
storeRef:
kind: SeaweedFSStore
name: default
reclaimPolicy: Retain
quota:
maxSize: 100Gi # Максимальный объём бакета; большее значение отклоняется.
EOFПроверьте состояние хранилища:
d8 k get seaweedfsstoreПример вывода:
NAME VOLUMES REPLICATION PHASE ENDPOINT READY AGE
default 3 001 Ready http://default-seaweedfs.d8-sds-object... True 3m
После развёртывания data plane хранилище переходит в состояние Ready, а в поле ENDPOINT отображается его эндпоинт.
Проверьте состояние ObjectStore:
d8 k get objectstoreПример вывода:
NAME STORE-KIND STORE RECLAIM PHASE READY AGE
standard SeaweedFSStore default Retain Ready True 2m
ObjectStore переходит в состояние Ready, если указанное в нём хранилище существует и также находится в состоянии Ready.
Admission-вебхук отклоняет неизвестное значение storeRef.kind. Поддерживаемые Kind хранилищ определяются реестром драйверов контроллера, а не схемой CRD. Поэтому добавление нового бэкенда не требует изменения схемы ObjectStore.
Запрос бакета
Создайте неймспейс приложения, если его ещё нет:
d8 k create namespace my-appЧтобы создать S3-бакет, создайте Bucket. Контроллер создаёт для него cluster-wide-объект BucketContents, определяет хранилище через ObjectStore и создаёт бакет в выбранном бэкенде. BucketContents связан с исходным Bucket и хранит информацию о размещении данных.
Пример создания бакета с accessPolicy: Private и reclaimPolicy: Retain:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: Bucket
metadata:
name: app-data
namespace: my-app
spec:
objectStoreRef: standard
accessPolicy: Private
reclaimPolicy: Retain # Не задавайте, если хотите использовать значение класса.
EOFПроверьте состояние Bucket:
d8 k -n my-app get bucket app-dataПример вывода:
NAME CONTENTS PHASE READY AGE
app-data contents-1f2e3d-... Ready True 20s
В состоянии Ready Bucket указывает имя принадлежащего ему BucketContents.
Созданный BucketContents виден на уровне кластера (d8 k get bktc), но создавать его вручную не следует. Admission-вебхук разрешает создание этого ресурса только ServiceAccount модуля. Это предотвращает появление BucketContents, не связанного с пользовательским Bucket.
Модуль не поддерживает привязку существующего бакета и совместное использование одного бакета из нескольких неймспейсов. Ранее эти сценарии зависели от BucketClaimPolicy, который выбирал неймспейсы по имени или регулярному выражению. Этот ресурс удалён, а межнеймспейсный доступ к бакету пока не реализован.
Если бакет уже существует
Имя бакета в бэкенде формируется на основе BucketContents. Бакет с таким именем может существовать заранее: например, если он был создан вручную, сохранился после пересоздания хранилища или принадлежит другому кластеру, использующему тот же бэкенд.
Каждый созданный бакет модуль помечает двумя тегами:
storage.deckhouse.io/owned-by sds-object
storage.deckhouse.io/bucket-contents contents-1a2b3c4d5e-team-a-data
Если этих тегов нет, модуль не принимает существующий бакет под управление. BucketContents остаётся неготовым, а состояние условия BucketReady меняется на False с причиной BucketNotOwnedByModule. Содержимое существующего бакета при этом не изменяется.
Пример состояния условия BucketReady:
BucketReady False BucketNotOwnedByModule
bucket "team-a-data" already exists in the backend and is not managed by this
module (it carries no ownership tag); remove it or point this Bucket at
another store
В этой ситуации удалите конфликтующий бакет, если он больше не нужен, либо укажите для Bucket другое хранилище. Контроллер не повторяет попытку автоматически, чтобы не предоставить доступ к данным, которыми модуль не управляет.
Бакеты, созданные модулем до появления этих тегов, обрабатываются отдельно. На следующем цикле reconcile модуль определяет их по сохранённому status.bucketName и добавляет необходимые теги. Поэтому обновление не нарушает работу ранее созданных бакетов.
Запрос учётных данных
Для получения учётных данных создайте BucketAccess, который ссылается на Bucket в том же неймспейсе, у которого состояние условия Bound — True. Контроллер создаёт отдельные ключ доступа и секретный ключ для этого бакета и сохраняет их в Secret с именем <ACCESS>-s3-credentials по умолчанию.
Пример создания BucketAccess, ссылающегося на Bucket app-data, с permission: ReadWrite:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: BucketAccess
metadata:
name: app-data
namespace: my-app
spec:
bucketRef: app-data
permission: ReadWrite # Для доступа только на чтение используйте ReadOnly.
EOFПроверьте состояние BucketAccess:
d8 k -n my-app get bucketaccess app-dataПример вывода:
NAME BUCKET PHASE SECRET READY AGE
app-data app-data Ready app-data-s3-credentials True 20s
После создания учётных данных BucketAccess содержит имя Secret, в котором они сохранены.
Использование учётных данных
Secret содержит стандартные переменные подключения к S3. Добавьте его в контейнер в манифесте Deployment через envFrom:
| Ключ | Описание |
|---|---|
S3_ENDPOINT |
Внутрикластерный URL S3-эндпоинта |
S3_REGION |
Регион S3 |
S3_BUCKET |
Имя бакета |
AWS_ACCESS_KEY_ID |
Ключ доступа |
AWS_SECRET_ACCESS_KEY |
Секретный ключ |
Пример фрагмента Deployment с подключённым Secret:
spec:
template:
spec:
containers:
- name: app
envFrom:
- secretRef:
name: app-data-s3-credentialsХранилища на Ceph RGW
Хранилище на Ceph RGW создаётся через объект SDSElasticStore. Он разворачивает Ceph RADOS Gateway поверх существующего кластера sds-elastic и принимает собственные настройки пулов Ceph.
Пример создания SDSElasticStore с репликацией size: 3:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: SDSElasticStore
metadata:
name: heavy
spec:
elasticClusterRef: main
dataPool:
replicated:
size: 3
# Вместо репликации можно использовать erasure coding.
# erasureCoded: { dataChunks: 4, codingChunks: 2 }
EOFПример создания ObjectStore, ссылающегося на SDSElasticStore:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: ObjectStore
metadata:
name: capacity
spec:
storeRef:
kind: SDSElasticStore
name: heavy
EOFРабота с Bucket и BucketAccess не зависит от типа хранилища, указанного в ObjectStore. Для Ceph RGW при создании Bucket модуль создаёт бакет и отдельного Rook CephObjectStoreUser, который становится его владельцем. Для каждого BucketAccess создаётся отдельный CephObjectStoreUser, которому доступ к бакету предоставляется с помощью политики бакета.
Ротация учётных данных
Чтобы сменить ключ доступа для BucketAccess, установите или измените аннотацию storage.deckhouse.io/rotate. Контроллер создаст новую пару ключей, обновит Secret и отзовёт предыдущий ключ:
d8 k -n my-app annotate bucketaccess app-data storage.deckhouse.io/rotate="$(date +%s)" --overwriteИспользование внешней базы метаданных
metadataStore: External позволяет использовать внешний PostgreSQL, который модуль не разворачивает и не обслуживает. Как и при metadataStore: Postgres, несколько filer могут использовать одну базу метаданных. При этом администратор самостоятельно отвечает за доступность, резервное копирование и обновление внешней базы.
Если база метаданных недоступна, хранилище не может обслуживать S3-запросы. Репликация данных на volume-серверах не заменяет доступность базы метаданных.
Пример создания секрета с параметрами подключения и использующего его SeaweedFSStore:
d8 k apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: media-metadata-db
namespace: d8-sds-object
stringData:
host: pg.example.internal
port: "5432"
database: seaweedfs_media
username: seaweedfs
password: <PASSWORD>
sslmode: verify-full
ca.crt: |
-----BEGIN CERTIFICATE-----
...
---
apiVersion: storage.deckhouse.io/v1alpha1
kind: SeaweedFSStore
metadata:
name: media
spec:
metadataStore: External
externalMetadataStore:
secretRef:
name: media-metadata-db
filers: 3
storage:
class: linstor-r2
EOFТребования к базе данных. Используйте PostgreSQL 12 или новее, отдельную пустую базу и роль с правом создавать в ней таблицы. Filer создаёт таблицу для каждого бакета при первом обращении и не выполняет миграции схемы.
Не используйте общую прикладную базу: имена таблиц формируются из имён бакетов и могут совпасть с именами таблиц других приложений.
TLS. По умолчанию используется sslmode: require: соединение шифруется, но сертификат сервера не проверяется. Чтобы включить проверку сертификата и имени сервера, добавьте сертификат центра сертификации (CA) в ключ ca.crt Secret и укажите sslmode: verify-full. CA-сертификат будет смонтирован в filer и использован при установлении соединения.
Значение sslmode: disable отклоняется при проверке конфигурации, поскольку соединение передаёт пароль и метаданные объектов. Опечатка или другое неизвестное libpq значение sslmode может пройти проверку доступности базы: на этом этапе проверяется DNS/TCP-соединение с указанным адресом и портом. Ошибка обнаружится при запуске filer: libpq отклонит значение, и под filer будет перезапускаться.
Изменение параметров подключения. После изменения адреса базы, пароля или CA-сертификата в Secret filer перезапускаются и загружают новые параметры. Параметры подключения читаются только при запуске процесса.
При одном filer S3-эндпоинт будет кратковременно недоступен. Если filer несколько, они перезапускаются последовательно.
Размещение подов
В параметре spec.placement задаются nodeSelector и tolerations. Эти настройки применяются ко всем подам SeaweedFSStore, которые создаёт модуль.
Для реплик master и volume-серверов требуется размещение на разных узлах. Если для очередной реплики нет подходящего отдельного узла, соответствующий под остаётся в состоянии Pending.
Для filer распределение по разным узлам является предпочтительным. Если такое размещение невозможно, несколько filer могут быть запущены на одном узле. Отказ нескольких filer снижает доступность сервиса до повторного планирования подов, но не приводит к потере метаданных, поскольку они хранятся отдельно.
Параметр spec.placement не применяется к управляемой базе метаданных. Размещение PostgreSQL настраивается отдельно в PostgresClass с помощью tolerations, nodeSelector и nodeAffinity. Чтобы использовать определённый PostgresClass, укажите его в spec.postgresClassName. Если параметр не задан, используется класс default.
Пример настройки размещения хранилища с отдельным PostgresClass для базы метаданных:
spec:
metadataStore: Postgres
postgresClassName: storage-dedicated
placement:
nodeSelector:
node-role/storage: ""
tolerations:
- key: storage.deckhouse.io/dedicated
operator: Exists
effect: NoScheduleОтветственность за внешнюю базу. Модуль не создаёт базу и роль, не выполняет миграции, не создаёт резервные копии и не контролирует состояние сервера PostgreSQL. Перед настройкой filer модуль проверяет доступность указанного адреса и порта. Ошибка DNS-разрешения или недоступный порт отражаются в статусе хранилища.
Пример сообщения в статусе:
BackendReady False Pending
the external metadata database at pg.example.internal:5432 did not answer:
dial tcp: lookup pg.example.internal: no such host
При потере базы метаданных объекты останутся на volume-серверах, но сопоставление объектов с бакетами будет утрачено. Включите эту базу в план резервного копирования хранилища.
Политика высвобождения
Что произойдёт с сохранёнными данными при удалении, зависит от установленной политики высвобождения (параметр reclaimPolicy):
-
Для Bucket с
reclaimPolicy: Retain, соответствующий бакет и его объекты сохраняются. BucketContents переходит в фазуReleasedи сохраняет сведения об исходном Bucket и хранилище, в котором находятся данные:d8 k get bktcПример вывода:
NAME STORE-KIND STORE OWNER-NS OWNER BUCKET PHASE READY AGE contents-1f2e3d-... SeaweedFSStore default my-app app-data my-app-app-data Released False 4hЕсли повторно создать Bucket
app-dataв неймспейсеmy-app, контроллер снова свяжет его с сохранённым BucketContents и данными. При удалении неймспейса Bucket удаляется вместе с ним, а данные приRetainсохраняются.Deleteвместо этого удаляет бакет с объектами, а с ними и BucketContents. Bucket, не задавший политику, берёт её у класса; у класса по умолчаниюRetain. -
Удаление BucketAccess всегда отзывает его ключ доступа и удаляет его Secret (данные бакета не затрагиваются).
-
Хранилище
reclaimPolicy: Retain(по умолчанию) — при удалении хранилища данные сохраняются: SDSElasticStore сохраняет свои пулы Ceph RGW, SeaweedFSStore оставляет свои PVC.Delete— данные уничтожаются. -
Удаление ObjectStore не удаляет хранилище и уже созданные бакеты. После удаления класса нельзя создавать через него новые Bucket. Ссылка на фактическое хранилище сохраняется в BucketContents.
Чтобы удалить данные, сохранённые после удаления Bucket с reclaimPolicy: Retain, удалите соответствующий BucketContents. Если связанного Bucket уже нет, контроллер удалит бакет в бэкенде.
Политика высвобождения определяет поведение при удалении Bucket. Удаление BucketContents — отдельная операция. Если Bucket уже удалён, удаление BucketContents приводит к удалению сохранённого бакета в бэкенде. Если связанный Bucket продолжает существовать, контроллер создаст BucketContents заново и повторно свяжет его с существующим бакетом.
Публикация хранилища за пределами кластера
По умолчанию хранилище доступно только внутри кластера. В status.endpoint заполнено только поле internal, и этот адрес добавляется в Secret с учётными данными. Для доступа из внешней сети опубликуйте хранилище через модуль alb, который реализует Gateway API поверх Envoy.
Перед публикацией подготовьте:
- Создайте Gateway с помощью ALBInstance или ClusterALBInstance модуля
alb. Имя и неймспейс Gateway определите поstatusсоответствующего объекта. - Создайте DNS-запись для имени внешнего эндпоинта.
- Создайте в неймспейсе
d8-sds-objectSecret типаkubernetes.io/tlsс сертификатом для этого имени. Модуль не выпускает сертификаты, поэтому используйте Secret, созданный cert-manager, или заранее подготовленный Secret.
Затем добавьте в хранилище блок publish:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: SeaweedFSStore
metadata:
name: default
spec:
storage:
class: linstor-thin-r2
publish:
hostname: s3.example.com
gatewayRef:
name: public-gw # Объект Gateway, созданный администратором.
namespace: d8-alb
tls:
secretRef:
name: s3-example-com-tls
EOFМодуль создаст ListenerSet (хост, порт 443, терминация TLS указанным сертификатом) и HTTPRoute на S3-порт хранилища. Проверьте опубликованный эндпоинт:
d8 k get seaweedfsstore default -o jsonpath='{.status.endpoint}'Пример вывода:
{"external":"https://s3.example.com","internal":"http://default-seaweedfs...:8333","region":"us-east-1"}
TLS обязателен и не может быть отключён. Учётные данные S3 передаются в заголовке Authorization, поэтому публикация по HTTP позволила бы перехватить их из сетевого трафика.
Модуль публикует имя хоста, а listener использует порт 443. Если ALBInstance или ClusterALBInstance настроен с inlet типа HostPort и нестандартным портом, например 8443, поле status.endpoint.external содержит https://<HOST> без номера порта. В таком окружении клиенту необходимо явно использовать https://<HOST>:8443.
Для inlet типа LoadBalancer, который принимает соединения на порту 443, адрес из status.endpoint.external можно использовать без изменений.
Выбор адреса в учётных данных
По умолчанию в Secret с учётными данными добавляется внутрикластерный адрес хранилища. Чтобы использовать внешний адрес, укажите в BucketAccess endpointScope: External.
Пример создания BucketAccess с endpointScope: External:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: BucketAccess
metadata:
name: backup-writer
namespace: my-app
spec:
bucketRef: app-data
permission: ReadWrite
endpointScope: External
EOFЕсли для BucketAccess запрошен внешний адрес, но хранилище не опубликовано, BucketAccess не подставляет внутрикластерный адрес автоматически. Объект остаётся неготовым, а в status.conditions указывается, что для хранилища требуется настроить spec.publish.
При смене эндпоинта (включили публикацию, поменяли имя хоста) Secret всех затронутых BucketAccess перевыпускаются автоматически.
Ограничения адресации
Поддерживается режим PathStyle: https://s3.example.com/<BUCKET>/<KEY>. Ему достаточно одного DNS-имени и одного сертификата.
Режим spec.publish.addressing: VirtualHosted использует адрес вида https://<BUCKET>.s3.example.com/<KEY>, но в текущей версии отклоняется admission-вебхуком. Для него требуются wildcard-DNS и wildcard-сертификат, а поддержка этого режима в S3-шлюзах бэкендов различается и пока не проверена модулем. Поэтому опубликованный эндпоинт поддерживает только режим PathStyle.
Компоненты, доступные только внутри кластера
Для SeaweedFS наружу публикуется только S3-порт. Модуль создаёт для него отдельный Service с одним портом. Основной Service хранилища также содержит HTTP- и gRPC-API filer, поэтому он не используется для внешней публикации.
В Ceph RGW S3 API и Admin Ops API используют один порт, а административные методы доступны по путям /admin/…. Поэтому при публикации SDSElasticStore этот путь также становится доступным по сети.
Учётные данные, выдаваемые модулем пользователям, не содержат административных прав и не дают доступ к Admin Ops API. Однако Rook создаёт для каждого объектного хранилища пользователя rgw-admin-ops-user с правами buckets=*;users=*. Его ключи хранятся в Secret в неймспейсе d8-sds-elastic. Безопасность Admin Ops API зависит от защиты этих учётных данных и ограничений на уровне Gateway.
Перед публикацией хранилища Ceph RGW учтите следующие меры защиты:
- запретите доступ к
/adminна Gateway, если это поддерживается используемой конфигурацией; - если ограничить
/adminневозможно, рассмотрите отдельный CephObjectStore для внешнего эндпоинта; - защищайте Secret
rgw-admin-ops-userкак административные учётные данные хранилища, доступного из внешней сети.
Для SeaweedFS этого ограничения нет: внешний Service содержит только S3-порт, а служебные API filer остаются недоступны через внешний маршрут.
Диагностика внешней публикации
Состояние внешней публикации отражается в условии PublishedEndpointReady из status.conditions и не влияет на состояние Ready самого хранилища. Ошибка внешнего маршрута не блокирует создание и удаление бакетов или выдачу учётных данных для внутрикластерного доступа.
Проверьте состояние условия PublishedEndpointReady:
d8 k get seaweedfsstore default -o jsonpath='{range .status.conditions[?(@.type=="PublishedEndpointReady")]}{.reason}: {.message}{end}'Типичные причины:
| Причина | Что делать |
|---|---|
GatewayAPIMissing |
В кластере нет CRD Gateway API — включите модуль alb |
NotAllowedByListeners |
Listener Gateway не принимает маршруты из неймспейса модуля — администратору нужно разрешить их (allowedRoutes либо ReferenceGrant в неймспейсе Gateway) |
BackendNotFound |
Gateway не видит Service хранилища; проверьте, что хранилище запустилось |
Pending |
Gateway-контроллер ещё не ответил про маршрут |
Публичное чтение
accessPolicy: PublicRead у Bucket открывает объекты бакета на чтение без учётных данных. Оба бэкенда поддерживают этот режим.
Пример создания Bucket с accessPolicy: PublicRead:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: Bucket
metadata:
name: site-assets
namespace: my-app
spec:
objectStoreRef: standard
accessPolicy: PublicRead
EOFПроверьте чтение объекта без учётных данных:
curl -s https://s3.example.com/my-app-site-assets/logo.png -o logo.pngПубличный доступ разрешает только чтение объектов:
- Только объекты, без листинга. Анонимный вызов
GetObjectразрешён, если известен ключ объекта.ListObjectsдля бакета остаётся запрещённым. Публичное чтение объектов не включает публичный листинг содержимого бакета. - Только чтение. Анонимные запись, удаление и тегирование запрещены на обоих бэкендах.
- Только этот бакет. Грант выдан на имя бакета, остальные бакеты того же хранилища он не затрагивает.
При использовании PublicRead учитывайте следующие особенности:
- Публичный доступ зависит от доступности эндпоинта. Внутри кластера S3-эндпоинт доступен через Service модуля. Для доступа из внешней сети настройте
spec.publishу хранилища. Публикация делает эндпоинт доступным из внешней сети, аaccessPolicyопределяет, требуется ли авторизация для чтения конкретного бакета. - Бакет в фазе
Releasedостаётся публичным. Удаление Bucket приreclaimPolicy: Retainсохраняет данные и сам BucketContents вместе с егоaccessPolicy. Поэтому после удаления Bucket данные остаются доступными в том же режиме. Чтобы отключить публичное чтение, администратор с правами на изменение cluster-wide-ресурса BucketContents должен установить у негоaccessPolicy: Private. Если сохранённые данные больше не нужны, администратор может вместо этого удалить BucketContents. Встроенные роли модуля User и ClusterEditor не предоставляют права на изменение BucketContents.
После изменения значения на Private публичное чтение отключается при следующем reconcile. Ранее выданные ключи доступа к бакету сохраняются.
Версионирование и блокировка объектов
versioning: Enabled хранит каждую версию объекта вместо перезаписи.
objectLock включает режим WORM (Write Once Read Many) для версий объектов. Версию, для которой действует срок хранения, нельзя удалить до его окончания — ни пользователю, ни администратору хранилища, ни модулю.
Пример создания Bucket с включённым версионированием и Object Lock:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: Bucket
metadata:
name: audit-log
namespace: my-app
spec:
objectStoreRef: standard
versioning: Enabled
objectLock:
mode: Compliance # Допустимые значения: Governance или Compliance.
days: 365
reclaimPolicy: Retain # Обязательно вместе с objectLock.
EOFРежим Governance допускает обход ограничения при наличии соответствующего разрешения. В режиме Compliance удалить защищённую версию до окончания срока нельзя. Срок хранения можно увеличить, но нельзя сократить. Эти ограничения применяет бэкенд.
В статусе модуль отражает фактическое состояние настроек в бэкенде:
d8 k get bktc -o custom-columns='NAME:.metadata.name,VERSIONING:.status.versioning,LOCK:.status.objectLock.enabled,MODE:.status.objectLock.mode'Проверки API
Admission-вебхук отклоняет несколько сочетаний ещё до того, как они дойдут до бэкенда:
objectLockтребуетversioning: Enabled. Блокировка построена на версиях.objectLockнеизменяем и задаётся только при создании Bucket. Ceph RGW принимает настройку Object Lock только при создании бакета, поэтому включить её для уже существующего бакета нельзя. Ограничение одинаково для обоих бэкендов: чтобы защитить существующие данные, создайте новый бакет с Object Lock и перенесите данные.objectLockнесовместим сreclaimPolicy: Delete— в том числе когдаDeleteприходит из класса по умолчанию. Бакет с защищёнными объектами удалить нельзя, поэтому такая пара оставила бы BucketContents вTerminatingдо истечения последнего срока. Запрос отклоняется, а не переключается молча наRetain.- Версионирование нельзя выключить на заблокированном бакете. Это отвергают оба бэкенда, и то же самое делает API.
Бессрочная блокировка удаления
Бессрочная блокировка удаления запрещает удаление версии объекта без ограничения по времени и действует до явного снятия. Бессрочная блокировка удаления не настраивается в Bucket: клиент устанавливает и снимает её для конкретной версии объекта с помощью своих учётных данных:
mc legalhold set myalias/my-app-audit-log/report.pdf
mc legalhold clear myalias/my-app-audit-log/report.pdfПока действует бессрочная блокировка удаления, удалить защищённую версию нельзя. Для удаления сначала снимите бессрочную блокировку удаления.
Удаление защищённых данных
При удалении Bucket с reclaimPolicy: Retain данные сохраняются, BucketContents переходит в фазу Released, а параметры защиты объектов продолжают действовать. Чтобы удалить сохранённые данные, удалите BucketContents. Если в бакете остаются защищённые версии, бэкенд отклонит удаление, BucketContents сохранит финалайзер, а причина будет указана в status.conditions.
Проверьте сообщение состояния условия Ready:
d8 k get bktc contents-... -o jsonpath='{.status.conditions[?(@.type=="Ready")].message}'Пример вывода:
бэкенд отказывается удалить бакет, пока его объекты защищены; ...
После окончания последнего срока хранения удаление продолжится автоматически. До этого удалить защищённые версии можно только при наличии разрешения на обход ограничения срока хранения. Для режима Compliance такой обход недоступен.
Ёмкость хранилища
Данные о ёмкости хранилища публикуются в status.capacity и отображаются в расширенном выводе d8 k.
Проверьте ёмкость хранилища:
d8 k get seaweedfsstore media -o wideПример вывода:
NAME VOLUMES REPLICATION PHASE ENDPOINT USED% CAPACITY READY
media 3 001 Ready http://...svc:8333 37.24 300Gi True
Фрагмент status.capacity в YAML-представлении SeaweedFSStore:
status:
capacity:
total: 300Gi
used: 111Gi
available: 189Gi
usedPercent: "37.24"
lastUpdated: "2026-08-30T09:12:04Z"Значение status.capacity рассчитывается по-разному для разных бэкендов:
- SeaweedFSStore — сумма ёмкости дисков, используемых volume-серверами этого хранилища. Если volume-сервер недоступен при сборе данных, его ёмкость не включается в расчёт. Это позволяет не считать недоступный диск свободным.
- SDSElasticStore — сырая ёмкость всего Ceph-кластера, которую сообщает сам Ceph. Это значение не является квотой конкретного SDSElasticStore и не показывает фактически доступный приложению объём: на него влияют схема репликации и использование других пулов того же кластера.
Если получить данные о ёмкости не удалось ни от одного источника, поле status.capacity не заполняется. Отсутствие поля означает, что ёмкость неизвестна; нулевое значение для этого случая не используется.
Метрики и алерты
Для каждого хранилища экспортируются следующие метрики с лейблами store_kind и store:
| Метрика | Описание |
|---|---|
sds_object_store_ready |
1, если хранилище готово обслуживать S3-запросы; 0 — если не готово |
sds_object_store_capacity_bytes_total |
Общий объём хранилища в байтах |
sds_object_store_capacity_bytes_used |
Занятый объём в байтах |
sds_object_store_capacity_bytes_available |
Доступный объём в байтах |
Метрики ёмкости экспортируются только после успешного получения данных о ёмкости. Если получить данные не удалось, метрики sds_object_store_capacity_bytes_* отсутствуют, поэтому алерты заполнения не срабатывают на основании неизвестного значения.
Метрика sds_object_store_ready экспортируется всегда, пока существует соответствующее хранилище. Значение 0 означает, что хранилище не готово. После удаления ресурса или модуля временной ряд исчезает. Таким образом, состояние неготовности отличается от отсутствия самого ресурса.
Для этих метрик настроены следующие алерты: D8SdsObjectStoreNotReady — хранилище остаётся неготовым более 30 минут; D8SdsObjectStoreFillingUp — занято более 85% ёмкости в течение часа; D8SdsObjectStoreAlmostFull — занято более 95% ёмкости. Состояние хранилищ также отображается на дашборде SDS Object — Stores.
Порог 95% учитывает поведение SeaweedFS: master прекращает размещать новые тома на диске после достижения 90% заполнения. Поэтому хранилище может оставаться в состоянии Ready, но уже не иметь возможности размещать новые данные.
Целостность данных
Статус хранилища содержит сведения о последней проверке целостности: источник проверки, время выполнения и обнаруженные повреждения.
Проверьте результат последней проверки целостности:
d8 k get seaweedfsstore,sdselasticstore -o custom-columns='NAME:.metadata.name,INTEGRITY:.status.conditions[?(@.type=="IntegrityHealthy")].status,LAST SCRUB:.status.integrity.lastScrubTime,DAMAGED:.status.integrity.damaged'До завершения первой проверки состояние условия IntegrityHealthy — Unknown. Это отличает отсутствие результатов проверки от подтверждённого состояния без повреждений. При обнаружении проблемы состояние условия меняется на False, а сообщение содержит диагностическую информацию бэкенда, включая сведения о проблемном диске.
Состояние Ready не зависит от IntegrityHealthy. Хранилище может продолжать обслуживать доступные данные даже при обнаружении повреждённого тома.
Механизм и периодичность проверки
У каждого бэкенда проверка устроена по-своему:
-
SeaweedFS — SeaweedFS сверяет контрольную сумму при чтении объекта. Для данных, к которым приложения давно не обращались, модуль по расписанию запускает полную проверку целостности: SeaweedFS считывает хранимые данные и сверяет их контрольные суммы.
Параметры периодической проверки задаются в
spec.integrity:apiVersion: storage.deckhouse.io/v1alpha1 kind: SeaweedFSStore metadata: name: media spec: integrity: interval: 24h # По умолчанию используется 168h; значения меньше 1h увеличиваются до 1h. mode: Full # Full используется по умолчанию и читает все байты; Index — только индексы. enabled: true # Далее следуют остальные поля spec.Режим
Fullиспользуется по умолчанию, посколькуIndexне обнаруживает повреждение содержимого объекта. Интервал по умолчанию выбран с учётом нагрузки: полная проверка читает каждый хранимый байт.Полная проверка выполняется асинхронно, отдельно от reconcile. Во время проверки
IntegrityHealthyполучает причинуScrubInProgress. Результат записывается в статус после завершения проверки; на больших хранилищах она может занимать продолжительное время. При перезапуске контроллера текущая проверка прекращается, а следующая запускается по расписанию.Недоступный volume-сервер не считается повреждённым. Он отражается в
status.integrity.unreachable. Если часть узлов не удалось проверить и повреждения не обнаружены,IntegrityHealthyостаётся в состоянииUnknownс причинойScrubIncomplete, поскольку проверка охватила не всё хранилище.Если в хранилище ещё нет ни одного volume, проверка не считается завершённой проверкой данных. Состояние условия
IntegrityHealthyостаётсяUnknownс причинойNothingToCheck, аstatus.integrityне заполняется. После появления данных хранилище будет проверено по расписанию. -
Ceph RGW — проверки выполняет Ceph по собственному расписанию. Модуль получает результаты из healthcheck ElasticCluster (
OSD_SCRUB_ERRORS,PG_DAMAGED,PG_NOT_DEEP_SCRUBBED, …). У SDSElasticStore нетspec.integrity: запускdeep-scrubи автоматическое восстановление настраиваются на уровне кластера Ceph и не управляются модулемsds-object.
status.integrity.source указывает источник опубликованного результата проверки.
Состояние репликации
Недостаточное количество копий не означает повреждение данных, поэтому оно отражается отдельно в состоянии условия RedundancyHealthy и status.redundancy.
Проверьте состояние репликации:
d8 k get seaweedfsstore -o custom-columns='NAME:.metadata.name,WANTED:.status.redundancy.copiesWanted,VOLUMES:.status.redundancy.volumes,SHORT:.status.redundancy.underReplicated'Данные о количестве копий берутся из топологии SeaweedFS master и обновляются при каждом reconcile независимо от расписания проверки целостности.
Сочетание RedundancyHealthy: False и IntegrityHealthy: True означает, что повреждений не обнаружено, но количество копий ниже требуемого. При replication: "000" требуется одна копия. Если она доступна, недостатка копий нет.
SeaweedFS 4.39 не восстанавливает потерянную реплику автоматически. В составе maintenance framework доступны задачи balance, vacuum, erasure coding, EC balance, S3 lifecycle и Iceberg, но отдельной задачи восстановления репликации нет, хотя соответствующий тип задачи присутствует в протоколе. Поэтому после потери реплики восстановите её вручную. Сначала выведите список подов в неймспейсе модуля и выберите под с образом SeaweedFS:
d8 k -n d8-sds-object get pods -o custom-columns='NAME:.metadata.name,IMAGES:.spec.containers[*].image'Откройте shell в выбранном поде:
d8 k -n d8-sds-object exec -it <SEAWEEDFS_POD> -- shЗатем запустите восстановление репликации из этого shell:
weed shell -master=<STORE>-seaweedfs-master:9333 <<'EOF'
lock
volume.fix.replication -apply
unlock
EOFДля SDSElasticStore состояние условия RedundancyHealthy — Unknown с причиной NotAccountedHere. Состояние репликации контролируется самим Ceph и доступно через его healthcheck; модуль sds-object не дублирует этот расчёт.
Автоматическое восстановление
По умолчанию модуль только сообщает об обнаруженном повреждении. Если установить spec.integrity.autoRepair: true, модуль попытается восстановить повреждённую копию SeaweedFS из другой копии, успешно прошедшей проверку:
spec:
replication: "001" # Для восстановления требуется более одной копии.
integrity:
autoRepair: trueАвтоматическое восстановление отключено по умолчанию, поскольку процедура удаляет повреждённую копию и создаёт новую. Перед восстановлением каждого тома модуль проверяет следующие условия:
- Для тома существует более одной копии. При
replication: "000"повреждённая копия является единственной, поэтому автоматическое восстановление невозможно. - Другая копия того же тома успешно прошла проверку целостности в текущем цикле. Недоступная или непроверенная копия не используется как источник восстановления.
Если хотя бы одно условие не выполнено, модуль не удаляет повреждённую копию, а status.integrity.details указывает причину отказа от восстановления. Если создание новой копии после удаления повреждённой завершилось ошибкой, RedundancyHealthy сообщает о недостаточном количестве копий.
Успешно восстановленные тома учитываются в status.integrity.repaired и больше не входят в число повреждённых. После успешного восстановления соответствующий алерт перестаёт срабатывать.
Для Ceph RGW этот механизм не применяется: восстановлением placement group управляет сам Ceph. Модуль не запускает deep-scrub и не включает osd_scrub_auto_repair.
Метрики и алерты
Состояние целостности и репликации также экспортируется в метрики с лейблами store_kind и store:
| Метрика | Описание |
|---|---|
sds_object_store_integrity_damaged |
Количество единиц хранения, в которых последняя проверка обнаружила повреждения |
sds_object_store_integrity_repaired |
Количество единиц хранения, успешно восстановленных модулем |
sds_object_store_integrity_scanned_volumes |
Количество томов, проверенных при последней проверке целостности |
sds_object_store_integrity_last_scrub_timestamp_seconds |
Время завершения последней проверки целостности; до первой проверки метрика не экспортируется |
sds_object_store_scrub_interval_seconds |
Настроенный интервал проверки целостности; при отключённой проверке метрика не экспортируется |
sds_object_store_redundancy_under_replicated |
У скольких единиц копий меньше, чем запрошено |
sds_object_store_integrity_unreachable_nodes |
Количество узлов хранения, недоступных во время последней проверки |
sds_object_store_redundancy_copies_wanted / _volumes |
Требуемое количество копий и количество учтённых единиц хранения |
sds_object_store_encryption_key_withheld |
1, пока сменившийся ключ шифрования не применяется |
Для этих метрик настроены следующие алерты:
D8SdsObjectStoreDataDamaged— последняя завершённая проверка обнаружила повреждение. Алерт срабатывает без дополнительной задержки.D8SdsObjectStoreUnderReplicated— количество копий ниже требуемого в течение 15 минут. Задержка исключает кратковременные срабатывания при плановом перезапуске volume-сервера.D8SdsObjectStoreEncryptionKeyWithheld— значение ключа шифрования изменилось, но модуль не применяет новый ключ, чтобы ранее записанные данные не стали недоступны после перезапуска S3-шлюза.D8SdsObjectStoreNotScrubbed— с последней завершённой проверки прошло более трёх интерваловspec.integrity.interval. Это позволяет обнаружить ситуацию, когда периодическая проверка перестала запускаться, хотя последний сохранённый результатIntegrityHealthyостаётся успешным. Если периодическая проверка отключена, метрика интервала не публикуется и этот алерт не применяется.
Дашборд Grafana SDS Object — Data integrity в директории Storage показывает количество хранилищ с повреждениями, недостаточной репликацией и просроченной проверкой, а также состояние каждого хранилища и время с момента последней проверки целостности.
Шифрование данных при хранении (encryption at rest)
Без spec.encryption содержимое объектов хранится на volume-серверах без серверного шифрования. Пользователь, получивший доступ к диску, сможет прочитать эти данные. Шифрование можно включить без изменений в приложениях, записывающих объекты.
Создайте Secret с ключевым материалом для шифрования:
# Создайте 32 байта ключевого материала. Сохраните резервную копию ключа вне кластера.
d8 k -n d8-sds-object create secret generic media-sse --from-literal=kek="$(head -c 32 /dev/urandom | xxd -p -c 32)"Пример создания SeaweedFSStore с включённым серверным шифрованием и указанным Secret:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: SeaweedFSStore
metadata:
name: media
spec:
storage:
class: linstor-thin-r2
encryption:
mode: ServerManaged
keySecretRef:
name: media-sse
EOFВместо kek Secret может содержать поле key с парольной фразой, из которой модуль получает ключ. Этот вариант подходит для внешних систем, которые предоставляют ключевой материал в строковом виде.
После включения шифрования модуль передаёт S3-шлюзу ключ из Secret и настраивает серверное шифрование для бакетов. Каждый объект шифруется отдельным ключом данных, который защищается ключом из Secret. Ключ из Secret не сохраняется в хранилище метаданных filer, поэтому доступ только к базе Postgres или PVC filer не позволяет расшифровать содержимое объектов.
Проверьте состояние шифрования:
d8 k get swfsstore media -o jsonpath='{.status.encryption}' | jqПример вывода:
{
"mode": "ServerManaged",
"keyFingerprint": "sha256:9c1f4a0b7e2d8536",
"since": "2026-08-25T09:12:04Z"
}
Смена ключа шифрования
Уже записанные объекты не перешифровываются автоматически. Если S3-шлюз запускается с другим ключом из Secret, чтение объектов, зашифрованных прежним ключом, завершается внутренней ошибкой сервера. Чтобы предотвратить потерю доступа к данным, модуль сравнивает отпечаток ключа и не применяет изменённый ключ без явного подтверждения.
Проверьте сообщение состояния условия EncryptionActive:
d8 k get swfsstore media -o jsonpath='{.status.conditions[?(@.type=="EncryptionActive")]}' | jq -r .messageПример вывода:
the wrapping key changed (sha256:9c1f4a0b7e2d8536 -> sha256:22ba07f6c4e1d980) and was NOT applied: ...
Пока состояние условия EncryptionActive — False, S3-шлюз продолжает использовать прежний ключ, с которым ранее записанные данные остаются доступными. Для восстановления штатного состояния верните исходный ключевой материал. Если данные, зашифрованные прежним ключом, больше не нужны, можно подтвердить использование нового ключа:
d8 k annotate swfsstore media storage.deckhouse.io/encryption-key-change-acknowledged=sha256:22ba07f6c4e1d980S3-шлюз считывает ключ при запуске. Поэтому изменение Secret само по себе не влияет на уже запущенный под, но без дополнительной проверки новый ключ был бы применён при следующем перезапуске и ранее зашифрованные объекты могли бы стать недоступны.
После включения spec.encryption.mode отключить серверное шифрование для существующего хранилища нельзя. Ранее зашифрованные объекты продолжают требовать исходный ключ. Чтобы перейти к хранилищу без серверного шифрования, создайте новое хранилище и перенесите в него данные.
Ограничения шифрования и SSE-C
Серверное шифрование имеет следующие ограничения и может использоваться вместе с клиентским шифрованием:
- Имена объектов, их размеры и теги не шифруются — только содержимое.
- Объекты, записанные до включения шифрования, не шифруются автоматически. Чтобы зашифровать их, загрузите данные заново после включения шифрования.
- Клиент может использовать собственный ключ (SSE-C). Ключ передаётся с каждым запросом и не сохраняется хранилищем. SSE-C не зависит от
spec.encryption. Используйте SSE-C через опубликованный TLS-эндпоинт: при обращении к внутреннему HTTP-эндпоинту ключ передаётся в заголовке без транспортного шифрования. - SSE-KMS для SeaweedFSStore не поддерживается. S3-шлюз читает конфигурацию KMS только из статического файла с учётными данными, что несовместимо с ключами, которые модуль создаёт для каждого BucketAccess. Для внешнего KMS используйте SDSElasticStore (Ceph RGW).
Шифрование в Ceph RGW
Для SDSElasticStore серверное шифрование требует внешней системы управления ключами (KMS). Ceph RGW получает ключи из KMS и не поддерживает передачу ключа непосредственно процессу RGW. В качестве KMS можно использовать Deckhouse Stronghold с transit engine.
Создайте Secret с токеном Stronghold:
# Токен, которому разрешено только чтение и использование transit-ключа.
d8 k -n d8-sds-object create secret generic rgw-stronghold-token --from-literal=token="$STRONGHOLD_TOKEN"Пример создания SDSElasticStore с указанным Secret и адресом Stronghold:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: SDSElasticStore
metadata:
name: heavy
spec:
elasticClusterRef: main
encryption:
mode: ServerManaged
stronghold:
address: https://stronghold.d8-stronghold.svc.cluster.local:8200
tokenSecretRef:
name: rgw-stronghold-token
# Для Stronghold с приватным сертификатом настройте CA Secret.
# caSecretRef:
# name: stronghold-ca
EOFПри настройке KMS для Ceph RGW учитывайте следующие особенности:
- Stronghold используется через Vault API. Rook получает
KMS_PROVIDER: vaultиVAULT_ADDR, поскольку Stronghold совместим с Vault API, который использует Ceph RGW. По той же схеме может работать другое Vault-совместимое хранилище. - Путь монтирования transit не настраивается. Для SSE-S3 Rook собирает префикс
RGW из одного имени движка (
/v1/transit), поэтому transit, смонтированный в другом месте, не будет использоваться этой конфигурацией. Используйте путьtransit. - Токен копируется в неймспейс
d8-sds-elastic. Rook ожидает Secret с токеном в неймспейсе CephObjectStore, поэтому модуль создаёт там управляемую копию Secret. При удалении хранилища копия также удаляется. После ротации исходного токена копия обновляется на следующем reconcile. Набор CA-сертификатов копируется аналогично: полеca.crtпреобразуется в ожидаемое Rook полеcert. - Для ключа KMS не сохраняется отпечаток в
status.encryption. Сам ключ хранится в Stronghold и не передаётся модулю, поэтому модуль не может вычислить его отпечаток или обнаружить замену ключа. Доступность ранее зашифрованных данных зависит от сохранности ключа в Stronghold.
status.encryption.message и состояние условия EncryptionActive отражают ошибки применения конфигурации шифрования в RGW, например отсутствие Secret с токеном. Для уже существующего хранилища остальные операции reconcile продолжаются. Новое хранилище с включённым шифрованием не создаётся до готовности конфигурации KMS, чтобы первые объекты не были записаны без шифрования.
Автоматическое удаление объектов
Для автоматического удаления устаревших логов, выгрузок и артефактов сборки используйте spec.lifecycle. Правила из spec.lifecycle применяются самим S3-бэкендом.
Пример создания Bucket с правилами удаления в spec.lifecycle:
d8 k apply -f - <<EOF
apiVersion: storage.deckhouse.io/v1alpha1
kind: Bucket
metadata:
namespace: team-a
name: build-logs
spec:
objectStoreRef: standard
lifecycle:
rules:
- id: logs
prefix: logs/
expireAfterDays: 30
- id: leftovers
abortIncompleteUploadsAfterDays: 1
EOFКаждое правило должно иметь уникальный id. Этот идентификатор передаётся в S3-бэкенд и используется для сопоставления правил при обновлении конфигурации. Он задаётся явно и не зависит от позиции правила в списке.
expireAfterDaysудаляет объект через столько дней после записи. На версионированном бакете это лишь делает текущую версию неактуальной — данные остаются, а место освобождаетexpireNoncurrentAfterDays.expireNoncurrentAfterDaysудаляет версию через столько дней после того, как она перестала быть текущей.abortIncompleteUploadsAfterDaysудаляет части незавершённых multipart-загрузок через заданное количество дней. Такие части занимают место, но не отображаются как обычные объекты.prefixограничивает действие правила объектами, ключи которых начинаются с указанного префикса. Еслиprefixне задан, правило применяется ко всем объектам бакета.
При каждом reconcile модуль формирует полный набор правил из spec.lifecycle и передаёт его в бэкенд. Если правило удалено из Bucket, оно также удаляется из конфигурации бакета в бэкенде.
Object Lock имеет приоритет над удалением по правилам spec.lifecycle. Если для версии действует срок хранения, правило из spec.lifecycle не сможет удалить её до окончания срока хранения.
Переходы между классами хранения не поддерживаются. В текущем API через spec.lifecycle доступны только операции удаления. SeaweedFS 4.39 поддерживает истечение по дням и дате, удаление неактуальных версий, ограничения newer-noncurrent, отмену незавершённых загрузок и удаление маркеров удаления, но не поддерживает действие Transition. Ceph RGW умеет переносить объекты между классами хранения, однако общий для обоих бэкендов параметр перехода пока не предоставляется.
Поддержка операций S3
SeaweedFS и Ceph RGW поддерживают разные наборы S3-операций. Перед использованием функции приложения проверьте её поддержку в выбранном бэкенде.
Таблица основана на реализации S3 API в SeaweedFS 4.39 и на матрице поддержки Ceph RGW версии, используемой модулем sds-elastic. Это возможности самих бэкендов, а не дополнительная реализация модуля sds-object. При обновлении версий бэкендов таблица требует повторной проверки.
| SeaweedFS 4.39 | Ceph RGW (Squid) | |
|---|---|---|
| Создание / удаление / HEAD бакета, расположение бакета | Да | Да |
| Листинг объектов (v1, v2), листинг версий | Да | Да |
| PUT / GET / HEAD / DELETE объекта, множественное удаление, копирование | Да | Да |
GetObjectAttributes |
Да | Да |
| Multipart-загрузка (create, upload, upload-part-copy, complete, abort, list) | Да | Да |
| POST-загрузка формой | Да | Да |
| Теги объектов, теги бакетов | Да | Да |
| Списки контроля доступа (ACL) бакетов и объектов | Да | Да, другой набор предопределённых ACL |
| Политика бакета (get, put, delete) | Да | Да |
| CORS | Да | Да |
| Lifecycle (get, put, delete) | Да | Да |
| Версионирование | Да | Да |
| Object Lock: конфигурация бакета, срок хранения, бессрочная блокировка удаления | Да | Да |
| Шифрование бакета по умолчанию (SSE-S3) | Да, только под админскими ключами | Да |
| Public access block, ownership controls | Да | Да |
| Request payment | Принимается, только BucketOwner, нигде не сохраняется |
Да |
| Класс хранения | Нет | Да |
| Уведомления бакета | Нет | Да |
| Bucket website | Нет | Да |
| Репликация бакета | Нет | Только между зонами |
RestoreObject, SelectObjectContent |
Нет | Нет |
Частично реализованные операции SeaweedFS. Некоторые S3-эндпоинты отвечают успешно, но не сохраняют конфигурацию. Например, accelerate всегда возвращает Suspended, логирование бакета возвращает пустой статус, а списки analytics, inventory, intelligent-tiering и metrics остаются пустыми. Ответ 200 для этих операций подтверждает обработку запроса, но не наличие соответствующей функции.
Какими функциями управляет модуль. Модуль настраивает создание бакета, политику бакета для accessPolicy, квоты, версионирование, Object Lock и шифрование по умолчанию. Остальные S3-операции выполняются непосредственно между приложением и бэкендом; модуль их не настраивает и не отслеживает.
Если запрошенная возможность не поддерживается выбранным бэкендом, BucketContents отражает это в состоянии условия FeaturesApplied.
Пример состояния условия FeaturesApplied:
FeaturesApplied False Unsupported
backend SeaweedFS does not enforce: quota.maxObjects
Таблица выше описывает общие возможности бэкендов, а состояние условия FeaturesApplied показывает результат применения запрошенных настроек к конкретному бакету.
Диагностика
Каждый объект содержит общее состояние в status.phase, а подробная причина текущего состояния отражается в status.conditions:
Pending— контроллер ещё не обработал объект или ожидает результат от зависимого этапа.InProgress— обработка идёт: стадия начата, но ещё не подтвердила успех.Ready— все стадии подтвердили успех. Данные Bucket, учётные данные BucketAccess и эндпоинт хранилища актуальны только в этой фазе.Error— один из этапов обработки завершился с ошибкой; причина указана вmessageсоответствующего условия вstatus.conditions.Released(только для BucketContents) — связанный Bucket удалён приreclaimPolicy: Retain; данные сохраняются и будут повторно связаны с Bucket с тем же именем в том же неймспейсе.
Чтобы увидеть подробности, выполните:
d8 k get bucket app-data -n my-app -o jsonpath='{.status.conditions}'Типичные сообщения, где они появляются и что делать:
| Сообщение | Где | Причина | Что делать |
|---|---|---|---|
spec.objectStoreRef is immutable after creation. |
Admission-вебхук, Bucket | Попытка сменить класс после создания | Создайте новый Bucket, указав нужный класс |
spec.bucketRef is immutable after creation. |
Admission-вебхук, BucketAccess | Попытка перенаправить доступ на другой бакет | Создайте новый BucketAccess |
spec.storeRef.kind "X" is not a store kind this module implements; known kinds: ... |
Admission-вебхук, ObjectStore | Опечатка или неподдерживаемый бэкенд в storeRef.kind |
Укажите SeaweedFSStore или SDSElasticStore |
spec.quota.maxSize/maxObjects ... exceeds the ... allowed by ObjectStore "X" |
Admission-вебхук, Bucket | Запрошенная квота выше потолка класса | Уменьшите квоту Bucket либо увеличьте квоту класса |
<KIND> "X" is not available / is not Ready (reason WaitingForStore) |
status.conditions BucketContents |
Хранилище, на которое ссылается ObjectStore.spec.storeRef, ещё не создано или не Ready |
Сначала проверьте хранилище, например d8 k get seaweedfsstore/sdselasticstore |
Bucket "X" is not Bound to contents (reason WaitingForBucket) |
status.conditions BucketAccess |
Учётные данные запрошены до того, как состояние условия Bound у Bucket стало True |
Дождитесь Bucket; действий не требуется |
BucketContents "X" already exists and is not owned by this Bucket; refusing to adopt it (reason ContentsNameTaken) |
Условие Bound в status.conditions Bucket |
Производное имя занято чужим или ранее Released BucketContents |
Изучите его через d8 k get bktc X -o yaml; удаляйте только если он действительно осиротел |
backend <DRIVER> does not enforce: publicRead, maxObjects (состояние условия FeaturesApplied) |
status.conditions BucketContents |
Запрошенные accessPolicy/quota.maxObjects не реализованы этим бэкендом |
Информационное сообщение — не блокирует Ready; подробнее в «Ограничениях» |
spec.replication must be 00z: ... / spec.volumeServers can only be increased ... / spec.filers above 1 requires spec.metadataStore: Postgres |
Admission-вебхук, SeaweedFSStore | Собственные настройки хранилища (число компонентов и код репликации) друг другу противоречат | Согласуйте значения, как описано выше в разделе «Создание хранилища» |