Разделил хранимые данные по слоям: config, data, cache

This commit is contained in:
2026-06-15 10:58:05 +03:00
parent 157f626c2e
commit b1f97c105a
6 changed files with 20 additions and 12 deletions
+5 -2
View File
@@ -3,6 +3,9 @@
# CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o jellybit ./cmd/jellybit # CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o jellybit ./cmd/jellybit
# distroless/static несёт CA-сертификаты (HTTPS к LLM/TMDB). Пользователь # distroless/static несёт CA-сертификаты (HTTPS к LLM/TMDB). Пользователь
# задаётся в compose (user: "1000:1000"). # задаётся в compose (user: "1000:1000").
#
# Тома (см. compose): /config (ro, рендерится плейбуком — восстановимо при
# деплое) + /data (SQLite, бекапить-и-не-терять).
FROM gcr.io/distroless/static-debian12 FROM gcr.io/distroless/static-debian12
COPY jellybit /usr/local/bin/jellybit COPY jellybit /usr/local/bin/jellybit
@@ -10,8 +13,8 @@ COPY jellybit /usr/local/bin/jellybit
EXPOSE 8080 EXPOSE 8080
# В distroless нет shell/curl — проверку делает сам бинарь (порт берёт из # В distroless нет shell/curl — проверку делает сам бинарь (порт берёт из
# /data/config.toml). compose может переопределить параметры healthcheck. # /config/config.toml — дефолтный путь). compose может переопределить параметры.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD ["/usr/local/bin/jellybit", "healthcheck"] CMD ["/usr/local/bin/jellybit", "healthcheck"]
ENTRYPOINT ["/usr/local/bin/jellybit", "--config", "/data/config.toml"] ENTRYPOINT ["/usr/local/bin/jellybit", "--config", "/config/config.toml"]
+4 -3
View File
@@ -95,6 +95,7 @@ jellybit recognize <infohash> --dry-run [--context "..."] --config ./config.toml
бинарь: `jellybit healthcheck` (GET `/healthz` по порту из конфига, exit 0/1). бинарь: `jellybit healthcheck` (GET `/healthz` по порту из конфига, exit 0/1).
Контейнер: `user 1000:1000`, порт `8080` на хост, mount `/srv/media` (единая Контейнер: `user 1000:1000`, порт `8080` на хост, mount `/srv/media` (единая
песочница для хардлинков) + data-том с `config.toml`/SQLite; к qBittorrent — песочница для хардлинков) + том `/config` (ro, `config.toml`, восстановим при
по сети Docker. Конкретная деплой-обвязка (плейбук, секреты) держится в деплое) + data-том `/data` (SQLite, бекапить); к qBittorrent — по сети Docker.
отдельном приватном репозитории и в комплект не входит. Конкретная деплой-обвязка (плейбук, секреты) держится в отдельном приватном
репозитории и в комплект не входит.
+1 -1
View File
@@ -16,7 +16,7 @@ import (
// нет shell/curl: docker зовёт сам бинарь. // нет shell/curl: docker зовёт сам бинарь.
func runHealthcheck(args []string) error { func runHealthcheck(args []string) error {
fs := flag.NewFlagSet("healthcheck", flag.ContinueOnError) fs := flag.NewFlagSet("healthcheck", flag.ContinueOnError)
configPath := fs.String("config", "/data/config.toml", "путь к config.toml") configPath := fs.String("config", "/config/config.toml", "путь к config.toml")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
} }
+1 -1
View File
@@ -23,7 +23,7 @@ import (
// Только чтение: ни записи в БД, ни хардлинков. // Только чтение: ни записи в БД, ни хардлинков.
func runRecognize(args []string) error { func runRecognize(args []string) error {
fs := flag.NewFlagSet("recognize", flag.ContinueOnError) fs := flag.NewFlagSet("recognize", flag.ContinueOnError)
configPath := fs.String("config", "/data/config.toml", "путь к config.toml") configPath := fs.String("config", "/config/config.toml", "путь к config.toml")
dryRun := fs.Bool("dry-run", true, "только показать план, без изменений (единственный режим)") dryRun := fs.Bool("dry-run", true, "только показать план, без изменений (единственный режим)")
contextStr := fs.String("context", "", "доп. текстовый контекст для распознавания") contextStr := fs.String("context", "", "доп. текстовый контекст для распознавания")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
+1 -1
View File
@@ -33,7 +33,7 @@ import (
// воркер (фоном) → HTTP-сервер; останавливается по SIGINT/SIGTERM. // воркер (фоном) → HTTP-сервер; останавливается по SIGINT/SIGTERM.
func runServe(args []string) error { func runServe(args []string) error {
fs := flag.NewFlagSet("serve", flag.ContinueOnError) fs := flag.NewFlagSet("serve", flag.ContinueOnError)
configPath := fs.String("config", "/data/config.toml", "путь к config.toml") configPath := fs.String("config", "/config/config.toml", "путь к config.toml")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
} }
+8 -4
View File
@@ -283,7 +283,8 @@ Jellyfin ([jellyfin-layout.md](jellyfin-layout.md)). Правила:
- **qBit** — `savepath=/srv/media/downloads`, temp `/srv/media/incomplete`. - **qBit** — `savepath=/srv/media/downloads`, temp `/srv/media/incomplete`.
- **jellybit** — читает `downloads`, пишет в `movies`/`series`; свой - **jellybit** — читает `downloads`, пишет в `movies`/`series`; свой
SQLite/конфиг — отдельным mount'ом `/srv/applications/jellybit/data`. SQLite — отдельным mount'ом `/srv/applications/jellybit/data`, конфиг —
отдельным `/srv/applications/jellybit/config`.
- **Jellyfin** — библиотеки указывают на `movies`/`series` (не на корень - **Jellyfin** — библиотеки указывают на `movies`/`series` (не на корень
`/srv/media`, иначе в индекс попадут downloads/incomplete). `/srv/media`, иначе в индекс попадут downloads/incomplete).
@@ -323,10 +324,13 @@ Jellybit работает в **docker** — в одной среде с qBittorr
- **`user: "1000:1000"`**, UMASK 022 — единый системный пользователь - **`user: "1000:1000"`**, UMASK 022 — единый системный пользователь
umbar; созданные каталоги 0755, файлы-ссылки наследуют inode источника. umbar; созданные каталоги 0755, файлы-ссылки наследуют inode источника.
- **mount `/srv/media`** (единая песочница) — для хардлинков и move - **mount `/srv/media`** (единая песочница) — для хардлинков и move
(см. «Пути и контейнеры»); `/srv/applications/jellybit/data` — отдельно. (см. «Пути и контейнеры»); каталоги jellybit — отдельно.
- **mount конфига** `/srv/applications/jellybit/config``/config` (ro):
`config.toml` (0600). Восстановим при деплое (рендерит плейбук umbar) —
бекапить не нужно.
- **mount данных** `/srv/applications/jellybit/data``/data`: SQLite - **mount данных** `/srv/applications/jellybit/data``/data`: SQLite
(`/data/jellybit.db`) и `config.toml`. Без него редеплой стёр бы всё (`/data/jellybit.db`). Бекапить-и-не-терять — без него редеплой стёр бы
in-flight состояние. всё in-flight состояние.
- **healthcheck** на `/healthz`. - **healthcheck** на `/healthz`.
Разделение ответственности: Разделение ответственности: