Использование Piraeus Datastore в Kubernetes кластере

Piraeus Datastore — это open-source решение для управления распределённым хранилищем в Kubernetes, построенное на базе LINSTOR и DRBD. Оно предоставляет CSI-интерфейс и поддерживает динамическое создание томов, репликацию, снапшоты и резервное копирование в облачные хранилища, включая S3.

1. Подготовка кластера Kubernetes

Для начала работы вам потребуется созданный кластер по крайней мере с одним узлом и подключенным к нему дополнительным диском. В данном примере будет рассмотрен кластер с тремя узлами ищущими метку csi-type=piraeus.

Если вы не указали метки при создании группы узлов, можете добавить их внучную:

kubectl label nodes worker-1 worker-2 worker-3 csi-type=piraeus

2. Установка Piraeus Datastore

2.1 Установка через манифест

kubectl apply --server-side -f "https://github.com/piraeusdatastore/piraeus-operator/releases/latest/download/manifest.yaml"

Проверим статус подов:

kubectl get pods -n piraeus-datastore
NAME                                                  READY   STATUS    RESTARTS   AGE
piraeus-operator-controller-manager-7d786569f-v9rlp   1/1     Running   0          2m41s
piraeus-operator-gencert-86b9d78f75-spl57             1/1     Running   0          2m41s

3. Настройка LINSTOR-кластера и саттелитов

3.1 Создание секрета с парольной фразой

LINSTOR будет использовать этот секрет при создании зашифрованных томов, а так же для сохранения реквизитов доступа для сохранения резервных копий

ВАЖНО: замените значение MASTER_PASSPHRASE на надёжную фразу!

kubectl apply -f - <<EOF
---
apiVersion: v1
kind: Secret
metadata:
  name: linstor-passphrase
  namespace: piraeus-datastore
stringData:
  MASTER_PASSPHRASE: B4dd_Ex4Mple_Pa$$PHr4ze
EOF

3.2 Создание LinstorCluster

kubectl apply -f - <<EOF
apiVersion: piraeus.io/v1
kind: LinstorCluster
metadata:
  name: linstorcluster
spec:
  linstorPassphraseSecret: linstor-passphrase
  nodeAffinity:
    nodeSelectorTerms:
      - matchExpressions:
          - key: csi-type
            operator: In
            values:
              - piraeus
  highAvailabilityController:
    enabled: false
  nfsServer:
    enabled: false
  csiNode:
    enabled: true
    podTemplate:
      spec:
        containers:
        - name: linstor-csi
          volumeMounts:
          - mountPath: /var/lib/k0s/kubelet
            mountPropagation: Bidirectional
            name: publish-dir
        - args:
          - --v=5
          - --csi-address=/csi/csi.sock
          - --kubelet-registration-path=/var/lib/k0s/kubelet/plugins/linstor.csi.linbit.com/csi.sock
          - --health-port=9809
          name: csi-node-driver-registrar
        volumes:
        - hostPath:
            path: /var/lib/k0s/kubelet
          name: publish-dir
        - hostPath:
            path: /var/lib/k0s/kubelet/plugins_registry
          name: registration-dir
        - hostPath:
            path: /var/lib/k0s/kubelet/plugins/linstor.csi.linbit.com
          name: plugin-dir
EOF

3.3 Настройка LinstorSatelliteConfiguration — использование /dev/vdb

kubectl apply -f - <<'EOF'
apiVersion: piraeus.io/v1
kind: LinstorSatelliteConfiguration
metadata:
  name: storage-satellites
spec:
  podTemplate:
    spec:
      # Отключаем автоматическую загрузку DRBD-модуля (если он уже есть)
      initContainers:
        - name: drbd-module-loader
          $patch: delete
  nodeAffinity:
    nodeSelectorTerms:
      - matchExpressions:
          - key: csi-type
            operator: In
            values:
             - piraeus
  storagePools:
    - name: vg1
      lvmThinPool:
        volumeGroup: vg1
      source:
        hostDevices:
          - /dev/vdb
EOF

О типах хранилищ в LINSTOR
LINSTOR поддерживает следующие типы storage pools (определяются в LinstorSatelliteConfiguration):

Тип пула Описание Особенности
lvmPool Классический LVM Volume Group (thick) — По умолчанию использует storage pool name как имя VG
— Можно переопределить через volumeGroup: <vg-name>
— Выделение места — full/dense
lvmThinPool LVM Thin Pool (thin LVM) — По умолчанию: VG = linstor_<pool-name>, LV = <pool-name>
— Можно переопределить volumeGroup, thinPool
— Экономия места, поддержка снапшотов и быстрое создание томов
filePool Файловое хранилище (каждому тому — файл в FS) — По умолчанию: /var/lib/linstor-pools/<pool-name>
— Подходит для отладки и лёгких нагрузок
fileThinPool Тонкое (sparse) файловое хранилище — Поведение как filePool, но файлы создаются sparse (разрежённые)
— Требует поддержки sparse файлов (XFS, ext4 с опцией sparse)
zfsPool ZFS ZPool (thick zVol) — По умолчанию использует pool name как имя zpool
— Можно переопределить через zPool: <zpool-name>
zfsThinPool ZFS ZPool с sparse zVol — Поведение как zfsPool, но тома создаются sparse (reservation=0)
— Подходит для экономии места на ZFS

Дождемся заверщения запуска подов в неймспейсе piraeus-datastore и проверим статус саттелитов:

kubectl -n piraeus-datastore exec -it deployments/linstor-controller -- linstor storage-pool list
[ ... таблица без emoji ... ]

На каждом из узлов на дополнительных дисках был инициализирован LVM. Приступим к выделению PV


4. Динамическое выделение PV и создание PVC

4.1 Создание StorageClass

kubectl apply -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: piraeus-storage-lvm
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: linstor.csi.linbit.com
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
parameters:
  linstor.csi.linbit.com/storagePool: "vg1"
  linstor.csi.linbit.com/layerList: "storage"
EOF

Проверим:

kubectl get storageclass
NAME                            PROVISIONER              RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
piraeus-storage-lvm (default)   linstor.csi.linbit.com   Delete          WaitForFirstConsumer   true                   10s

4.2 Создание PVC

kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-piraeus
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  namespace: nginx-piraeus
  name: nginx-piraeus
spec:
  storageClassName: piraeus-storage-lvm
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 2Gi
EOF

4.3 Создание Pod и сервиса

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  namespace: nginx-piraeus
  name: nginx-piraeus
spec:
  containers:
  - name: nginx
    image: library/nginx:1.28-alpine
    ports:
    - containerPort: 80
    volumeMounts:
      - mountPath: "/var/www/html"
        name: data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: nginx-piraeus
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-piraeus
  namespace: nginx-piraeus
spec:
  selector:
    app.kubernetes.io/name: nginx-piraeus
  ports:
    - port: 80
      targetPort: 80
  type: LoadBalancer
EOF

4.4 Проверка созданных ресурсов

Проверим состояние PVC:

kubectl get pvc -n nginx-piraeus
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          VOLUMEATTRIBUTESCLASS   AGE
nginx-piraeus   Bound    pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66   2Gi        RWO            piraeus-storage-lvm   <unset>                 2m18s

Проверим PV:

kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                         STORAGECLASS          VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66   2Gi        RWO            Delete           Bound    nginx-piraeus/nginx-piraeus   piraeus-storage-lvm   <unset>                          80s

Уточним размещение Persistent Volume:

kubectl describe pvc -n nginx-piraeus nginx-piraeus | grep volume.kubernetes.io/selected-node:
        volume.kubernetes.io/selected-node: worker-3

Проверим состояние LV на узле, где был размещен Persistent Volume:

kubectl -n piraeus-datastore exec pods/linstor-satellite.worker-3-bdhng -- lvs
LV                                             VG  Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000 vg1 Vwi-aotz-- 2.00g vg1         4.76                                   
vg1                                            vg1 twi-aotz-- 9.97g             0.96   10.90  

Проверим Pod и Service:

kubectl get -n nginx-piraeus pods,svc
NAME                READY   STATUS    RESTARTS   AGE
pod/nginx-piraeus   1/1     Running   0          92s

NAME                    TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
service/nginx-piraeus   LoadBalancer   10.96.28.209   172.16.100.251   80:30539/TCP   92s

Проверим монтирование и файловую систему внутри контейнера:

kubectl -n nginx-piraeus exec -it pods/nginx-piraeus -- df -h /var/www/html
Filesystem                Size      Used Available Use% Mounted on
/dev/mapper/vg1-pvc--deaf559a--6e96--4a3f--801f--bc56eb165c66_00000
1.9G     24.0K      1.8G   0% /var/www/html

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

kubectl -n nginx-piraeus exec -it pods/nginx-piraeus -- grep www /proc/mounts
/dev/mapper/vg1-pvc--deaf559a--6e96--4a3f--801f--bc56eb165c66_00000 /var/www/html ext4 rw,relatime,stripe=16 0 0

Как видим, Persistent Volume был успешно создан и подключен к созданному поду


5. Создание и восстановление снапшотов

Важное примечание: до создания VolumeSnapshotClass необходимо установить CRD и snapshot-контроллер, который обеспечивает поддержку снапшотов в Kubernetes:

5.1 Установка CRD и контроллера снапшотов

kubectl apply -k https://github.com/kubernetes-csi/external-snapshotter/client/config/crd
kubectl apply -k https://github.com/kubernetes-csi/external-snapshotter/deploy/kubernetes/snapshot-controller

Проверим, что контроллер запущен:

kubectl get pods -n kube-system | grep snapshot-controller
snapshot-controller-65b49c865c-vbr8l       1/1     Running   0          1m24s
snapshot-controller-65b49c865c-z5g77       1/1     Running   0          1m24s

5.2 Класс снапшотов для локального хранения (без S3)

kubectl apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: piraeus-snapshots
  namespace: piraeus-datastore
driver: linstor.csi.linbit.com
deletionPolicy: Delete
EOF

5.3 Создание снапшота

kubectl apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: nginx-piraeus
  namespace: nginx-piraeus
spec:
  volumeSnapshotClassName: piraeus-snapshots
  source:
    persistentVolumeClaimName: nginx-piraeus
EOF

Проверим:

kubectl get volumesnapshot -n nginx-piraeus
NAME            READYTOUSE   SOURCEPVC       SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS       SNAPSHOTCONTENT                                    CREATIONTIME   AGE
nginx-piraeus   true         nginx-piraeus                           2Gi           piraeus-snapshots   snapcontent-efe15b67-cbd1-4fef-ac5a-c39a215db2e9   5s             7s

kubectl -n piraeus-datastore exec pods/linstor-satellite.worker-3-bdhng -- lvs
  LV                                                                                           VG  Attr       LSize Pool Origin                                         Data%  Meta%  Move Log Cpy%Sync Convert
  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000                                               vg1 Vwi-aotz-- 2.00g vg1                                                 4.76                                   
  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000_snapshot-efe15b67-cbd1-4fef-ac5a-c39a215db2e9 vg1 Vri-a-tz-k 2.00g vg1  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000 4.76                                   
  vg1                                                                                          vg1 twi-aotz-- 9.97g                                                     0.96   10.97   

5.4 Восстановление PVC из снапшота

kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-piraeus-v2
  namespace: nginx-piraeus
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 2Gi
  dataSource:
    apiGroup: snapshot.storage.k8s.io
    kind: VolumeSnapshot
    name: nginx-piraeus
EOF

5.5 Пересоздамим под с использованием нового PVC

kubectl delete pod nginx-piraeus -n nginx-piraeus

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  namespace: nginx-piraeus
  name: nginx-piraeus
spec:
  containers:
  - name: nginx
    image: library/nginx:1.28-alpine
    ports:
    - containerPort: 80
    volumeMounts:
      - mountPath: "/var/www/html"
        name: data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: nginx-piraeus-v2
EOF

Проверим блочные устройства на worker-узле:

kubectl -n piraeus-datastore exec pods/linstor-satellite.worker-3-bdhng -- lvs
  LV                                                                                           VG  Attr       LSize Pool Origin                                                                                       Data%  Meta%  Move Log Cpy%Sync Convert
  pvc-25263fd1-ed50-4da7-bf8a-8685c5cb4e52_00000                                               vg1 Vwi-aotz-k 2.00g vg1  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000_snapshot-efe15b67-cbd1-4fef-ac5a-c39a215db2e9 4.76                                   
  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000                                               vg1 Vwi-a-tz-- 2.00g vg1                                                                                               4.76                                   
  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000_snapshot-efe15b67-cbd1-4fef-ac5a-c39a215db2e9 vg1 Vri-a-tz-k 2.00g vg1  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000                                               4.76                                   
  vg1                                                                                          vg1 twi-aotz-- 9.97g                                                                                                   0.96   11.07                      

5.6 Удалим созданный ранее снапшот

И снова проверим уструктуру Logical Volume

kubectl delete volumesnapshot -n nginx-piraeus nginx-piraeus
kubectl -n piraeus-datastore exec pods/linstor-satellite.worker-3-bdhng -- lvs
volumesnapshot.snapshot.storage.k8s.io "nginx-piraeus" deleted
  LV                                             VG  Attr       LSize Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  pvc-25263fd1-ed50-4da7-bf8a-8685c5cb4e52_00000 vg1 Vwi-aotz-k 2.00g vg1         4.76                                   
  pvc-deaf559a-6e96-4a3f-801f-bc56eb165c66_00000 vg1 Vwi-a-tz-- 2.00g vg1         4.76                                   
  vg1                                            vg1 twi-aotz-- 9.97g             0.96   11.00  

6. Загрузка снапшотов в S3

6.1 Настройка доступа к S3

Создадим Secret с учетными данными и VolumeSnapshotClass для S3:

kubectl apply -f - <<EOF
---
apiVersion: v1
kind: Secret
metadata:
  name: linstor-csi-s3-access
  namespace: piraeus-datastore
immutable: true
type: linstor.csi.linbit.com/s3-credentials.v1
stringData:
  access-key: YOUR_AWS_ACCESS_KEY_ID
  secret-key: YOUR_AWS_SECRET_ACCESS_KEY
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: piraeus-snapshots-s3
driver: linstor.csi.linbit.com
deletionPolicy: Delete
parameters:
  snap.linstor.csi.linbit.com/type: S3
  snap.linstor.csi.linbit.com/remote-name: example
  snap.linstor.csi.linbit.com/delete-local: "true"
  snap.linstor.csi.linbit.com/allow-incremental: "false"
  snap.linstor.csi.linbit.com/s3-bucket: piraeus-backups
  snap.linstor.csi.linbit.com/s3-endpoint: s3.example.com
  snap.linstor.csi.linbit.com/s3-signing-region: ru-1
  snap.linstor.csi.linbit.com/s3-use-path-style: "true"
  csi.storage.k8s.io/snapshotter-secret-name: linstor-csi-s3-access
  csi.storage.k8s.io/snapshotter-secret-namespace: piraeus-datastore
EOF

Замените имя бакета, точку подключения, и учетные данные на свои.

6.2 Создание и загрузка снапшота в S3

kubectl apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: nginx-piraeus-s3
  namespace: nginx-piraeus
spec:
  volumeSnapshotClassName: piraeus-snapshots-s3
  source:
    persistentVolumeClaimName: nginx-piraeus
EOF

Проверим статус снапшота — readyToUse: true означает успешную загрузку в S3:

kubectl get volumesnapshot -n nginx-piraeus nginx-piraeus-s3
NAME            READYTOUSE   SOURCEPVC       SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS          SNAPSHOTCONTENT                                    CREATIONTIME   AGE
nginx-piraeus   true         nginx-piraeus                           2Gi           piraeus-snapshots-s3   snapcontent-c7aa2b19-8331-47d1-a549-4c615d60bb46   3m10s          3m10s

6.3 Восстановление PVC из снапшота в S3

Используем тот же VolumeSnapshot, что и выше:

kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-piraeus-from-s3
  namespace: nginx-piraeus
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 2Gi
  dataSource:
    apiGroup: snapshot.storage.k8s.io
    kind: VolumeSnapshot
    name: nginx-piraeus-s3
EOF

Важно: если в VolumeStorageClass параметр delete-local установлен в значение true, то локальный снапшот удаляется после загрузки данных в S3 — он будет восстановлен из облака при создании PVC.


Заключение

Piraeus Datastore — это зрелое и гибкое решение для распределённого и локального хранения в Kubernetes:

  • Простая установка через манифест и Helm-чарты

  • Гибкая настройка саттелитов под любые конфигурации дисков

  • Динамическое создание PV/PVC через CSI

  • Локальные и облачные снапшоты с поддержкой загрузки в S3

Благодаря S3-интеграции вы можете не только быстро восстанавливать тома из снапшотов, но и обеспечивать длительное хранение и трансферные точки восстановления в облаке. ```

Нам доверяют тысячи компаний и разработчиков

22 года
Предоставляем услуги профессионального хостинга
35 000+
Клиентов доверяют нам размещение своих сайтов
99.99%
Подтвержденный uptime наших серверов хостинга
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
Наши клиенты
ВК49865