Как говорят у меня на родине: корпоративная жадность — двигатель миграций. И именно это мы сейчас можем наблюдать на примере MinIO — некогда любимого инструмента DevOps-инженеров для развёртывания S3-совместимого хранилища. В 2021 году они втихушку сменили лицензию на AGPL v3, а в 2025 году и вовсе выпилили веб-интерфейс из бесплатной версии. Ну и, наверное, можно подумать, что за такой удобный инструмент можно и заплатить. Но тогда встаёт вопрос: какова цена коммерческой лицензии? От $96 000 в год)
В этой статье мы разберём, чем можно заменить MinIO, сравним альтернативы в разных сценариях и, конечно же, развернём их руками — потому что теория без практики, как вайбкодер без гпт.
Что случилось с MinIO?
Давайте сначала разберёмся, что вообще нас побудило искать альтернативы. История MinIO — классический пример того, как популярный open-source проект превращается в ловушку для пользователей.
Хронология событий
Дата | Событие |
|---|---|
2015 | MinIO основан, лицензия Apache 2.0 |
Октябрь 2019 | Начало перехода на AGPL v3 (operator и другие компоненты) |
Май 2021 | Полный переход MinIO Server на AGPL v3 |
2022 | Публичное обвинение Nutanix в нарушении лицензии |
2023 | Отзыв лицензии у Weka «без предупреждения» |
Июнь 2025 | Удаление веб-консоли из бесплатной версии |
Что такое AGPL v3 и почему это проблема?
AGPL v3 (GNU Affero General Public License) — это «открытая лицензия», но у неё есть одна очень интересная ключевая особенность — network copyleft. Если вы используете AGPL-софт и предоставляете к нему доступ через сеть (даже если пользователи не скачивают ��аше ПО), вы обязаны открыть исходный код всего приложения под той же лицензией.
Практические последствия для бизнеса:
SaaS-продукты — если ваш сервис использует MinIO для хранения данных клиентов, вам нужно либо открыть весь код, либо купить коммерческую лицензию.
Внутренние продукты — даже если вы используете MinIO только внутри компании, но к нему есть сетевой доступ у сотрудников, формально это может считаться «предоставлением через сеть».
Встраиваемые решения — если вы продаёте железо или софт с MinIO внутри, клиенты теоретически могут потребовать исходный код вашего продукта.
Однако это не было бы серьёзным звоночком, так как на самом деле множество продуктов используют эту лицензию. Например, MongoDB, Grafana. Основная цель — отпугиватель для конкурентов-облаков.
Ценовая политика MinIO
Посмотрим на цены коммерческой версии (данные с официального сайта):
Объём | Цена в год |
|---|---|
До 1TB | $96,000 |
1PB | $244,032 |
10PB | $2,440,320 |
Для сравнения: за $96,000 в год можно арендовать ~800TB в Backblaze B2 или ~200TB в AWS S3 Standard. Или купить собственные серверы с дисками и нанять DevOps-инженера для их обслуживания.
Удаление фич из бесплатной версии
В июне 2025 года MinIO выпустили PR под названием «Implemented AGPL MinIO Object Browser simplified Console», который на практике означал:
Удалено из бесплатной версии:
Полноценный веб-интерфейс управления.
Графическое управление пользователями и политиками.
Визуализация метрик.
Управление репликацией через UI.
Осталось:
CLI-инструмент
mc admin.Базовый API.
Prometheus-метрики (но без UI).
Комментарий разработчика MinIO на вопрос про использование UI: «No for UI based administrative use-cases move to https://min.io/download?view=aistor-custom or use mc as a community member».
Обзор альтернатив
Итак, в результате мы там, где мы есть. И нам надо что-то делать, так что предлагаю рассмотреть четыре основных кандидата на замену MinIO:
Решение | Язык | Лицензия | Сложность | Лучший сценарий |
|---|---|---|---|---|
SeaweedFS | Go | Apache 2.0 | Средняя | Миллиарды мелких файлов, CDN |
Garage | Rust | AGPL v3 | Низкая | Edge, ограниченные ресурсы, геораспределение |
Ceph RGW | C++ | LGPL 2.1/3.0 | Высокая | Enterprise, петабайты данных, unified storage |
OpenMaxIO | Go | Apache 2.0 | Низкая | Drop-in замена MinIO |
Да, Garage тоже на AGPL, но есть важный нюанс — это некоммерческий проект от французской организации Deuxfleurs, защищающей цифровые п��ава. У них нет армии юристов и коварных планов преследований пользователей.
SeaweedFS: когда у вас миллиарды файлов
SeaweedFS — это быстрое распределённое хранилище, изначально вдохновлённое статьёй Facebook* о Haystack (2010). Его главная фишка — O(1) поиск на диске для blob-объектов. Это достигается за счёт того, что метаданные файлов хранятся не централизованно, а распределены по volume-серверам.
Архитектура SeaweedFS
┌─────────────────────────────────────────────────────────────────┐
│ Клиенты │
│ (S3 API / Filer API / FUSE / WebDAV / Hadoop) │
└───────────────────────────┬─────────────────────────────────────┘ │
┌───────────────────────────▼─────────────────────────────────────┐
│ S3 Gateway (опционально) │
│ Трансляция S3 API → Filer API │
└───────────────────────────┬─────────────────────────────────────┘ │
┌───────────────────────────▼─────────────────────────────────────┐
│ Filer (опционально) │
│ Метаданные файловой системы │
│ Бэкенды: LevelDB / MySQL / PostgreSQL / Redis / etcd │
│ Поддержка: directories, symlinks, xattr │
└───────────────────────────┬─────────────────────────────────────┘ │
┌───────────────────────────▼─────────────────────────────────────┐
│ Master Servers │
│ (управление топологией) │
│ Raft consensus для HA (минимум 3 для кворума) │
│ Хранит: volume locations, cluster topology, free space │
└───────────────────────────┬─────────────────────────────────────┘ │
┌─────────────┬─────────────┴─────────────┬───────────────────────┐
│ Volume 1 │ Volume 2 │ Volume N │
│ Server │ Server │ Server │
│ DC1/Rack1 │ DC1/Rack2 │ DC2/Rack1 │
│ (SSD) │ (HDD) │ (HDD) │
└─────────────┴───────────────────────────┴───────────────────────┘
Ключевые концепции:
Volume — единица хранения, файл размером до 30GB по умолчанию. Внутри хранятся needle.
Needle — конкретный файл внутри volume. Адресуется как
volume_id, needle_id, cookie. Название — отсылка к идиоме «needle in a haystack» (иголка в стоге сена) из треда на Facebook*.Collection — логическая группировка volumes (аналог bucket в S3).
Data Center / Rack — топология для умного размещения реплик.
Практика: разворачиваем SeaweedFS в Docker
Простой вариант для разработки
version: '3.9'
services:
seaweedfs:
image: chrislusf/seaweedfs:latest
ports:
- "9333:9333" # Master
- "8080:8080" # Volume
- "8888:8888" # Filer
- "8333:8333" # S3
command: 'server -s3 -dir=/data'
volumes:
- ./data:/data
restart: unless-stoppedЭтот вариант запускает все компоненты в одном контейнере — удобно для тестов.
Production-ready кластер
version: '3.9'
networks:
seaweedfs:
driver: bridge
services:
# =============== MASTER SERVERS (минимум 3 для HA) ===============
master1:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "9333:9333"
- "19333:19333"
command: >
master
-ip=master1
-ip.bind=0.0.0.0
-port=9333
-mdir=/data
-peers=master1:9333,master2:9333,master3:9333
-volumeSizeLimitMB=1024
-defaultReplication=001
-garbageThreshold=0.3
-metricsPort=9324
volumes:
- ./data/master1:/data
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9333/cluster/status"]
interval: 30s
timeout: 10s
retries: 3
master2:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "9334:9333"
- "19334:19333"
command: >
master
-ip=master2
-ip.bind=0.0.0.0
-port=9333
-mdir=/data
-peers=master1:9333,master2:9333,master3:9333
-volumeSizeLimitMB=1024
-defaultReplication=001
-garbageThreshold=0.3
-metricsPort=9324
volumes:
- ./data/master2:/data
restart: unless-stopped
master3:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "9335:9333"
- "19335:19333"
command: >
master
-ip=master3
-ip.bind=0.0.0.0
-port=9333
-mdir=/data
-peers=master1:9333,master2:9333,master3:9333
-volumeSizeLimitMB=1024
-defaultReplication=001
-garbageThreshold=0.3
-metricsPort=9324
volumes:
- ./data/master3:/data
restart: unless-stopped
# =============== VOLUME SERVERS ===============
volume1:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "8080:8080"
- "18080:18080"
command: >
volume
-mserver="master1:9333,master2:9333,master3:9333"
-ip.bind=0.0.0.0
-port=8080
-dir=/data
-max=300
-dataCenter=dc1
-rack=rack1
-compactionMBps=50
-fileSizeLimitMB=256
-metricsPort=9325
volumes:
- ./data/volume1:/data
depends_on:
- master1
- master2
- master3
restart: unless-stopped
volume2:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "8081:8080"
- "18081:18080"
command: >
volume
-mserver="master1:9333,master2:9333,master3:9333"
-ip.bind=0.0.0.0
-port=8080
-dir=/data
-max=300
-dataCenter=dc1
-rack=rack2
-compactionMBps=50
-fileSizeLimitMB=256
-metricsPort=9325
volumes:
- ./data/volume2:/data
depends_on:
- master1
restart: unless-stopped
volume3:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "8082:8080"
- "18082:18080"
command: >
volume
-mserver="master1:9333,master2:9333,master3:9333"
-ip.bind=0.0.0.0
-port=8080
-dir=/data
-max=300
-dataCenter=dc1
-rack=rack3
-compactionMBps=50
-fileSizeLimitMB=256
-metricsPort=9325
volumes:
- ./data/volume3:/data
depends_on:
- master1
restart: unless-stopped
# =============== FILER (для S3 API и файловой семантики) ===============
filer:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "8888:8888"
- "18888:18888"
- "9326:9326"
command: >
filer
-master="master1:9333,master2:9333,master3:9333"
-ip.bind=0.0.0.0
-port=8888
-defaultReplicaPlacement=001
-metricsPort=9326
volumes:
- ./config/filer.toml:/etc/seaweedfs/filer.toml:ro
depends_on:
- master1
- volume1
- volume2
- volume3
restart: unless-stopped
# =============== S3 GATEWAY ===============
s3:
image: chrislusf/seaweedfs:latest
networks:
- seaweedfs
ports:
- "8333:8333"
command: >
s3
-filer="filer:8888"
-filer.path=/buckets
-ip.bind=0.0.0.0
-port=8333
-config=/etc/seaweedfs/s3.json
-allowEmptyFolder=false
-metricsPort=9327
volumes:
- ./config/s3.json:/etc/seaweedfs/s3.json:ro
depends_on:
- filer
restart: unless-stoppedЗачем 3 мастера? Raft consensus требует большинство. С тремя мастерами:
2 из 3 живы → кластер работает;
1 из 3 жив → кластер read-only или недоступен.
Конфигурационные файлы
config/filer.toml — настройки Filer (бэкенд метаданных):
[filer.options]
recursive_delete = false
max_file_name_length = 512
# Выбираем бэкенд для метаданных
# Для production рекомендуется PostgreSQL или MySQL
# Вариант 1: встроенный LevelDB (для небольших инсталляций, например dev или test)
[leveldb2]
enabled = true
dir = "/data/filerldb2"
# Вариант 2: PostgreSQL (рекомендуется для prod)
[postgres2]
enabled = false
createTable = """
CREATE TABLE IF NOT EXISTS "%s" (
dirhash BIGINT,
name VARCHAR(65535),
directory VARCHAR(65535),
meta bytea,
PRIMARY KEY (dirhash, name)
)
"""
hostname = "postgres"
port = 5432
username = "seaweedfs"
password = "seaweedfs_password"
database = "seaweedfs"
sslmode = "disable"
# Вариант 3: MySQL
[mysql2]
enabled = false
hostname = "mysql"
port = 3306
username = "seaweedfs"
password = "seaweedfs_password"
database = "seaweedfs"config/s3.json — настройки S3 API:
{
"identities": [
{
"name": "admin",
"credentials": [
{
"accessKey": "BESTACCESSKEY",
"secretKey": "WriterSecretKeyChangeInProduction12345678"
}
],
"actions": [
"Admin",
"Read",
"Write",
"List",
"Tagging"
]
},
{
"name": "app-readonly",
"credentials": [
{
"accessKey": "BESTACCESSKEY",
"secretKey": "WriterSecretKeyChangeInProduction12345678"
}
],
"actions": [
"Read",
"List"
]
},
{
"name": "app-writer",
"credentials": [
{
"accessKey": "BESTACCESSKEY",
"secretKey": "WriterSecretKeyChangeInProduction12345678"
}
],
"actions": [
"Read",
"Write",
"List"
]
},
{
"name": "anonymous",
"actions": [
"Read:public-*"
]
}
]
}Запуск и проверка
# Создаём директории
mkdir -p data/{master1,master2,master3,volume1,volume2,volume3} config
# Создаём конфиги (см. выше)
# Запускаем
docker compose -f docker-compose.production.yml up -d
# Ждём инициализации (30-60 секунд) и проверяем статус кластера
curl -s http://localhost:9333/cluster/status | jq .
# Ожидаемый вывод:
# {
# "IsLeader": true,
# "Leader": "master1:9333",
# "Peers": ["master2:9333", "master3:9333"]
# }
# Проверяем топологию
curl -s http://localhost:9333/dir/status | jq .
# Проверяем volume servers
curl -s http://localhost:9333/vol/status | jq '.Volumes | length'Работа с S3 API
# Устанавливаем AWS CLI
pip install awscli
# Настраиваем профиль
aws configure --profile seaweedfs
# AWS Access Key ID: BESTACCESSKEY
# AWS Secret Access Key: WriterSecretKeyChangeInProduction12345678
# Default region name: us-east-1
# Default output format: json
# Создаём bucket
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 mb s3://test-bucket
# Загружаем файл
echo "Hello, SeaweedFS!" > test.txt
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 cp test.txt s3://test-bucket/
# Загружаем директорию рекурсивно
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 sync ./local-folder s3://test-bucket/backup/ --recursive
# Листинг
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 ls s3://test-bucket/
# Скачиваем
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 cp s3://test-bucket/test.txt ./downloaded.txt
# Удаляем
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 rm s3://test-bucket/test.txt
# Presigned URL (временная ссылка на скачивание)
aws --profile seaweedfs --endpoint-url http://localhost:8333 \
s3 presign s3://test-bucket/test.txt --expires-in 3600Репликация и отказоустойчивость
SeaweedFS поддерживает гибкую настройку репликации через параметр -defaultReplication:
Значение | Описание |
|---|---|
| Без репликации (1 копия) |
| 1 реплика на другом volume в том же rack |
| 1 реплика в другом rack того же DC |
| 1 реплика в другом DC |
| 2 реплики в разных DC |
| 1 в другом rack + 1 в другом DC |
# Создание collection с конкретной репликацией
curl "http://localhost:9333/dir/assign?collection=critical-data&replication=110"
# Проверка репликации конкретного volume
curl -s http://localhost:9333/vol/status | jq '.Volumes[] | select(.ReplicaPlacement != "000")'FUSE-монтирование
SeaweedFS можно смонтировать как обычную файловую систему:
# Устанавливаем weed mount
wget https://github.com/seaweedfs/seaweedfs/releases/latest/download/linux_amd64_full.tar.gz
tar -xzf linux_amd64_full.tar.gz
# Монтируем
mkdir -p /mnt/seaweedfs
./weed mount -filer=localhost:8888 -dir=/mnt/seaweedfs -filer.path=/Встроенный бенчмарк
# Запускаем бенчмарк напрямую
docker run --rm --network host chrislusf/seaweedfs \
weed benchmark -master=localhost:9333 -c 16 -n 100000
# Параметры:
# -c 16 — 16 параллельных клиентов
# -n 100000 — 100,000 операций
# -size 1024 — размер файла в байтах (по умолчанию 1KB)
# Пример вывода:
# ------------ Writing Benchmark ----------
# Completed 100000 of 100000 requests, 99.8%
# Total time: 15.234 seconds
# Throughput: 6565.1 files/sec
# Transfer rate: 6.41 MB/sec
#
# ------------ Reading Benchmark ----------
# Completed 100000 of 100000 requests, 100.0%
# Total time: 8.127 seconds
# Throughput: 12305.7 files/sec
# Transfer rate: 12.02 MB/secМониторинг SeaweedFS
SeaweedFS экспортирует метрики в формате Prometheus. Добавляем в docker-compose:
prometheus:
image: prom/prometheus:latest
networks:
- seaweedfs
ports:
- "9090:9090"
volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml:ro
restart: unless-stopped
grafana:
image: grafana/grafana:latest
networks:
- seaweedfs
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
restart: unless-stopped
volumes:
grafana-data:config/prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'seaweedfs-master'
static_configs:
- targets: ['master1:9324', 'master2:9324', 'master3:9324']
- job_name: 'seaweedfs-volume'
static_configs:
- targets: ['volume1:9325', 'volume2:9325', 'volume3:9325']
- job_name: 'seaweedfs-filer'
static_configs:
- targets: ['filer:9326']
- job_name: 'seaweedfs-s3'
static_configs:
- targets: ['s3:9327']Ключевые метрики для мониторинга:
Метрика | Описание | Alert threshold |
|---|---|---|
| Общий размер дисков | — |
| Использовано | > 80% |
| Запросы к filer | — |
| Латентность | p99 > 100ms |
| S3-запросы | — |
| S3-латентность | p99 > 200ms |
Garbage Collection и Compaction
SeaweedFS не удаляет данные мгновенно — они помечаются как удалённые, а физическое освобождение происходит при compaction:
# Через weed shell
docker exec -it seaweedfs weed shell
# В shell:
> volume.vacuum -garbageThreshold 0.3
# Запустит compaction для volumes с >30% мусора
# Или через HTTP API
curl -X POST "http://localhost:9333/vol/vacuum?garbageThreshold=0.3"Когда выбирать SeaweedFS?
✅ Да:
Миллиарды мелких файлов (картинки, аватары, документы).
Нужен POSIX-доступ через FUSE.
Cloud tiering (горячие данные локально, холодные в облаке).
Apache 2.0 лицензия критична.
CDN/медиахранилище.
❌ Нет:
Нужна максимальная S3-совместимость (нет versioning, lifecycle policies).
Меньше 3 серверов для production.
Garage: лёгкое решение для edge и геораспределения
Garage — детище французской некоммерческой организации Deuxfleurs. Реализован на Rust, что даёт минимальное потребление ресурсов и высокую надёжность. Главная фича — встроенная георепликация с учётом зон.
Философия Garage
Garage проектировали под конкретную задачу: объединить разные узлы в разных местах в одно хранилище, даже если связь между ними не самого хорошего качества. Хорошо подходит для:
Несколько Raspberry Pi в разных городах/квартирах.
Серверы, разбросанные по разным точкам.
Домашние серверы энтузиастов, объединённые через интернет.
Бэкапы, которые должны лежать в разных географических местах.
Архитектура Garage
В отличие от классической master-slave архитектуры, Garage использует полностью распределённый подход:
┌─────────────────────────────────────┐
│ Клиенты │
│ (S3 API / K2V API) │
└────────────────┬────────────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Node A │◄─────────────►│ Node B │◄─────────────►│ Node C │
│ Paris │ │ Berlin │ │ London │
│ Zone: EU │ │ Zone: EU │ │ Zone: EU │
│ 1TB SSD │ │ 2TB HDD │ │ 500GB SSD │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
│ Gossip Protocol (RPC) │
└─────────────────────────────┴─────────────────────────────┘
Каждый узел:
├── Принимает S3-запросы
├── Хранит данные
├── Участвует в репликации
└── Равноправен с другимиКлючевые концепции:
Zone — логическая группа узлов, которые могут отказать вместе (rack, DC, город).
Replication factor — сколько копий данных хранится (по умолчанию 3).
Layout — карта распределения данных по узлам.
Partition — единица распределения данных (2^partition_bits партиций).
Практика: разворачиваем Garage
Single-node для разработки
# Генерируем секреты
RPC_SECRET=$(openssl rand -hex 32)
ADMIN_TOKEN=$(openssl rand -base64 32)
METRICS_TOKEN=$(openssl rand -base64 32)
# Создаём директории
mkdir -p ~/garage/{data,meta}
# Создаём конфигурацию
cat > ~/garage/garage.toml << EOF
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "sqlite" # Для single-node, в production используйте lmdb
replication_factor = 1 # Для single-node
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "${RPC_SECRET}"
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage.localhost"
[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.garage.localhost"
index = "index.html"
[k2v_api]
api_bind_addr = "[::]:3904"
[admin]
api_bind_addr = "[::]:3903"
admin_token = "${ADMIN_TOKEN}"
metrics_token = "${METRICS_TOKEN}"
EOF
# Запускаем через Docker
docker run -d \
--name garage \
-p 3900:3900 \
-p 3901:3901 \
-p 3902:3902 \
-p 3903:3903 \
-p 3904:3904 \
-v ~/garage/garage.toml:/etc/garage.toml:ro \
-v ~/garage/data:/var/lib/garage/data \
-v ~/garage/meta:/var/lib/garage/meta \
dxflrs/garage:v2.1.0
# Проверяем статус
docker exec garage /garage statusMulti-node кластер (3 узла)
Для production-кластера нам нужно минимум 3 узла в разных зонах. Создаём docker-compose для каждого узла:
docker-compose.node1.yml:
version: '3.9'
services:
garage:
image: dxflrs/garage:v2.1.0
container_name: garage-node1
network_mode: host
volumes:
- ./garage-node1.toml:/etc/garage.toml:ro
- ./node1/data:/var/lib/garage/data
- ./node1/meta:/var/lib/garage/meta
restart: unless-stoppedgarage-node1.toml:
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "lmdb"
metadata_auto_snapshot_interval = "6h"
replication_factor = 3
compression_level = 2
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "NODE1_PUBLIC_IP:3901"
rpc_secret = "SAME_SECRET_FOR_ALL_NODES_32_HEX_CHARS"
bootstrap_peers = [
"NODE2_PUBLIC_IP:3901",
"NODE3_PUBLIC_IP:3901"
]
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage.example.com"
[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.garage.example.com"
index = "index.html"
[k2v_api]
api_bind_addr = "[::]:3904"
[admin]
api_bind_addr = "[::]:3903"
admin_token = "YOUR_ADMIN_TOKEN"
metrics_token = "YOUR_METRICS_TOKEN"Аналогично создаём конфиги для node2 и node3, меняя rpc_public_addr.
Инициализация кластера
# На каждом узле получаем Node ID
docker exec garage-node1 /garage node id
# Вывод: 5a7c4f3b9e@192.168.1.10:3901
# Соединяем узлы (на любом из них)
docker exec garage-node1 /garage node connect 7b8d5e2a1f@192.168.1.11:3901
docker exec garage-node1 /garage node connect 9c6a3d8e4b@192.168.1.12:3901
# Проверяем статус
docker exec garage-node1 /garage status
# Все узлы должны быть видны
# Создаём layout
docker exec garage-node1 /garage layout assign \
--zone paris \
--capacity 500G \
5a7c4f3b9e
docker exec garage-node1 /garage layout assign \
--zone berlin \
--capacity 1T \
7b8d5e2a1f
docker exec garage-node1 /garage layout assign \
--zone london \
--capacity 500G \
9c6a3d8e4b
# Просматриваем и применяем
docker exec garage-node1 /garage layout show
docker exec garage-node1 /garage layout apply --version 1Создание пользователей и buckets
# Создаём bucket
docker exec garage-node1 /garage bucket create my-data
# Создаём ключ
docker exec garage-node1 /garage key create my-app-key
# Выводим ключ (запоминаем access_key и secret_key)
docker exec garage-node1 /garage key info my-app-key --show-secret
# Даём права на bucket
docker exec garage-node1 /garage bucket allow \
--read \
--write \
--owner \
my-data \
--key my-app-key
# Проверяем
docker exec garage-node1 /garage bucket info my-dataРабота с S3 API
# Настраиваем AWS CLI
cat >> ~/.aws/credentials << EOF
[garage]
aws_access_key_id = BESTACCESSKEY
aws_secret_access_key = WriterSecretKeyChangeInProduction12345678
EOF
cat >> ~/.aws/config << EOF
[profile garage]
region = garage
output = json
EOF
# Тестируем
aws --profile garage \
--endpoint-url http://localhost:3900 \
s3 ls
# Создаём bucket через CLI (альтернатива garage CLI)
aws --profile garage \
--endpoint-url http://localhost:3900 \
s3 mb s3://test-bucket
# Multipart upload для больших файлов
aws --profile garage \
--endpoint-url http://localhost:3900 \
s3 cp large-file.zip s3://my-data/ \
--expected-size 10737418240K2V API — уникальная фича Garage
Garage предоставляет не только S3, но и K2V (Key-Value-Value) API — распределённое key-value хранилище с поддержкой causal consistency:
# Включено по умолчанию на порту 3904
# Пример использования через curl
# Записываем значение
curl -X PUT \
-H "Authorization: AWS4-HMAC-SHA256 ..." \
-d "my-value" \
"http://localhost:3904/my-bucket/my-partition-key?sort_key=my-sort-key"
# Читаем
curl -H "Authorization: ..." \
"http://localhost:3904/my-bucket/my-partition-key?sort_key=my-sort-key"K2V полезен для хранения метаданных, сессий, конфигураций — всего, что требует быстрого доступа по ключу.
Web UI для Garage
Официального UI нет, но есть community-проект garage-webui:
# Добавляем в docker-compose
garage-webui:
image: khairul169/garage-webui:latest
container_name: garage-webui
ports:
- "3909:3909"
volumes:
- ./garage.toml:/etc/garage.toml:ro
environment:
API_BASE_URL: "http://garage:3903"
S3_ENDPOINT_URL: "http://garage:3900"
# Опционально: аутентификация
# AUTH_USER_PASS: "admin:$2y$10$xxxxx" # bcrypt hash
restart: unless-stoppedМониторинг Garage
# prometheus.yml
scrape_configs:
- job_name: 'garage'
static_configs:
- targets:
- 'node1:3903'
- 'node2:3903'
- 'node3:3903'
metrics_path: /metrics
authorization:
credentials: YOUR_METRICS_TOKENКлючевые метрики:
Метрика | Описание |
|---|---|
| Размер хранимых данных |
| Количество блоков данных |
| Объектов в bucket |
| Байт в bucket |
| Латентность RPC |
| Латентность S3 |
Troubleshooting Garage
Проблема: узлы не видят друг друга
# Проверяем сетевую доступность
nc -zv node2_ip 3901
# Проверяем, что rpc_secret одинаков на всех узлах
grep rpc_secret /etc/garage.toml
# Проверяем firewall
sudo iptables -L -n | grep 3901Проблема: Layout не применяется
# Смотрим текущую версию
docker exec garage /garage layout show
# Если "staged changes", применяем
docker exec garage /garage layout apply --version N
# Если конфликт, можно откатить
docker exec garage /garage layout revert --version NПроблема: данные не реплицируются
# Проверяем здоровье кластера
docker exec garage /garage status
# Смотрим repair status
docker exec garage /garage repair --all-nodes status
# Запускаем repair вручную
docker exec garage /garage repair --all-nodes blocksКогда выбирать Garage?
✅ Да:
Edge-деплой на Raspberry Pi или маломощных VPS.
Геораспределённый кластер с высокой задержкой между узлами.
Минимальное потребление RAM критично (Rust!).
Self-hosted бэкапы с репликацией.
Простота важнее фич.
❌ Нет:
Нужна полная S3-совместимость (versioning, lifecycle, advanced IAM).
Enterprise-фичи обязательны.
Больше 50TB данных.
Высокие требования к производительности.
Ceph: Оставь надежду, всяк сюда входящий
Ceph — это монстр enterprise-уровня. Используется в CERN для хранения данных Large Hadron Collider, в Bloomberg для финансовой аналитики, в DreamWorks для рендер-пайплайнов. Если вам нужны петабайты — это ваш выбор.
Зачем такая сложность?
Ceph предоставляет unified storage — из одного кластера вы получаете:
RBD — block storage (аналог EBS).
CephFS — distributed file system (аналог EFS).
RGW — object storage с S3/Swift API (аналог S3).
Это означает, что вместо трёх разных систем хранения вы управляете одной.
Архитектура Ceph
┌─────────────────────────────────────────────────────────────────────────┐
│ Клиенты │
│ S3/Swift API POSIX/NFS Block Devices │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ RGW │ │ MDS │ │ RBD │ │
│ │ (Object)│ │ (File) │ │ (Block) │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
└────────────┼─────────────────┼──────────────────┼───────────────────────┘
│ │ │
└─────────────────┼──────────────────┘
│
┌──────────────────────────────▼──────────────────────────────────────────┐
│ librados │
│ Библиотека доступа к RADOS │
└──────────────────────────────┬──────────────────────────────────────────┘
│
┌──────────────────────────────▼──────────────────────────────────────────┐
│ RADOS │
│ Reliable Autonomic Distributed Object Store │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ CRUSH Algorithm │ │
│ │ Controlled Replication Under Scalable Hashing │ │
│ │ (Определяет размещение данных без центрального каталога) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ MON │ │ MON │ │ MON │ │ MGR │ │
│ │ Monitor │ │ Monitor │ │ Monitor │ │ Manager │ │
│ │ (quorum)│ │ │ │ │ │(metrics)│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ OSD │ │ OSD │ │ OSD │ │ OSD │ ... │
│ │ Disk1 │ │ Disk2 │ │ Disk3 │ │ Disk4 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────────────┘Компоненты:
MON (Monitor) — хранит карту кластера, обеспечивает консенсус. Минимум 3 для кворума.
OSD (Object Storage Daemon) — один на каждый физический диск. Хранит данные, обрабатывает репликацию.
MGR (Manager) — метрики, dashboard, модули расширения.
MDS (Metadata Server) — только для CephFS, хранит метаданные файловой системы.
RGW (RADOS Gateway) — S3/Swift API gateway.
Быстрый старт с MicroCeph
Canonical упростили жизнь, создав MicroCeph — обёртку над Ceph для простого развёртывания:
# Требования: Ubuntu 22.04+, минимум 8GB RAM, свободный диск
# Устанавливаем MicroCeph
sudo snap install microceph --channel=latest/stable
# ВАЖНО: фиксируем версию, чтобы избежать автообновлений
sudo snap refresh --hold microceph
# Инициализируем кластер
sudo microceph cluster bootstrap
# Проверяем статус
sudo microceph statusДобавляем хранилище:
# Вариант 1: реальный диск
sudo microceph disk add /dev/sdb --wipe
# Вариант 2: loop-устройство для тестов
sudo dd if=/dev/zero of=/var/snap/microceph/common/data/osd.img bs=1M count=20480
LOOP=$(sudo losetup --find --show /var/snap/microceph/common/data/osd.img)
sudo microceph disk add $LOOP --wipe
# Проверяем
sudo ceph osd treeВключаем RGW:
# Включаем Object Gateway
sudo microceph enable rgw
# Ждём запуска (может занять минуту)
sleep 60
# Проверяем
sudo ceph -s | grep rgw
curl http://localhost:80Создаём пользователя:
# Создаём S3 пользователя
sudo radosgw-admin user create \
--uid=myuser \
--display-name="My User" \
--access-key=myaccesskey \
--secret=mysupersecretkey
# Или с автогенерацией ключей
sudo radosgw-admin user create \
--uid=autouser \
--display-name="Auto User"
# Ключи будут в выводе командыProduction-деплой с Cephadm
Для серьёзных инсталляций используйте cephadm — современный оркестратор Ceph:
# На первом узле (будет bootstrap node)
# Устанавливаем cephadm
curl --silent --remote-name \
https://download.ceph.com/rpm-squid/el9/noarch/cephadm
chmod +x cephadm
sudo mv cephadm /usr/local/bin/
# Или через пакетный менеджер (Ubuntu)
sudo apt install -y cephadm
# Bootstrap кластера
sudo cephadm bootstrap \
--mon-ip 192.168.1.10 \
--initial-dashboard-user admin \
--initial-dashboard-password SecureP@ssw0rd \
--dashboard-ssl \
--allow-fqdn-hostname
# Сохраняем вывод! Там будут:
# - URL dashboard
# - Credentials
# - SSH ключ для добавления узловДобавляем узлы:
# Копируем SSH-ключ на другие узлы
sudo cephadm shell -- ceph cephadm get-pub-key > ceph.pub
ssh-copy-id -f -i ceph.pub root@node2
ssh-copy-id -f -i ceph.pub root@node3
# Добавляем узлы
sudo cephadm shell -- ceph orch host add node2 192.168.1.11
sudo cephadm shell -- ceph orch host add node3 192.168.1.12
# Добавляем OSD на всех узлах (автоматически найдёт свободные диски)
sudo cephadm shell -- ceph orch apply osd --all-available-devices
# Или явно указываем диски
sudo cephadm shell -- ceph orch daemon add osd node2:/dev/sdb
sudo cephadm shell -- ceph orch daemon add osd node3:/dev/sdbРазвёртываем RGW:
# Создаём spec-файл для RGW
cat > rgw-spec.yaml << 'EOF'
service_type: rgw
service_id: objectstore
service_name: rgw.objectstore
placement:
count: 2
label: "rgw"
spec:
rgw_frontend_port: 8080
rgw_frontend_extra_args:
- "tcp_nodelay=1"
- "request_timeout_ms=30000"
EOF
# Добавляем label на узлы, где будет RGW
sudo cephadm shell -- ceph orch host label add node1 rgw
sudo cephadm shell -- ceph orch host label add node2 rgw
# Применяем spec
sudo cephadm shell -- ceph orch apply -i rgw-spec.yaml
# Проверяем
sudo cephadm shell -- ceph orch ls
sudo cephadm shell -- ceph orch ps | grep rgwНастраиваем SSL и HA с ingress:
# rgw-ingress-spec.yaml
service_type: ingress
service_id: rgw.objectstore
placement:
count: 2
label: rgw
spec:
backend_service: rgw.objectstore
virtual_ip: 192.168.1.100/24
frontend_port: 443
monitor_port: 1967
ssl_cert: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
ssl_key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----Kubernetes: Rook-Ceph Operator
Если у вас Kubernetes, Rook — лучший способ запустить Ceph:
# Устанавливаем Rook-operator
kubectl create namespace rook-ceph
kubectl apply -f https://raw.githubusercontent.com/rook/rook/v1.14.0/deploy/examples/crds.yaml
kubectl apply -f https://raw.githubusercontent.com/rook/rook/v1.14.0/deploy/examples/common.yaml
kubectl apply -f https://raw.githubusercontent.com/rook/rook/v1.14.0/deploy/examples/operator.yaml
# Ждём готовности operator
kubectl -n rook-ceph wait --for=condition=ready pod -l app=rook-ceph-operator --timeout=300sСоздаём CephCluster:
# ceph-cluster.yaml
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
cephVersion:
image: quay.io/ceph/ceph:v18.2.2
allowUnsupported: false
dataDirHostPath: /var/lib/rook
mon:
count: 3
allowMultiplePerNode: false
mgr:
count: 2
allowMultiplePerNode: false
modules:
- name: pg_autoscaler
enabled: true
- name: prometheus
enabled: true
dashboard:
enabled: true
ssl: true
storage:
useAllNodes: true
useAllDevices: true
# Или явно указываем устройства:
# nodes:
# - name: "worker-1"
# devices:
# - name: "sdb"
# - name: "sdc"
resources:
osd:
limits:
cpu: "2"
memory: "4Gi"
requests:
cpu: "1"
memory: "2Gi"Создаём Object Store:
# ceph-objectstore.yaml
apiVersion: ceph.rook.io/v1
kind: CephObjectStore
metadata:
name: my-store
namespace: rook-ceph
spec:
metadataPool:
replicated:
size: 3
dataPool:
erasureCoded:
dataChunks: 2
codingChunks: 1
preservePoolsOnDelete: true
gateway:
port: 80
securePort: 443
instances: 2
resources:
limits:
cpu: "2"
memory: "2Gi"
requests:
cpu: "500m"
memory: "1Gi"Создаём пользователя:
# ceph-objectstore-user.yaml
apiVersion: ceph.rook.io/v1
kind: CephObjectStoreUser
metadata:
name: my-user
namespace: rook-ceph
spec:
store: my-store
displayName: "S3 User"Е# Применяем
kubectl apply -f ceph-cluster.yaml
kubectl apply -f ceph-objectstore.yaml
kubectl apply -f ceph-objectstore-user.yaml
# Ждём готовности (может занять 5-10 минут)
kubectl -n rook-ceph wait --for=condition=ready cephcluster rook-ceph --timeout=600s
# Получаем credentials
kubectl -n rook-ceph get secret rook-ceph-object-user-my-store-my-user -o jsonpath='{.data.AccessKey}' | base64 -d
kubectl -n rook-ceph get secret rook-ceph-object-user-my-store-my-user -o jsonpath='{.data.SecretKey}' | base64 -d
# Получаем endpoint
kubectl -n rook-ceph get svc rook-ceph-rgw-my-storeErasure Coding vs Replication
Ceph поддерживает два способа защиты данных:
Replication (репликация):
Простая: данные копируются N раз.
Overhead: 200% при 3 репликациях (1TB данных = 3TB на дисках).
Производительность: быстрее на чтение.
Надёжность: переживает потерю N-1 узлов.
Erasure Coding (EC):
Сложная: данные разбиваются на K чанков + M чанков чётности.
Overhead: зависит от профиля (например, 4+2 = 50% overhead).
Производительность: медленнее, больше CPU.
Надёжность: переживает потерю M-узлов.
# Создаём EC-профиль
sudo ceph osd erasure-code-profile set ec-42-profile \
k=4 m=2 \
crush-failure-domain=host
# Создаём EC pool
sudo ceph osd pool create ec-data-pool 32 32 erasure ec-42-profile
# Для RGW: используем EC для data pool
sudo radosgw-admin zone placement modify \
--rgw-zone=default \
--placement-id=default-placement \
--data-pool=ec-data-poolМониторинг Ceph
Ceph имеет встроенный модуль Prometheus:
# Включаем модуль
sudo ceph mgr module enable prometheus
# Метрики доступны на порту 9283
curl http://ceph-mgr-host:9283/metricsКлючевые метрики:
Метрика | Описание | Alert |
|---|---|---|
| 0=OK, 1=WARN, 2=ERR | != 0 |
| OSD online | == 0 |
| Деградированные PG | > 0 |
| Использование пула | > 80% |
| Латентность RGW | p99 > 500ms |
Alertmanager rules:
groups:
- name: ceph
rules:
- alert: CephHealthWarning
expr: ceph_health_status == 1
for: 5m
labels:
severity: warning
annotations:
summary: "Ceph health warning"
- alert: CephHealthError
expr: ceph_health_status == 2
for: 1m
labels:
severity: critical
annotations:
summary: "Ceph health critical"
- alert: CephOSDDown
expr: ceph_osd_up == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Ceph OSD {{ $labels.osd }} is down"Troubleshooting Ceph
Проблема: HEALTH_WARN
# Смотрим детали
sudo ceph health detail
# Частые причины:
# - "too few PGs per OSD" — увеличьте pg_num
# - "pool has no replicas configured" — настройте репликацию
# - "clock skew detected" — синхронизируйте NTPПроблема: медленные OSD
# Проверяем latency
sudo ceph osd perf
# Проверяем blocked requests
sudo ceph daemon osd.0 dump_blocked_ops
# Проверяем slow ops
sudo ceph daemon osd.0 dump_historic_slow_opsПроблема: RGW 503 errors
# Проверяем статус RGW
sudo systemctl status ceph-radosgw@rgw.*
# Смотрим логи
sudo journalctl -u ceph-radosgw@rgw.* -f
# Проверяем pools
sudo ceph osd pool ls detail | grep rgwКогда выбирать Ceph?
✅ Да:
Петабайты данных.
Нужны block + file + object из одного кластера.
Enterprise SLA обязателен.
Есть команда с опытом Ceph или готовностью учиться.
Kubernetes-native storage нужен.
❌ Нет:
Меньше 3 узлов.
Меньше 8GB RAM на узел.
Нет времени на обучение.
Quick and dirty решение.
OpenMaxIO: форк старого доброго MinIO
OpenMaxIO — это community-форк последней версии MinIO до удаления фич.
Развёртывание
# Docker (single node)
docker run -d \
--name openmaxio \
-p 9000:9000 \
-p 9001:9001 \
-v /data:/data \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=password123456" \
openmaxio/openmaxio:latest \
server /data --console-address ":9001"
# Веб-консоль доступна на :9001Важное предупреждение
⚠️ OpenMaxIO — community-проект без гарантий:
Нет коммерческой поддержки.
Обновления безопасности могут задерживаться.
Долгосрочная судьба проекта неизвестна.
Используйте на свой страх и риск.
Рекомендую рассматривать его только как временное решение на время миграции на SeaweedFS/Garage/Ceph.
Сравнительное тестирование производительности
Я провёл тестирование на идентичном железе для объективного сравнения:
Тестовый стенд:
3 x VM: 4 vCPU, 16GB RAM, 500GB NVMe SSD.
Network: 10Gbps между узлами.
OS: Ubuntu 24.04 LTS.
Методология
Использовал s3-benchmark:
# Тест 1: мелкие файлы (1KB x 100,000)
s3-benchmark -a ACCESS_KEY -s SECRET_KEY \
-b test-bucket -u http://endpoint:port \
-t 32 -z 1K -n 100000
# Тест 2: средние файлы (1MB x 10,000)
s3-benchmark -a ACCESS_KEY -s SECRET_KEY \
-b test-bucket -u http://endpoint:port \
-t 32 -z 1M -n 10000
# Тест 3: большие файлы (100MB x 100)
s3-benchmark -a ACCESS_KEY -s SECRET_KEY \
-b test-bucket -u http://endpoint:port \
-t 16 -z 100M -n 100Результаты
Тест 1: мелкие файлы (1KB x 100,000)
Решение | Write ops/sec | Read ops/sec | Write MB/s | Read MB/s |
|---|---|---|---|---|
MinIO (baseline) | 12,500 | 18,200 | 12.2 | 17.8 |
SeaweedFS | 45,000 | 52,000 | 43.9 | 50.8 |
Garage | 8,200 | 11,500 | 8.0 | 11.2 |
Ceph RGW | 6,800 | 9,400 | 6.6 | 9.2 |
SeaweedFS выигрывает на мелких файлах благодаря архитектуре Haystack, которая включает распределённые метаданные.
Тест 2: средние файлы (1MB x 10,000)
Решение | Write ops/sec | Read ops/sec | Write MB/s | Read MB/s |
|---|---|---|---|---|
MinIO | 850 | 1,200 | 850 | 1,200 |
SeaweedFS | 920 | 1,350 | 920 | 1,350 |
Garage | 680 | 950 | 680 | 950 |
Ceph RGW | 780 | 1,100 | 780 | 1,100 |
На средних файлах разница сглаживается — все решения упираются в сеть и диски.
Тест 3: большие файлы (100MB x 100)
Решение | Write MB/s | Read MB/s | CPU % | RAM GB |
|---|---|---|---|---|
MinIO | 980 | 1,150 | 45% | 2.1 |
SeaweedFS | 920 | 1,080 | 38% | 1.8 |
Garage | 850 | 980 | 25% | 0.8 |
Ceph RGW | 890 | 1,050 | 52% | 3.2 |
Garage показывает минимальное потребление ресурсов благодаря реализации на Rust.
S3 API Compatibility
Тестировал с помощью ceph/s3-tests:
Feature | MinIO | SeaweedFS | Garage | Ceph RGW |
|---|---|---|---|---|
Basic GET/PUT/DELETE | ✅ | ✅ | ✅ | ✅ |
Multipart Upload | ✅ | ✅ | ✅ | ✅ |
Presigned URLs | ✅ | ✅ | ✅ | ✅ |
Versioning | ✅ | ❌ | ❌ | ✅ |
Lifecycle Policies | ✅ | ❌ | ❌ | ✅ |
Object Lock | ✅ | ❌ | ❌ | ✅ |
Bucket Policies | ✅ | Partial | Partial | ✅ |
IAM | ✅ | Basic | Basic | ✅ |
Server-Side Encryption | ✅ | ✅ | ✅ | ✅ |
Cross-Region Replication | ✅ | ✅ | ✅ | ✅ |
S3 Select | ✅ | ❌ | ❌ | ✅ |
Compatibility score (ceph s3-tests):
Ceph RGW: 576/700 passed (82%).
MinIO: 321/700 passed (46%).
SeaweedFS: ~200/700 passed (~29%).
Garage: ~150/700 passed (~21%).
Итоговая сравнительная таблица
Критерий | SeaweedFS | Garage | Ceph RGW | OpenMaxIO |
|---|---|---|---|---|
Лицензия | Apache 2.0 ✅ | AGPL v3 ⚠️ | LGPL ✅ | Apache 2.0 ✅ |
Язык | Go | Rust | C++ | Go |
Min. RAM | 2GB | 512MB | 8GB | 4GB |
Min. CPU | 2 cores | 1 core | 4 cores | 2 cores |
Min. узлов (HA) | 3 | 3 | 3 | 4 |
S3 совместимость | ~70% | ~60% | ~90% | ~95% |
Versioning | ❌ | ❌ | ✅ | ✅ |
Lifecycle | ❌ | ❌ | ✅ | ✅ |
Object Lock | ❌ | ❌ | ✅ | ✅ |
Erasure Coding | ✅ | ❌ (3x repl) | ✅ | ✅ |
Geo-replication | ✅ | ✅ (native) | ✅ | ✅ |
Web UI | ✅ Filer | Community | ✅ Dashboard | ✅ |
Kubernetes native | Helm | Manual | Rook ✅ | Operator |
Сложность | Средняя | Низкая | Высокая | Низкая |
Production-ready | ✅ | ✅ (< 50TB) | ✅ | ⚠️ Community |
Лучший для | CDN, медиа | Edge, homelab | Enterprise | Миграция |
Заключение
Уход MinIO в коммерческое русло — это боль для тысяч инженеров по всему миру, но также это хороший толчок для засидевшихся админов, которые получили возможность изучить что-то новое.
Мои личные рекомендации:
Для большинства случаев — SeaweedFS. Отличный баланс фич, производительности и сложности. Apache 2.0 лицензия снимает юридические риски.
Для edge/homelab — Garage. Минимальные требования к ресурсам, встроенная георепликация, простота.
Для enterprise — Ceph. Да, сложно. Да, нужна команда. Но это единственное решение, которое масштабируется до петабайт и даёт unified storage.
Для срочной миграции — OpenMaxIO как временное решение, с планом перехода на что-то из п.1-3.
И главное помните: вопрос не в том, какое решение лучше в синтетических тестах, а в том, какое лучше для вас. Поэтому тестируйте и удачи с миграцией!
*Принадлежит компании Meta, признанной экстремистской и запрещённой в России.
© 2026 ООО «МТ ФИНАНС»

