- PVSM.RU - https://www.pvsm.ru -
Мы делаем Pier — open‑source панель для деплоя приложений на свои серверы, по смыслу близкую к Coolify, Dokku или CapRover. Подключаешь Git‑репозиторий, получаешь контейнер за Traefik с сертификатом Let's Encrypt, бэкапы базы в S3 и алерты.
Функционально таких проектов много, поэтому в этой статье речь пойдёт не о том, что Pier умеет, а о том, как он устроен: мы с самого начала ставили жёсткое ограничение по ресурсам и почти каждое архитектурное решение выросло из него. За семь месяцев и ~550 коммитов набралось достаточно решений и граблей, о которых хочется рассказать.
Coolify после установки поднимает Laravel‑приложение, PostgreSQL, Redis, Horizon, Soketi и Traefik. В простое это 750 МБ — 1,2 ГБ RAM. Для с 1 ГБ памяти это неприемлемо: панель съедает сервер раньше, чем на нём появится первое приложение.
Отсюда требование: панель в простое должна занимать десятки мегабайт, а не сотни. В итоге получилось 20–40 МБ RSS для процесса Pier плюс Traefik. Ниже о том, за счёт чего.
|
Слой |
Выбор |
Почему |
|---|---|---|
|
Язык |
Rust |
один статический бинарник, без рантайма, предсказуемая память |
|
HTTP |
Axum + Tokio |
async, WebSocket для логов и метрик |
|
Docker |
Bollard |
Docker Engine API напрямую, без вызова CLI |
|
Хранилище |
SQLite (rusqlite) |
без отдельного контейнера с СУБД |
|
UI |
MiniJinja + HTMX + Alpine.js |
серверный рендеринг, ~30 КБ JS |
|
Стили |
Tailwind v3, собирается заранее |
итоговый CSS вшит в бинарник |
|
Прокси |
Traefik |
маршрутизация и ACME без нашего кода |
Панель хранит конфигурацию: проекты, сервисы, домены, секреты, историю деплоев, метрики алертов. Это небольшой объём данных с редкими записями от единственного процесса. Отдельный Postgres здесь дал бы +100–200 МБ памяти, ещё один контейнер, который нужно бэкапить и обновлять, и сетевую зависимость при старте панели.
Миграции у нас — append‑only массив SQL‑строк в коде; номер последней применённой хранится в БД. Никаких внешних инструментов миграций: бинарник при старте сам доводит схему до актуальной. Правило одно: старые миграции никогда не редактируются, только добавляются новые.
Панель управления — это в основном формы, таблицы и логи. SPA здесь означал бы отдельную сборку фронтенда, дублирование валидации и сотни килобайт JS. С HTMX сервер отдаёт готовые HTML‑фрагменты, а Alpine.js закрывает локальную интерактивность (модалки, вкладки, тумблеры).
Шаблоны MiniJinja, CSS, шрифты и переводы вшиты в бинарник через rust-embed. Следствие, о котором мы узнали не сразу: даже в debug‑сборке правка шаблона требует пересборки, потому что файлы с диска не читаются. Зато деплой самой панели — это замена одного файла.
Интерфейс переводится через rust-i18n, а текущая локаль запроса хранится в task‑local переменной Tokio. В шаблонах доступны функции t() и te(), в ошибках API — те же ключи. Каталог сейчас около 2000 ключей; добавить язык — значит положить ещё один YAML‑файл.
Изначально сессии были на JWT. Потом мы перешли на opaque‑сессии в SQLite и не жалеем:
JWT нельзя отозвать без чёрного списка, а чёрный список — это и есть серверное хранилище сессий, только неудобное.
Для панели с одним инстансом stateless‑аутентификация ничего не даёт: проверка сессии — это поиск по индексу в локальной SQLite.
С серверными сессиями просто сделать то, что нужно админке: выход со всех устройств при смене пароля, ротацию ID сессии после логина, абсолютный TTL, привязку к User‑Agent, сборку мусора просроченных сессий, мгновенный оффбординг удалённого пользователя.
Сверху — TOTP 2FA, роли с проверкой прав на уровне ресурса и API‑токены для CI.
На дополнительные серверы ставится pier-agent — отдельный лёгкий бинарник, который выполняет Docker‑операции и отдаёт метрики. Центральная панель общается с агентами по HTTP, агент шлёт heartbeat.
Самая интересная часть — кросс‑серверные кластеры баз данных: реплика MongoDB или Redis, разнесённая по разным машинам. Здесь пришлось решать связность контейнеров между хостами без оверлейной сети Docker Swarm. Мы публикуем порты узлов кластера в выделенном диапазоне и открываем их в файрволе только для внутренних подсетей.
Панель работает не от root. Но обновление затрагивает systemd‑юниты, вспомогательные сервисы и сам бинарник — это root‑операции. Решение:
Панель пишет файл‑запрос в специальную директорию.
systemd .path‑юнит видит файл и запускает root‑сервис pier-updater.
Апдейтер скачивает последний официальный релиз, проверяет sha256 и запускает тот же установщик, что и curl | bash.
Статус и лог пишутся в файлы, которые панель показывает пользователю.
Принципиальный момент: панель может только попросить обновиться. Какую версию и откуда ставить, решает root‑сторона. Скомпрометированная панель не может подсунуть апдейтеру свой бинарник.
Для репозиториев без Dockerfile мы интегрировали Railpack (преемник Nixpacks от Railway) поверх локального BuildKit. Это единственная по‑настоящему тяжёлая часть системы: компиляция пользовательского кода требует 4+ ГБ RAM и десятки гигабайт под кэш. Поэтому:
на хостах с RAM < 4 ГБ UI показывает жёсткое предупреждение;
параллельные сборки ограничены (по умолчанию одна);
кэш BuildKit ежедневно подрезается до ~10 ГБ / 7 дней;
установку Railpack можно отключить флагом, тогда остаются деплой из Dockerfile, образа и Compose.
Хостеры фильтруют порты. На одном из
Telegram‑алерты из России. api.telegram.org [2] на российских
Traefik, оставленный выключенным. Одно действие в панели могло остановить контейнер прокси и не поднять его обратно — все сайты на сервере ложились. Теперь панель гарантирует, что Traefik не может остаться в остановленном состоянии.
Один публичный порт, привязанный дважды. При редактировании сервиса порт мог попасть в конфигурацию контейнера дважды, и Docker отказывался его запускать. Мелочь, но из таких мелочей и состоит большая часть работы над PaaS.
Bitnami и MongoDB на новых ядрах. Обновление образов сломало кластерные шаблоны, а MongoDB не стартовала на свежих ядрах Linux. Поддержка каталога из 40 шаблонов оказалась отдельной постоянной работой.
|
|
Coolify |
Pier |
|---|---|---|
|
RAM в простое |
750 МБ — 1,2 ГБ |
20–40 МБ (+ Traefik) |
|
Диск |
~1 ГБ |
15–30 МБ |
|
Процессов/контейнеров панели |
6+ |
1 + Traefik |
|
Минимальный |
2 ГБ / 2 vCPU |
512 МБ / 1 vCPU |
Лицензия AGPL-3.0. Установка: curl -fsSL https://pier.team/install | sudo bash.
Код: github.com/joveptesg/pier [3]
Документация [4]
Если у вас есть опыт с Coolify, Dokku или CapRover, расскажите в комментариях, чего вам в них не хватало. Нам это поможет решить, что делать дальше.
Автор: alexlisg
Источник [5]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/vps/460218
Ссылки в тексте:
[1] VPS: https://www.reg.ru/?rlink=reflink-717
[2] api.telegram.org: http://api.telegram.org
[3] github.com/joveptesg/pier: https://github.com/joveptesg/pier
[4] Документация: https://pier.team/docs/getting-started/introduction
[5] Источник: https://habr.com/ru/articles/1095618/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1095618
Нажмите здесь для печати.