k8s/research/minio.md
2026-07-15 11:14:21 +03:00

31 KiB
Raw Permalink Blame History

MinIO в Kubernetes: объектное хранилище 1 ТБ с веб-интерфейсом

Кластер: Rocky Linux 9 · Kubernetes 1.33 · Flannel CNI
Текущая топология: k8s-manager-01 (10.203.0.92) · k8s-master-01 (10.203.0.97) · k8s-worker-01 (10.203.0.96)
Дата исследования: 2026-05-28
Проверено на кластере: 2026-05-28 (kubectl + Longhorn API)


Содержание

  1. Обзор и назначение
  2. Режимы развёртывания
  3. Планирование хранилища 1 ТБ
  4. Helm-развёртывание (standalone)
  5. MinIO Console: веб-интерфейс
  6. Интеграция с Traefik
  7. Безопасность: пользователи и политики
  8. Интеграция с Loki (S3 backend)
  9. Ansible-роль и плейбук
  10. Масштабирование до distributed-режима
  11. Итоги и рекомендации

1. Обзор и назначение

MinIO — S3-совместимое объектное хранилище. Работает в Kubernetes как StatefulSet или Deployment, предоставляет:

  • S3 API (порт 9000) — совместим с любым клиентом AWS SDK, boto3, mc, s3cmd
  • MinIO Console (порт 9001) — встроенный веб-интерфейс: браузер объектов, управление пользователями, мониторинг

Сценарии использования в текущем кластере

Сценарий Описание
Loki S3 backend Хранилище chunks/index при переходе на distributed Loki
Бэкапы баз данных S3-target для pg_dump, mysqldump, Velero
Артефакты CI/CD GitLab Runner cache, артефакты сборки
Файловое хранилище Статика, медиафайлы приложений
Резервные копии etcd Автоматические снэпшоты control plane

2. Режимы развёртывания

Текущее состояние кластера (проверено)

Longhorn-диски на k8s-worker-01:
  longhorn-disk1  /mnt/longhorn-disk1  ~4.09 TiB  (свободно ~4.06 TiB)  allowScheduling=true
  longhorn-disk2  /mnt/longhorn-disk2  ~4.09 TiB  (свободно ~4.06 TiB)  allowScheduling=true

k8s-master-01: диск из Longhorn удалён — нода без дисков, в планировании не участвует ✓

StorageClass longhorn (default):
  numberOfReplicas: 1  ✓
  allowVolumeExpansion: true
  createDefaultDiskLabeledNodes: true

Traefik hostPort (занято): 10001 (k8s-dashboard), 10002 (longhorn-ui)
Traefik hostPort (свободно): 10003+  → MinIO: 10005 (API), 10006 (Console)

Standalone (текущий кластер — 1 worker)

┌─────────────────────────────────────────────────────────────┐
│  k8s-worker-01 (10.203.0.96)                               │
│                                                             │
│  [MinIO Pod — StatefulSet 1 replica]                       │
│   ├── порт 9000 (S3 API)                                   │
│   └── порт 9001 (Console UI)                               │
│            ↓                                               │
│   [PVC 1 TiB → StorageClass longhorn-minio]               │
│   [Longhorn → longhorn-disk1 (/mnt/longhorn-disk1, 4 TiB)] │
└─────────────────────────────────────────────────────────────┘
                    ↓ ClusterIP
          ┌─────────────────────┐
          │ Traefik             │
          │ 10005 → API :9000  │
          │ 10006 → UI  :9001  │
          └─────────────────────┘

Ограничения standalone: нет erasure coding. Потеря диска = потеря данных. Приемлемо при наличии Longhorn-снэпшотов по расписанию.

SNMD — Single Node Multi-Drive (будущее)

Worker уже имеет два диска (~4 TiB каждый). MinIO поддерживает SNMD начиная с 4 дисков. При добавлении ещё двух дисков к worker-ноде можно перейти на SNMD без новых нод:

MinIO SNMD, 4 диска по ~1 TiB (из доступных 4 TiB на каждом диске):
  - usable storage ≈ 2 TiB (EC:2 — паритет 50%)
  - допустимая потеря: 2 из 4 дисков

Distributed (4+ нод)

При добавлении worker-нод: 1 под MinIO на ноду, PVC через Longhorn на каждой. Требует минимум 4 пода (4 ноды) для полноценного erasure coding.

Для текущего кластера (1 worker, 2 диска) — только standalone.


3. Планирование хранилища 1 ТБ

Реальная конфигурация дисков (проверено)

На k8s-worker-01 уже настроены два Longhorn-диска:

Диск Путь Всего Свободно Статус
longhorn-disk1 /mnt/longhorn-disk1 ~4.09 TiB ~4.06 TiB Ready, Schedulable
longhorn-disk2 /mnt/longhorn-disk2 ~4.09 TiB ~4.06 TiB Ready, Schedulable

Оба диска полностью свободны. PVC 1 TiB займёт ~25% одного диска, оставляя ~3 TiB в резерве на том же диске.

Выделенный StorageClass для MinIO

Дефолтный longhorn (numberOfReplicas: 1) технически подойдёт, но для MinIO рекомендуется отдельный StorageClass по двум причинам:

  • reclaimPolicy: Retain — при случайном удалении namespace или PVC данные на диске не уничтожаются (дефолтный Longhorn использует Delete)
  • diskSelector — позволяет зафиксировать MinIO на longhorn-disk1, оставив longhorn-disk2 для других workload (Loki, бэкапы и т.д.)
# применить через роль minio/tasks/storageclass.yml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-minio
provisioner: driver.longhorn.io
reclaimPolicy: Retain          # данные остаются при удалении PVC
allowVolumeExpansion: true
parameters:
  numberOfReplicas: "1"
  dataLocality: "best-effort"
  diskSelector: "minio"        # тег только на longhorn-disk1
  fsType: "ext4"
  dataEngine: "v1"

Disk-тег для изоляции MinIO на disk1 (опционально)

Если нужно зафиксировать MinIO именно на longhorn-disk1 (рекомендуется при нескольких workload):

kubectl -n longhorn-system patch node.longhorn.io k8s-worker-01 --type=json -p='[
  {"op":"add","path":"/spec/disks/longhorn-disk1/tags","value":["minio"]}
]'

Без тега Longhorn выберет любой из двух дисков (disk1 или disk2) — это тоже корректно, просто менее предсказуемо.

Репликация на уровне Longhorn

Сейчас: numberOfReplicas: 1 — без репликации. При добавлении второго worker с Longhorn-дисками поднять до 2 — Longhorn начнёт реплицировать PVC MinIO между нодами без остановки пода.

Важно: репликация Longhorn защищает от потери ноды, но не заменяет MinIO distributed mode. Longhorn реплицирует блочное устройство целиком, erasure coding MinIO работает на уровне объектов.

Расчёт полезной ёмкости

Физический диск (longhorn-disk1) — ~4.09 TiB. MinIO получает PVC 1 TiB — остаток диска доступен для других PVC.

Параметр Значение
Физический диск ~4.09 TiB (longhorn-disk1)
PVC для MinIO 1 TiB
Overhead Longhorn + ext4 ~2%
Overhead MinIO (метаданные) ~1%
Доступно для объектов ~990 Gi
Рекомендуемый порог заполнения 80% → ~790 Gi
Остаток на диске для других PVC ~3.09 TiB

MinIO по умолчанию отказывается принимать данные при заполнении > 95% (настраивается через MINIO_STORAGE_CLASS_STANDARD).


4. Helm-развёртывание (standalone)

Helm chart

Используется официальный chart minio/minio (не bitnami — он добавляет лишние зависимости).

helm repo add minio https://charts.min.io/
helm repo update

minio-values.yml

# roles/minio/files/minio-values.yml

## Режим: standalone
mode: standalone

## Образ
image:
  repository: quay.io/minio/minio
  tag: RELEASE.2025-04-22T22-12-26Z   # фиксированная версия
  pullPolicy: IfNotPresent

## Корневые учётные данные (переопределяются через Secret)
existingSecret: minio-root-credentials

## Хранилище
persistence:
  enabled: true
  storageClass: longhorn-minio   # выделенный SC: numberOfReplicas=1, только worker-диски
  accessMode: ReadWriteOnce
  size: 1Ti

## Ресурсы пода
resources:
  requests:
    memory: 512Mi
    cpu: 250m
  limits:
    memory: 2Gi
    cpu: 1000m

## Привязка к worker-ноде (не запускать на control plane)
nodeSelector:
  node-role.kubernetes.io/control-plane: ""   # исключить
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: node-role.kubernetes.io/control-plane
              operator: DoesNotExist

## Сервисы
service:
  type: ClusterIP
  port: 9000

consoleService:
  type: ClusterIP
  port: 9001

## Buckets создаются автоматически при старте
buckets:
  - name: loki-chunks
    policy: none
    purge: false
  - name: backups
    policy: none
    purge: false
  - name: artifacts
    policy: none
    purge: false

## Пользователи (пароли — через Secret, задаются ниже)
users:
  - accessKey: loki
    existingSecret: minio-user-loki
    existingSecretKey: secretKey
    policy: readwrite
  - accessKey: backup
    existingSecret: minio-user-backup
    existingSecretKey: secretKey
    policy: readwrite

## Политики для бакетов
policies:
  - name: loki-policy
    statements:
      - resources:
          - "arn:aws:s3:::loki-chunks"
          - "arn:aws:s3:::loki-chunks/*"
        actions:
          - "s3:GetObject"
          - "s3:PutObject"
          - "s3:DeleteObject"
          - "s3:ListBucket"

## Метрики (если Prometheus есть)
metrics:
  serviceMonitor:
    enabled: false   # включить когда появится Prometheus

## MinIO Console — веб-интерфейс
consoleIngress:
  enabled: false   # используем Traefik напрямую через ClusterIP

## Окружение MinIO
environment:
  MINIO_BROWSER_REDIRECT_URL: "http://10.203.0.96:10006"   # URL Console через Traefik
  MINIO_STORAGE_CLASS_STANDARD: "EC:0"                      # standalone: без erasure coding
  MINIO_UPDATE: "off"                                        # отключить автообновление

Secret с корневыми учётными данными

kubectl create secret generic minio-root-credentials \
  --from-literal=rootUser=minioadmin \
  --from-literal=rootPassword='СИЛЬНЫЙ_ПАРОЛЬ_МИНИМУМ_8_СИМВОЛОВ' \
  -n minio

Установка

kubectl create namespace minio

helm upgrade --install minio minio/minio \
  --namespace minio \
  --version 5.4.0 \
  --values roles/minio/files/minio-values.yml \
  --wait

Проверка

# Статус пода
kubectl get pod -n minio

# Логи
kubectl logs -n minio -l app=minio

# Проброс порта для быстрой проверки
kubectl port-forward -n minio svc/minio 9000:9000 &
kubectl port-forward -n minio svc/minio-console 9001:9001 &

# Проверка S3 API через mc (MinIO Client)
mc alias set local http://localhost:9000 minioadmin ПАРОЛЬ
mc ls local
mc admin info local

5. MinIO Console: веб-интерфейс

MinIO Console — встроенный React-интерфейс, запускается в том же поде на порту 9001. Отдельная установка не нужна начиная с MinIO RELEASE.2021-07-08.

Возможности Console

Раздел Функции
Object Browser Навигация по бакетам, загрузка/скачивание файлов, просмотр метаданных
Buckets Создание бакетов, версионирование, lifecycle policies, replication
Identity → Users Создание пользователей, назначение политик
Identity → Groups Группировка пользователей
Identity → Policies Редактор IAM-политик (JSON)
Monitoring Дашборд загрузки, IOPS, throughput в реальном времени
Logs Потоковый просмотр логов MinIO в браузере
Audit Журнал операций (включается через MINIO_AUDIT_WEBHOOK_*)

Настройка адреса Console

MinIO Console проверяет MINIO_BROWSER_REDIRECT_URL при формировании redirect после логина. Без правильного значения Console вернёт 401 или redirect на неверный URL.

# В minio-values.yml — уже задано выше
environment:
  MINIO_BROWSER_REDIRECT_URL: "http://10.203.0.96:10006"

6. Интеграция с Traefik

Два порта в traefik_port_map:

  • 10005 — MinIO S3 API (для клиентов, boto3, mc)
  • 10006 — MinIO Console (веб-интерфейс)

Добавить в inventory/prod/group_vars/traefik.yml

traefik_port_map:
  # ... существующие записи ...

  - name: minio-api
    description: "MinIO S3 API"
    port: 10005
    backend:
      namespace: minio
      service: minio
      port: 9000
      scheme: http
    basicauth:
      enabled: false   # MinIO использует собственную аутентификацию (AWS Signature v4)

  - name: minio-console
    description: "MinIO Console (Web UI)"
    port: 10006
    backend:
      namespace: minio
      service: minio-console
      port: 9001
      scheme: http
    basicauth:
      enabled: false   # MinIO Console имеет собственный логин

Важно: BasicAuth от Traefik + MinIO Console не совместимы — браузер не может пройти двойную аутентификацию. MinIO Console защищён своим логином, этого достаточно.

После добавления запустить setup_traefik.yml.

Адреса после развёртывания

Сервис URL Назначение
MinIO S3 API http://10.203.0.96:10005 Внешний доступ клиентов
MinIO Console http://10.203.0.96:10006 Веб-интерфейс администратора
MinIO API (внутри кластера) http://minio.minio.svc.cluster.local:9000 Для подов кластера
MinIO Console (внутри кластера) http://minio-console.minio.svc.cluster.local:9001

Настройка mc (MinIO Client) для внешнего доступа

# На manager-ноде или локально
mc alias set prod http://10.203.0.96:10005 minioadmin ПАРОЛЬ

# Проверка
mc ls prod
mc admin info prod
mc du prod/loki-chunks

7. Безопасность: пользователи и политики

Принцип минимальных привилегий

Не используйте root-учётные данные в приложениях. Для каждого сервиса — отдельный пользователь с ограниченной политикой.

Создание пользователей через mc

# Пользователь для Loki (только свой бакет)
mc admin user add prod loki ПАРОЛЬ_LOKI

mc admin policy create prod loki-policy /dev/stdin <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:*"],
      "Resource": [
        "arn:aws:s3:::loki-chunks",
        "arn:aws:s3:::loki-chunks/*"
      ]
    }
  ]
}
EOF

mc admin policy attach prod loki-policy --user loki

# Пользователь для бэкапов (только запись в backups)
mc admin user add prod backup ПАРОЛЬ_BACKUP

mc admin policy create prod backup-policy /dev/stdin <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::backups",
        "arn:aws:s3:::backups/*"
      ]
    }
  ]
}
EOF

mc admin policy attach prod backup-policy --user backup

Lifecycle policy: автоудаление старых объектов

# Удалять объекты в backups старше 30 дней
mc ilm rule add --expire-days 30 prod/backups

# Удалять незавершённые multipart uploads старше 7 дней
mc ilm rule add --expire-days 7 --noncurrent-expire-days 7 prod/backups

Версионирование бакетов (защита от случайного удаления)

# Включить версионирование
mc version enable prod/backups

# Посмотреть все версии объекта
mc ls --versions prod/backups/db-dump.sql.gz

8. Интеграция с Loki (S3 backend)

При переходе Loki на distributed-режим (см. PLG исследование) MinIO становится S3 backend для хранения chunks и index.

Loki values для S3 backend

# roles/logging/templates/loki-values.yml.j2 (distributed режим)
loki:
  storage:
    type: s3
    s3:
      endpoint: http://minio.minio.svc.cluster.local:9000
      region: us-east-1         # MinIO игнорирует region, но поле обязательно
      bucketnames: loki-chunks
      access_key_id: loki
      secret_access_key: "{{ loki_minio_password }}"
      insecure: true            # http (не https)
      s3forcepathstyle: true    # обязательно для MinIO

  schemaConfig:
    configs:
      - from: "2024-01-01"
        store: tsdb
        object_store: s3        # ← было filesystem
        schema: v13
        index:
          prefix: loki_index_
          period: 24h

Secret для Loki в namespace monitoring

kubectl create secret generic loki-minio-secret \
  --from-literal=AWS_ACCESS_KEY_ID=loki \
  --from-literal=AWS_SECRET_ACCESS_KEY=АРОЛЬ_LOKI' \
  -n monitoring

9. Ansible-роль и плейбук

Структура роли roles/minio/

roles/minio/
├── defaults/main.yml
├── tasks/
│   ├── main.yml
│   ├── namespace.yml       — создать namespace minio
│   ├── secrets.yml         — создать Secrets из vault/переменных
│   ├── helm.yml            — helm upgrade --install minio
│   └── mc.yml              — настройка mc alias, пользователей, политик, lifecycle
├── files/
│   └── minio-values.yml
└── templates/
    └── minio-values.yml.j2

defaults/main.yml

minio_namespace: minio
minio_chart_version: "5.4.0"           # minio/minio chart
minio_image_tag: "RELEASE.2025-04-22T22-12-26Z"

minio_storage_class: longhorn-minio   # выделенный SC, не дефолтный longhorn (numberOfReplicas=3)
minio_storage_size: 1Ti

minio_console_url: "http://10.203.0.96:10006"
minio_api_external_url: "http://10.203.0.96:10005"

# Имена Secrets (значения создаются вручную через kubectl)
minio_root_secret: minio-root-credentials

minio_buckets:
  - loki-chunks
  - backups
  - artifacts

minio_resources_requests_memory: "512Mi"
minio_resources_limits_memory: "2Gi"

tasks/helm.yml

- name: MinIO | Add Helm repo
  kubernetes.core.helm_repository:
    name: minio
    repo_url: https://charts.min.io/

- name: MinIO | Deploy via Helm
  kubernetes.core.helm:
    name: minio
    chart_ref: minio/minio
    chart_version: "{{ minio_chart_version }}"
    release_namespace: "{{ minio_namespace }}"
    create_namespace: true
    values: "{{ lookup('template', 'minio-values.yml.j2') | from_yaml }}"
    wait: true
    wait_condition:
      type: Ready
      status: "True"
    timeout: "10m0s"

playbooks/setup_minio.yml

---
- name: Deploy MinIO object storage
  hosts: manager_nodes
  become: false
  roles:
    - minio

.gitlab-ci.yml — новый job

setup/minio:
  stage: setup
  script:
    - ansible-playbook -i inventory/prod playbooks/setup_minio.yml
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      when: manual
  resource_group: production

Переменные GitLab CI/CD (добавить)

Переменная Описание
MINIO_ROOT_PASSWORD Пароль root-пользователя MinIO
MINIO_LOKI_PASSWORD Пароль пользователя loki
MINIO_BACKUP_PASSWORD Пароль пользователя backup

10. Масштабирование

Этапы роста: Longhorn и MinIO вместе

Реальное текущее состояние (проверено): worker имеет 2 диска по ~4 TiB, оба пустые. Это даёт несколько путей масштабирования без добавления нод:

Этап Кластер Longhorn MinIO
Сейчас 1 worker, 2 диска по 4 TiB longhorn SC: numberOfReplicas: 1, master без дисков ✓ standalone, PVC 1 TiB на disk1
+2 диска к worker 1 worker, 4 диска 4 PVC по 1 TiB, numberOfReplicas: 1 SNMD: 4 drives, EC:2, ~2 TiB usable
+1 worker с дисками 2 workers Поднять numberOfReplicas: 2 в longhorn-minio standalone + Longhorn-репликация между нодами
+3 workers (4 total) 4 workers numberOfReplicas: 2 Distributed: 4 пода, EC:2

Шаг 1: добавление второго worker (без пересоздания MinIO)

После добавления k8s-worker-02 в кластер:

# Убедиться что Longhorn видит новую ноду и диск
kubectl get nodes -o wide
kubectl get nodes.longhorn.io -n longhorn-system

# Обновить numberOfReplicas у StorageClass (или через Longhorn UI)
kubectl edit storageclass longhorn
# numberOfReplicas: "1" → "2"

# Обновить replicas у существующего PVC MinIO
kubectl -n longhorn-system edit volume <minio-pvc-volume-name>
# spec.numberOfReplicas: 1 → 2
# Longhorn начнёт ребалансировку в фоне, MinIO продолжает работать

Шаг 2: SNMD — 4 диска на одной ноде (реалистичный следующий шаг)

Worker уже имеет 2 диска (~4 TiB каждый). При добавлении ещё 2 дисков можно перейти на SNMD без новых нод:

# minio-values.yml — SNMD режим (4 диска на k8s-worker-01)
mode: distributed    # в MinIO SNMD тоже использует mode: distributed
replicas: 1          # 1 нода
drivesPerNode: 4     # 4 PVC на под

persistence:
  storageClass: longhorn-minio
  size: 1Ti          # 4 × 1 TiB = 4 TiB raw → ~2 TiB usable (EC:2)

При SNMD Longhorn создаёт 4 отдельных PVC (по одному на каждый логический диск MinIO). numberOfReplicas: 1 в StorageClass — MinIO EC уже обеспечивает отказоустойчивость.

Шаг 3: distributed (4+ workers)

# minio-values.yml при 4 worker-нодах
mode: distributed
replicas: 4          # 4 пода на 4 нодах
drivesPerNode: 1     # 1 Longhorn PVC на под

persistence:
  storageClass: longhorn-minio
  size: 1Ti          # 4 × 1 TiB raw → ~2 TiB usable (EC:2)

affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchLabels:
            app: minio
        topologyKey: kubernetes.io/hostname

В distributed-режиме Longhorn предоставляет отдельный PVC каждому поду MinIO. Репликацию Longhorn для distributed оставить на numberOfReplicas: 1 — MinIO EC уже обеспечивает отказоустойчивость.

Миграция standalone → distributed

MinIO не поддерживает in-place миграцию. Процедура:

1. Запустить distributed MinIO рядом (namespace minio-dist)
2. mc mirror minio-standalone minio-distributed --preserve --watch
3. Дождаться синхронизации всех объектов (mc du для сверки объёмов)
4. Переключить Traefik (изменить service в IngressRoute) на новый сервис
5. Обновить endpoint в configs Loki, бэкапов и других клиентов
6. Подождать 24-48 часов, убедиться что клиенты работают корректно
7. Удалить standalone namespace и PVC

Расширение объёма без миграции (только standalone)

Longhorn поддерживает расширение PVC онлайн — без остановки MinIO:

kubectl patch pvc minio -n minio \
  -p '{"spec":{"resources":{"requests":{"storage":"2Ti"}}}}'

# Longhorn расширит том; MinIO увидит новое пространство автоматически
mc admin info prod   # проверить новый объём в разделе capacity

11. Итоги и рекомендации

Почему Longhorn — правильный выбор для этого кластера

Longhorn уже является стандартом хранилища в кластере. Использование его для MinIO даёт:

  • Единая точка управления — диски, снэпшоты, репликация управляются через Longhorn UI, без отдельной операционной нагрузки
  • Онлайн-расширение — PVC MinIO расширяется без остановки пода (kubectl patch pvc)
  • Путь к отказоустойчивости — при добавлении второго worker достаточно поднять numberOfReplicas: 2, MinIO продолжает работать без изменений
  • Снэпшоты как бэкап — Longhorn умеет делать снэпшоты PVC по расписанию; для MinIO standalone это основной механизм защиты данных до перехода на distributed

Порядок развёртывания

1. Применить StorageClass longhorn-minio (см. раздел 3)
   (опц.) Longhorn UI → k8s-worker-01 → добавить тег "minio" на longhorn-disk1 для изоляции
2. kubectl create namespace minio
3. Создать Secret minio-root-credentials вручную
4. Запустить setup_minio.yml (Helm install)
5. Добавить minio-api и minio-console в traefik_port_map (порты 10005, 10006 — свободны)
6. Запустить setup_traefik.yml
7. Проверить Console: http://10.203.0.96:10006
8. Создать пользователей через mc (loki, backup)
9. Обновить loki-values.yml если Loki уже работает

Итоговые адреса

Сервис URL
MinIO Console (UI) http://10.203.0.96:10006
MinIO S3 API http://10.203.0.96:10005
MinIO API (внутри кластера) http://minio.minio.svc.cluster.local:9000

Следующие шаги

  • Применить StorageClass longhorn-minio (раздел 3)
  • (опц.) Longhorn UI: добавить тег minio на longhorn-disk1 для изоляции диска
  • Создать Secret minio-root-credentials вручную
  • Написать роль roles/minio/ по структуре из раздела 9
  • Добавить job setup/minio в .gitlab-ci.yml
  • Добавить minio-api и minio-console в traefik_port_map (порты 10005, 10006)
  • Добавить переменные MINIO_ROOT_PASSWORD, MINIO_LOKI_PASSWORD в GitLab CI/CD Variables
  • Добавить firewalld-правило в roles/minio/tasks/firewall.yml (порты 9000, 9001 в trusted zone для flannel.1/cni0)