Свой S3 или пошаговая настройка Garage
Здрасти, здрасти. Теперь по выходным у меня полнейший «цифровой детокс», а причина этому — дача. Круче всякого спортзала прокачивает, а заодно прочищает голову. Физический труд всегда в почёте.
Ладно, это детали… сегодня будем поднимать собственный S3 и да, без хуйни вроде minio и ceph.
читать первым в телеграм читать первым в макс
А на помощь к нам приходит «Гараж», в котором мы и будем хранить наши «Вёдра». Garage ориентирован на маленький и средние кластера, домашние сервера и распределенные ноды. И да, он полностью в opensource и не просит денег. Для self-host пиздатейшее решений, да и морда есть из коробки.
Я возьму 3 своих рандомных сервера и сделаю из них кластер. Сервера не пустые, на них что-то крутится и вертится, просто рядышком впендюрю еще одну хуёвинку.
Почему именно 3 сервера? Кластерная классика, если один из серверов пойдёт по пизде, то 2 других соберут кворум и отдадут тебе твои данные. То есть тебе не нужно иметь заранее подготовленные машины, можно взять какойнить хлам и из него запилить кластер под бекапы. И всё это дело будет работать нативно через API S3.
Прицепом воткнем балансировщик нагрузки, чтобы по домену всё работало. И да, запускать будем в докере.
Поехали настроим это безобразие.
Демон докера надеюсь у тебя уже установлен, поэтому заострять внимание на этом не будем. Заходим на первый сервер и мутим мутки:
Файл compose.yaml:
services:
garage:
image: dxflrs/garage:v2.3.0
ports:
- "3900:3900" # S3 API
- "3901:3901" # RPC
- "3902:3902" # Web (optional)
- "3903:3903" # Admin API
volumes:
- ./garage.toml:/etc/garage.toml:ro
- ./meta:/var/lib/garage/meta
- ./data:/var/lib/garage/data
Думаю, вопросов не должно возникнуть. Банальный композник, порты я тебе все подписал. Версию гаража можешь глянуть в интернете, на момент написания статьи последняя v2.3.0. Да буква «v» тут важна и latest тут не канает.
Рядышком подкидываем конфиг garage.toml:
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
replication_factor = 3
consistency_mode = "consistent"
rpc_bind_addr = "0.0.0.0:3901"
rpc_public_addr = "95.95.95.95:3901"
rpc_secret = "5a69376ed4253b21370dbdfda2a5e..."
[s3_api]
api_bind_addr = "0.0.0.0:3900"
s3_region = "garage"
[admin]
api_bind_addr = "0.0.0.0:3903"
Создаём секрет для rpc_secret:
openssl rand -hex 32
Обращаем внимание на параметр rpc_public_addr это общедоступный адрес, можешь связать все 3 сервера приватной сетью через тот же netbird и прописать айпишник сюда. Он нужен для кластера. Все остальные параметры, тоже интуитивно понятны.
Например consistency_mode нужен, чтобы соблюдать строгую консистентность, прям как в настоящих S3.
Запускаем: docker compose up

Супер, мастер нода успешно запущена. Теперь можно добавить ключик -d и запустить контейнер в фоне.
Теперь отправляемся на 2 других сервера и конфигурируем их. Будут нюансы, поэтому повнимательнее.
Композник оставляем такой же, как и на первой ноде, а в конфиге меняем только параметр rpc_public_addr. Запускаем в фоне docker compose up -d.
Запускаем в консоли:
docker exec -it garage-garage-1 /garage node id
И смотрим выхлоп:

Что-то есть. Дальше план такой:
- Поднимаем оставшиеся ноды
- Получаем их IDшники
- Собираем кластер
Так, айдишники у нас на руках, идем на первую ноду и добавляем 2 других ноды:
docker exec -it garage-garage-1 /garage node connect ID2
docker exec -it garage-garage-1 /garage node connect ID3
В ID2 и ID3 подставляем те самые строки вида:
193e204ac94c92d0a81e59841735@79.45.31.104:3901
e77af28b18504c80ca57f61dd3cd@102.51.11.56:3901

Проверяем связку:
docker exec -it garage-garage-1 /garage status

Отлично, оно живое. Продолжаем разговор.
Поздравляю, кластер S3 успешно собран. Теперь нужно пройтись напильником:
docker exec -it garage-garage-1 /garage layout assign 193e204ac94c92d0 -z z1 -c 1G
docker exec -it garage-garage-1 /garage layout assign 86535d1f65cde795 -z z2 -c 1G
docker exec -it garage-garage-1 /garage layout assign b897100c9b408729 -z z3 -c 1G
Айдишники меняем на свои (выше на скрине они есть, когда запрашивает статус кластера), следом указываем зону и размер стораджа. Для примера я выставил 1 гигабайт. Для синтетических тестов этого вполне хватит.
Смотрим что у нас получилось:
docker exec -it garage-garage-1 /garage layout show

Видим что всё прекрасно, все 3 ноды видны, они в кластере, доступен 1 гигабайт.
Применяем:
docker exec -it garage-garage-1 /garage layout apply --version 1

Аще заебись! Снова смотрим статус:
docker exec -it garage-garage-1 /garage status

Вуаля, хранилище создано и введено в эксплуатацию. Гараж балансирует данные и синхронизирует ноды.
Теперь у тебя есть полноценный и свой собственный S3. Можешь его теперь ебать и в хвост и в гриву.
А как? Ну для начала нужно сгенерить API ключик, выполняем:
docker exec -it garage-garage-1 /garage key create bashdays-key

Получаем ожидаемый результат. Тут нужно забрать Key ID и Secret key, они пригодятся для подключения.
Создаем первый bucket:
docker exec -it garage-garage-1 /garage bucket create bashdays-bucket

Выдаем доступ:
docker exec -it garage-garage-1 /garage bucket allow --read --write --owner bashdays-bucket --key bashdays-key

Ну и всё. теперь можно проверить, я взял rclone и сконфигурировал так:
[garage]
type = s3
provider = Other
access_key_id = GK5eba63ef8f5
secret_access_key = a0333b9e7a9d61f
region = garage
endpoint = http://103.90.33.11:3900
Можем подключиться:
rclone lsd garage:
В результате видим:
-1 2026-04-27 14:30:49 -1 bashdays-bucket
То есть rclone успешно подключился по протоколу S3 и увидел наш созданный бакет. Давай загрузим файл и посмотрим как оно все пройдет:
echo "hello from garage" > /tmp/bashdays.txt
rclone copy /tmp/bashdays.txt garage:bashdays-bucket
rclone ls garage:bashdays-bucket
Что и требовалось доказать:

Всё прекрасно работает. Забираем файл обратно:
rclone copy garage:bashdays-bucket/bashdays.txt .

Красота неописуемая! Ну а теперь проверяем отказоустойчивость, гасим первый сервер docker compose down и смотрим статус. Статус запрашиваем на втором сервере:

Видим что первая нода пошла по пизде, но кластер не развалился. Запрашиваем файл со второй ноды. Но предварительно в rclone конфиге меняем endpoint на айпишник второй ноды.
rclone copy garage:bashdays-bucket/bashdays.txt .
cat bashdays.txt

Вот и произошла кластерная магия. Первый сервер сгорел, но наши данные не утеряны, у нас есть к ним доступ. Возвращаем первую ноду встрой и смотрим:
Супер, всё успешно восстановилось:

Основная настройка на этом закончена. Чуть позже покажу тебе как делать прямые ссылки на файлы, чтобы каждый желающий смог скачать файлы с твоего хранилища. Ну и накинем haproxy, чтобы оно прям по всем бест-практикам себя чувствовало.
А пока на этом всё, настоятельно рекомендую потыкать эту настройку и проникнуться.
