Garage в Docker Compose: готовый файл
Если серверов под объектное хранилище несколько и они стоят в разных дата-центрах или даже странах, MinIO начинает доставлять хлопоты: его erasure coding рассчитан на однородные узлы с быстрой сетью между ними, а не на три VPS в разных локациях с непредсказуемым пингом. Garage — S3-совместимое хранилище от французской ассоциации Deuxfleurs, написанное на Rust специально для геораспределённых и разнородных кластеров: меньше памяти, проще модель согласованности, честная работа при отвале одного узла. Дальше — готовый docker-compose.yml и пошаговая инициализация кластера от одного узла до трёх в разных локациях.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое Garage и чем он легче MinIO
Garage реализует подмножество S3 API — достаточное для большинства приложений: PutObject, GetObject, DeleteObject, multipart-загрузка, бакеты, политики доступа, статический веб-хостинг из бакета. Чего в нём нет или что реализовано ограниченно — версионирование объектов, Object Lock, часть административных вызовов AWS. Если приложению нужен именно этот функционал, сверьтесь с актуальным списком поддерживаемых операций в документации проекта перед тем, как переключать прод.
Ключевое отличие от MinIO — модель согласованности. MinIO для избыточности использует erasure coding: файл режется на части и раскладывается по дискам, что требует предсказуемой и быстрой сети между узлами. Garage вместо этого хранит целые копии объектов (репликация, а не шардирование) и использует CRDT для метаданных — структуры данных, которые сходятся к одному состоянию независимо от порядка получения обновлений. Узлы не обязаны договариваться синхронно через Raft-подобный консенсус на каждую операцию, поэтому кластер переживает временные разрывы связи между дата-центрами без блокировки записи.
Практический эффект: Garage можно раскидать по трём разным провайдерам в трёх странах, и он будет работать, пока связь есть хотя бы с частью узлов, определяющей кворум. Второй плюс — потребление ресурсов: одному узлу Garage для небольшого кластера хватает 256-512 МБ памяти, тогда как MinIO в кластерном режиме обычно требует заметно больше, особенно на объём с большим числом мелких объектов.
Обратная сторона — Garage моложе, и сообщество меньше: меньше готовых интеграций, нет встроенной веб-консоли (только CLI и минимальный HTTP admin API). Для зрелого инструмента с графическим интерфейсом присмотритесь к MinIO в Docker Compose. Для геораспределённого кластера на разношёрстных серверах с минимальным потреблением ресурсов — Garage создан именно для этого.
Архитектура: узлы, зоны и layout
Кластер Garage состоит из узлов (nodes), каждый — отдельный процесс/контейнер со своим node_id (генерируется автоматически из ключа при первом запуске). Узлы объединяются в кластер через RPC-соединение по TCP (порт 3901 по умолчанию), для которого все узлы должны знать общий rpc_secret — просто shared-секрет, а не сертификат.
Логическое распределение данных задаётся через layout — таблицу, в которой каждому узлу назначается зона (zone, обычно = дата-центр или регион) и ёмкость (capacity, вес узла в кластере). Garage распределяет реплики объекта так, чтобы по возможности они попадали в разные зоны — это и даёт геораспределённость: при replication_factor = 3 и трёх зонах каждый объект физически лежит в трёх разных локациях.
Три ключевых порта на каждом узле:
| Порт | Назначение |
|---|---|
| 3900 | S3 API (то, к чему подключается приложение/клиент) |
| 3901 | RPC между узлами кластера |
| 3902 | Статический веб-хостинг из бакета (опционально) |
| 3903 | Admin API — статус, layout, метрики Prometheus |
Метаданные (список объектов, layout, ключи доступа) Garage хранит в отдельной БД на движке LMDB или Sled, сами данные объектов — в data_dir как есть, файлами. Это упрощает бэкап и диагностику: можно посмотреть на файловую систему и понять, что где лежит.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверГотовый docker-compose.yml для одного узла
Начнём с одного узла — этого достаточно, чтобы проверить, что всё работает, прежде чем разносить кластер по локациям. Структура каталогов на хосте:
mkdir -p /opt/garage/{etc,meta,data}
Конфиг /opt/garage/etc/garage.toml:
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "lmdb"
replication_factor = 1
rpc_bind_addr = "[::]:3901"
rpc_public_addr = "127.0.0.1:3901"
rpc_secret = "ВАШ_RPC_SECRET_64_HEX_СИМВОЛА"
[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.example.com"
[s3_web]
bind_addr = "[::]:3902"
root_domain = ".web.example.com"
index = "index.html"
[admin]
api_bind_addr = "[::]:3903"
admin_token = "ВАШ_ADMIN_TOKEN"
metrics_token = "ВАШ_METRICS_TOKEN"
rpc_secret сгенерируйте один раз и используйте одинаковым на всех узлах будущего кластера:
openssl rand -hex 32
docker-compose.yml:
services:
garage:
image: dxflrs/garage:v1.0.1
container_name: garage
restart: unless-stopped
ports:
- "3900:3900"
- "3901:3901"
- "3902:3902"
- "3903:3903"
volumes:
- ./etc/garage.toml:/etc/garage.toml:ro
- ./meta:/var/lib/garage/meta
- ./data:/var/lib/garage/data
Версию образа dxflrs/garage перед запуском сверьте с тегами на Docker Hub или релизами на GitHub проекта — Garage обновляется чаще, чем этот текст, а мажорная версия влияет на формат конфига. Поднимаем:
docker compose up -d
docker compose logs -f garage
В логе при первом старте появится сгенерированный node_id — он понадобится на следующем шаге.
Инициализация кластера, бакеты и ключи доступа
Даже одиночному узлу нужен layout — без него Garage не начинает принимать данные. Все команды выполняются через garage CLI внутри контейнера:
docker compose exec garage garage status
Вывод покажет узел со статусом NO ROLE ASSIGNED и его ID (короткий хеш вида a1b2c3d4...). Назначаем ему зону и ёмкость, затем применяем layout:
docker compose exec garage garage layout assign -z dc1 -c 10G a1b2c3d4
docker compose exec garage garage layout show
docker compose exec garage garage layout apply --version 1
Версию (--version 1) Garage подскажет сам в выводе layout show — это защита от случайного применения layout, рассчитанного на другое состояние кластера. После применения garage status должен показать узел как healthy.
Дальше — бакет и ключ доступа:
docker compose exec garage garage bucket create my-app-storage
docker compose exec garage garage key create my-app-key
docker compose exec garage garage bucket allow \
--read --write --owner my-app-storage --key my-app-key
Команда key create выведет Key ID и Secret Access Key — сохраните их сразу, повторно secret не показывается (можно только пересоздать ключ). Эти два значения и есть то, что вы пропишете в приложении вместо AWS-ключей, s3_region из конфига (garage в примере выше) — вместо AWS-региона.
Геораспределённый кластер на несколько локаций
Смысл Garage раскрывается, когда узлов больше одного и они физически разнесены. Сценарий: три VPS в разных локациях — например, в России, ЕС и США. На каждом сервере — тот же docker-compose.yml и тот же garage.toml, но с двумя отличиями: rpc_public_addr указывает на публичный IP именно этого сервера, а rpc_secret — одинаковый на всех трёх.
rpc_public_addr = "203.0.113.10:3901"
Порт 3901 должен быть открыт между узлами (в файрволе — разрешить входящие с IP остальных узлов кластера, не открывать всему интернету без необходимости). После старта всех трёх контейнеров узлы нужно свести в один кластер командой garage node connect, выполненной с любого из них в сторону остальных:
docker compose exec garage garage node connect <node_id_2>@203.0.113.20:3901
docker compose exec garage garage node connect <node_id_3>@203.0.113.30:3901
Дальше — layout с тремя зонами и replication_factor = 3 в конфиге каждого узла (после первого запуска фактор репликации без пересоздания кластера не поменять, так что закладывайте его сразу):
docker compose exec garage garage layout assign -z ru -c 10G <node_id_1>
docker compose exec garage garage layout assign -z eu -c 10G <node_id_2>
docker compose exec garage garage layout assign -z us -c 10G <node_id_3>
docker compose exec garage garage layout apply --version 1
С этого момента каждый записанный объект реплицируется в три зоны, и клиент может обращаться к S3 API любого из трёх узлов — данные будут те же. Для распределения клиентов по узлам обычно ставят перед кластером балансировщик или geo-DNS, отдающий ближайший узел; если это ваш случай, пригодится статья про гео-DNS и когда он нужен. Учтите и задержку между зонами: запись подтверждается, когда кворум реплик её принял, поэтому медленный канал между дата-центрами замедлит запись — для бэкапов и статики это не критично, но для синхронной записи с жёстким SLA латентность стоит измерить заранее на вашей паре локаций.
Проверка S3 API, мониторинг и бэкап метаданных
Проверить, что S3 API отвечает, можно любым S3-клиентом. Быстрее всего — через rclone, который умеет работать с произвольным S3-совместимым эндпоинтом:
[garage]
type = s3
provider = Other
access_key_id = ВАШ_KEY_ID
secret_access_key = ВАШ_SECRET
endpoint = http://ВАШ_СЕРВЕР:3900
region = garage
rclone lsd garage:
rclone copy ./test.txt garage:my-app-storage/
Если предпочитаете держать rclone тоже в контейнере рядом — есть готовый rclone в Docker Compose. Тем же способом подключаются aws-cli (aws --endpoint-url http://ВАШ_СЕРВЕР:3900 s3 ls) и SDK приложения — меняете только endpoint_url, region и ключи.
Мониторинг: admin API отдаёт метрики в формате Prometheus на /metrics порта 3903 (авторизация — заголовком с metrics_token из конфига). Основные метрики — число объектов, занятое место по узлам, состояние layout, задержки RPC между узлами; последнее особенно важно в геораспределённом кластере, где рост RPC-латентности — первый признак проблем с сетью между локациями.
Бэкап в Garage — двухуровневый. Сами данные объектов уже реплицированы кластером, поэтому отдельно бэкапить их обязательно только если репликация меньше 3 или вы не доверяете кластеру целиком (например, единая точка отказа в оплате всех серверов у одного провайдера). Метаданные (layout, бакеты, ключи) — то, что действительно больно потерять: держите свежую копию garage.toml и rpc_secret вне серверов кластера, а сам каталог meta можно снапшотить штатными средствами тома (LVM/ZFS snapshot) или синхронизировать в другой бакет через rclone sync. Общие принципы разворачивания Docker Compose на проде, включая типичные грабли с правами на volume и restart-политиками, разобраны в статье про частые ошибки Docker Compose на сервере.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Чем Garage принципиально отличается от MinIO, если оба говорят по S3?
Моделью отказоустойчивости: MinIO режет объект на части (erasure coding) и рассчитан на однородный кластер с быстрой сетью, Garage хранит целые копии и использует CRDT для метаданных, что делает его устойчивее к разрывам связи между разными дата-центрами и легче по ресурсам на узел.
Можно ли начать с одного узла, а потом добавить ещё два для геораспределения?
Да, но replication_factor в конфиге поменять на лету нельзя без пересоздания кластера — если план на 3 узла в разных локациях, закладывайте replication_factor = 3 сразу, даже если на старте физически один узел.
Нужен ли отдельный балансировщик перед кластером Garage?
Не обязательно — любой узел отвечает на S3-запросы с одинаковыми данными, клиент может стучаться в любой. Балансировщик или geo-DNS нужны, если хотите направлять клиентов на ближайший географически узел ради задержки.
Есть ли у Garage веб-интерфейс, как консоль в MinIO?
Встроенной консоли у Garage нет, только CLI и HTTP admin API. Сторонние веб-панели существуют, но не входят в официальную поставку и их зрелость стоит проверить перед продакшн-использованием.
Что будет, если один из трёх узлов в другой стране надолго отвалится?
Кластер продолжит принимать запросы, пока доступен кворум оставшихся узлов и зон, покрывающих replication_factor; данные, которые были только на упавшем узле, восстановятся репликацией после его возврата в кластер.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →