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

789 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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. [Обзор и назначение](#1-обзор-и-назначение)
2. [Режимы развёртывания](#2-режимы-развёртывания)
3. [Планирование хранилища 1 ТБ](#3-планирование-хранилища-1-тб)
4. [Helm-развёртывание (standalone)](#4-helm-развёртывание-standalone)
5. [MinIO Console: веб-интерфейс](#5-minio-console-веб-интерфейс)
6. [Интеграция с Traefik](#6-интеграция-с-traefik)
7. [Безопасность: пользователи и политики](#7-безопасность-пользователи-и-политики)
8. [Интеграция с Loki (S3 backend)](#8-интеграция-с-loki-s3-backend)
9. [Ansible-роль и плейбук](#9-ansible-роль-и-плейбук)
10. [Масштабирование до distributed-режима](#10-масштабирование-до-distributed-режима)
11. [Итоги и рекомендации](#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, бэкапы и т.д.)
```yaml
# применить через роль 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):
```bash
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 — он добавляет лишние зависимости).
```bash
helm repo add minio https://charts.min.io/
helm repo update
```
### `minio-values.yml`
```yaml
# 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 с корневыми учётными данными
```bash
kubectl create secret generic minio-root-credentials \
--from-literal=rootUser=minioadmin \
--from-literal=rootPassword='СИЛЬНЫЙ_ПАРОЛЬ_МИНИМУМ_8_СИМВОЛОВ' \
-n minio
```
### Установка
```bash
kubectl create namespace minio
helm upgrade --install minio minio/minio \
--namespace minio \
--version 5.4.0 \
--values roles/minio/files/minio-values.yml \
--wait
```
### Проверка
```bash
# Статус пода
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.
```yaml
# В 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`
```yaml
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) для внешнего доступа
```bash
# На 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
```bash
# Пользователь для 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: автоудаление старых объектов
```bash
# Удалять объекты в 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
```
### Версионирование бакетов (защита от случайного удаления)
```bash
# Включить версионирование
mc version enable prod/backups
# Посмотреть все версии объекта
mc ls --versions prod/backups/db-dump.sql.gz
```
---
## 8. Интеграция с Loki (S3 backend)
При переходе Loki на distributed-режим (см. [PLG исследование](../logging/plg.md)) MinIO становится S3 backend для хранения chunks и index.
### Loki values для S3 backend
```yaml
# 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
```bash
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`
```yaml
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`
```yaml
- 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`
```yaml
---
- name: Deploy MinIO object storage
hosts: manager_nodes
become: false
roles:
- minio
```
### `.gitlab-ci.yml` — новый job
```yaml
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` в кластер:
```bash
# Убедиться что 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 **без новых нод**:
```yaml
# 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)
```yaml
# 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:
```bash
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)