SeaweedFS в Docker Compose: готовый файл
Когда в бакете миллионы мелких файлов — аватарки, превью, чанки видео, объекты IoT — обычная файловая система и даже классический S3-сервер начинают упираться в накладные расходы на метаданные: каждый файл съедает inode, каждый список директории тормозит. SeaweedFS спроектирован ровно под эту задачу: он группирует мелкие объекты в крупные volume-файлы и держит метаданные отдельно от данных, поэтому масштабируется до миллиардов файлов там, где другие решения начинают деградировать. Ниже — рабочий docker-compose.yml с master, volume-сервером, filer и S3 API, и на что обратить внимание при переходе в продакшен.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое SeaweedFS и когда он нужен
SeaweedFS — распределённая файловая система с открытым кодом, вдохновлённая архитектурой Facebook Haystack, которую Facebook в своё время использовал для хранения миллиардов фотографий. Идея простая: вместо того чтобы держать каждый мелкий файл отдельным inode на диске, SeaweedFS упаковывает файлы в крупные volume-файлы по несколько гигабайт и хранит только смещение (offset) файла внутри volume в оперативной памяти. Чтение объекта — это одно дисковое обращение, а не блуждание по дереву каталогов.
У системы три ключевых компонента:
- Master — координатор кластера. Знает, какие volume-серверы живы, сколько на них места, и выдаёт volume-серверам ID новых volume-файлов. Аналог namenode в HDFS, но существенно легче.
- Volume server — хранит сами данные: файлы объединены в volume-файлы фиксированного максимального размера (по умолчанию около 30 ГБ), внутри — компактный формат с минимумом накладных расходов на файл.
- Filer — надстройка, которая даёт файловую иерархию (директории, имена файлов) поверх плоского хранилища volume-серверов, плюс S3-совместимый API, WebDAV и FUSE-монтирование. Filer хранит метаданные во внешней БД — по умолчанию встроенный LevelDB, но для продакшена лучше PostgreSQL, MySQL или Redis.
Когда SeaweedFS оправдан:
- Хранилище для миллионов маленьких объектов — превью изображений, чанки для стриминга, файлы CDN-кэша.
- Нужен S3 API, но объектов настолько много, что метаданные в БД у альтернатив (например, у filer-less подхода MinIO) становятся узким местом.
- Нужна горизонтальная запись: добавили volume-сервер — сразу выросла и ёмкость, и пропускная способность записи, без ребалансировки всего кластера сразу.
- Нужна репликация на уровне volume (например, 001 — один дополнительный реплик в другой стойке/датацентре) без внешнего RAID или отдельного слоя вроде DRBD.
Когда не стоит: если у вас пара тысяч файлов и один бакет для бэкапов — это тот случай, когда MinIO в Docker Compose проще в эксплуатации и даёт тот же S3 API с меньшим числом движущихся частей. SeaweedFS выигрывает именно на масштабе и объёме мелких файлов, а не как замена MinIO «по умолчанию».
Готовый docker-compose.yml
Минимальный работоспособный кластер из одного master, одного volume-сервера и одного filer с включённым S3 API — этого достаточно для теста и для небольшой продакшен-нагрузки на одном сервере:
services:
master:
image: chrislusf/seaweedfs:3.79
container_name: seaweedfs-master
restart: unless-stopped
command: >
master
-ip=master
-mdir=/data
-volumeSizeLimitMB=1024
-defaultReplication=000
ports:
- "9333:9333"
- "19333:19333"
volumes:
- master_data:/data
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:9333/cluster/status"]
interval: 10s
timeout: 5s
retries: 5
volume:
image: chrislusf/seaweedfs:3.79
container_name: seaweedfs-volume
restart: unless-stopped
depends_on:
master:
condition: service_healthy
command: >
volume
-mserver=master:9333
-ip=volume
-port=8080
-max=50
-dir=/data
ports:
- "8080:8080"
- "18080:18080"
volumes:
- volume_data:/data
filer:
image: chrislusf/seaweedfs:3.79
container_name: seaweedfs-filer
restart: unless-stopped
depends_on:
master:
condition: service_healthy
volume:
condition: service_started
command: >
filer
-master=master:9333
-ip=filer
-s3
-s3.port=8333
environment:
WEED_LEVELDB2_ENABLED: "true"
ports:
- "8888:8888"
- "8333:8333"
- "18888:18888"
volumes:
- filer_data:/data
volumes:
master_data:
volume_data:
filer_data:
Порты по назначению: 9333 и 19333 — HTTP и gRPC мастера (UI кластера); 8080 и 18080 — HTTP и gRPC volume-сервера, наружу обычно не открывается; 8888 — HTTP filer с файловой иерархией и WebDAV; 8333 — S3-совместимый API, именно его указывают в клиентах; 18888 — служебный gRPC filer.
Наружу в реальной эксплуатации нужен только 8333 (S3) и, если нужен веб-доступ к файлам, 8888 — оба стоит спрятать за реверс-прокси с HTTPS, а не публиковать напрямую. Про сам подход к прокси — в статье про Traefik как реверс-прокси для Docker.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПервый запуск и проверка кластера
Поднимаем стек и ждём, пока все три сервиса станут healthy:
docker compose up -d
docker compose ps
Статус кластера через API мастера:
curl -s http://localhost:9333/cluster/status | python3 -m json.tool
В ответе должен быть один master в статусе leader и один volume-сервер в списке. Если volume не появился, смотрите его логи (docker compose logs volume --tail=50) — частая причина на старте в том, что volume-сервер не успел достучаться до master, пока тот ещё поднимался; depends_on с condition: service_healthy в конфиге выше как раз решает эту гонку.
Веб-интерфейс мастера доступен на http://<ip-сервера>:9333 — там видно карту volume-серверов, занятое место и статистику по репликации. Filer со своим файловым UI — на http://<ip-сервера>:8888.
S3 API: бакеты и загрузка через привычные инструменты
S3 API у SeaweedFS живёт в filer (порт 8333 в конфиге выше). Он совместим с тем же протоколом, что и AWS S3, MinIO и Garage — значит подходят те же клиенты: aws-cli, mc, boto3, rclone, restic.
По умолчанию S3 API SeaweedFS работает без аутентификации, что годится только для локального теста. Ключи задаются файлом конфигурации, который передаётся filer при старте:
{
"identities": [
{
"name": "app",
"credentials": [
{
"accessKey": "AKIAEXAMPLE",
"secretKey": "замените-на-случайный-секрет"
}
],
"actions": [
"Read",
"Write",
"List",
"Tagging",
"Admin"
]
}
]
}
Сохраните файл как s3-config.json, смонтируйте в контейнер filer и добавьте флаг:
filer:
# ...
command: >
filer
-master=master:9333
-ip=filer
-s3
-s3.port=8333
-s3.config=/etc/seaweedfs/s3-config.json
volumes:
- filer_data:/data
- ./s3-config.json:/etc/seaweedfs/s3-config.json:ro
Дальше работаем как с любым S3-совместимым хранилищем через mc (клиент MinIO, который умеет говорить с любым S3 API):
mc alias set sw http://localhost:8333 AKIAEXAMPLE замените-на-случайный-секрет
mc mb sw/uploads
mc cp ./photo.jpg sw/uploads/
mc ls sw/uploads
В коде приложения на boto3 разницы с настоящим S3 нет вообще — меняете endpoint_url на адрес своего сервера и ключи на свои, остальной код остаётся прежним.
Filer: файловая иерархия и точка входа для приложений
В отличие от плоского бакета S3 у filer есть настоящая иерархия каталогов, доступная по HTTP и WebDAV, — это удобно, если приложению нужно работать с путями, а не переписывать логику под ключи объектов. Загрузка файла через filer напрямую:
curl -F file=@photo.jpg "http://localhost:8888/uploads/photo.jpg"
curl "http://localhost:8888/uploads/photo.jpg" -o downloaded.jpg
Filer также умеет монтироваться как обычная файловая система через FUSE — полезно, если старое приложение ожидает путь на диске, а не HTTP-вызов:
weed mount -filer=localhost:8888 -dir=/mnt/seaweedfs
Важный момент по метаданным: по умолчанию filer хранит их во встроенном LevelDB прямо в volume контейнера. Для одного узла это работает, но не переживёт потерю тома без бэкапа и плохо ведёт себя при параллельном доступе нескольких filer-инстансов (если решите масштабировать filer горизонтально). Для продакшена стоит переключить filer на внешнюю БД — переменными окружения вида WEED_POSTGRES_ENABLED=true, WEED_POSTGRES_HOSTNAME, WEED_POSTGRES_DATABASE, WEED_POSTGRES_USER, WEED_POSTGRES_PASSWORD (полный список — в официальной документации SeaweedFS под конкретную СУБД: PostgreSQL, MySQL или Redis). Тогда несколько filer-контейнеров могут работать параллельно за одной базой, и вы получаете отказоустойчивость на уровне filer, а не только volume-серверов.
Продакшен: HTTPS, репликация, бэкап
Три вещи, которые стоит сделать до того, как на кластер пойдёт реальный трафик.
HTTPS через реверс-прокси. SeaweedFS сам по себе не терминирует TLS на S3-порту в стандартной конфигурации. Ставьте перед filer Traefik или nginx, который берёт сертификат Let's Encrypt и проксирует на 8333 порт filer внутри docker-сети — так S3-эндпоинт будет доступен по https://storage.example.com, а сам SeaweedFS наружу вообще не смотрит. Подробный разбор — в статье про Docker Compose для продакшена: те же принципы сетей, секретов и healthcheck применимы и здесь.
Репликация volume. Флаг -defaultReplication у master задаёт схему репликации в формате XYZ, где цифры — число дополнительных копий на уровнях: другой диск (X), другой сервер (Y), другой датацентр (Z). 000 из примера выше — без репликации, только для теста. На одном сервере с несколькими дисками разумно 100; если серверов несколько — 010 или 001 по топологии. Репликация требует кратно больше места, это не бесплатно.
Бэкап. Репликация — не бэкап: она не спасёт от случайного удаления бакета или бага в приложении. Регулярно снимайте weed backup для volume-серверов на отдельное хранилище либо синхронизируйте S3-бакет через rclone во внешнее объектное хранилище — время такой синхронизации сильно зависит от объёма и канала, ориентируйтесь на собственный замер, а не на чужие цифры.
SeaweedFS vs MinIO: что выбрать
Оба дают S3 API, но решают немного разные задачи:
| Критерий | SeaweedFS | MinIO |
|---|---|---|
| Сильная сторона | Миллиарды мелких файлов, низкие накладные расходы на метаданные | Простота эксплуатации, зрелая экосистема, erasure coding «из коробки» |
| Архитектура | Master + volume + filer, метаданные отдельно от данных | Единый бинарник, объекты и метаданные в одном движке |
| Порог входа | Выше — три роли, нужно понимать репликацию volume и БД для filer | Ниже — один контейнер, один конфиг, для старта хватает статьи выше |
| Файловая иерархия | Есть (filer): каталоги, WebDAV, FUSE-монтирование | Плоская модель бакетов, иерархия эмулируется префиксами ключей |
| Когда выбрать | CDN-кэш, чанки видео, миллионы аватарок/превью, где важна цена хранения на файл | Бэкапы, артефакты CI/CD, S3-бакет для одного-двух приложений |
Если сомневаетесь — начните с MinIO: он проще в поддержке, и для большинства задач «нужен свой S3» этого достаточно. Переходите на SeaweedFS, когда объектов десятки и сотни миллионов, а не тысячи, и вы уже упёрлись в конкретную метрику — например, время листинга бакета или память под метаданные.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
SeaweedFS подходит для хранения бэкапов через restic или rclone?
Да, оба работают с любым S3-совместимым API, включая SeaweedFS. Для сценария «бэкапы одного сервера» разница с MinIO небольшая — выбирайте по тому, что проще поддерживать именно вам.
Нужен ли отдельный volume-сервер на каждый диск?
Для продакшена — да: один volume-процесс на диск даёт максимум IOPS и упрощает мониторинг заполнения. На одном VPS с одним диском хватит одного volume-сервера, как в конфиге выше.
Что будет, если volume-сервер заполнится?
Master перестанет назначать на него новые volume-файлы и направит запись на серверы со свободным местом, уже записанные данные останутся доступны для чтения. Мониторьте /cluster/status или метрики Prometheus, чтобы не упереться в 100% неожиданно.
Можно ли мигрировать с MinIO на SeaweedFS без даунтайма?
Разово — да, через rclone sync между двумя S3-эндпоинтами с переключением endpoint_url в конфиге приложения. Совсем без даунтайма нужен период двойной записи в оба хранилища на время миграции — это логика на стороне приложения.
Работает ли SeaweedFS на слабом VPS?
Master и filer лёгкие, но volume-сервер кэширует индексы в памяти — на паре гигабайт RAM небольшой кластер работает нормально, для миллионов объектов закладывайте больше памяти и следите за метриками, а не ориентируйтесь на «должно хватить».
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →