build(deploy): build images on the server instead of publishing to a registry
ci / api (push) Successful in 50s
ci / recommender (push) Successful in 37s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (apps/web/Dockerfile, web, ) (push) Successful in 44s
release / android + release (push) Failing after 53s
ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 45s
ci / ts (packages + web) (push) Successful in 37s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, api, api) (push) Successful in 1m30s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/api/Dockerfile, storage-agent, storage-agent) (push) Successful in 52s
ci / docker (образы собираются — их сервер собирает сам при обновлении) (services/recommender/Dockerfile, recommender, ) (push) Successful in 28s
ci / mobile (Metro-бандл Android) (push) Successful in 49s
release / verify (push) Successful in 1m14s

- deploy/compose.yaml: every app service has `build:` (repo root context),
  local tags pipu-music-<service>:<version>
- deploy/update.sh: git fetch → checkout tag (latest release by default,
  or vX.Y.Z / main) → docker compose build --pull → up -d → prune → /readyz;
  re-executes from a temp copy because checkout may replace the script
- install.sh / .env.example: no REGISTRY, PIPU_VERSION set by update.sh,
  .env owned by the invoking user
- release.yml: drop image publishing; release ships APK + sha256 only
- ci.yml: new `docker` job builds all images without push
- docs: install guide uses git clone, deployment/ci-cd updated, ADR-013

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-20 00:16:05 +03:00
1 parent 1633b28c1a
commit 01319c58d7
11 files changed
+201 -186

No files matched your search

+22 -72
View File
@@ -32,85 +32,33 @@
Перед первым запуском: `mkdir -p /srv/pipu/library && mount --bind /srv/pipu/library /srv/pipu/library && mount --make-rshared /srv/pipu/library`
(делает `deploy/install.sh`, плюс systemd-unit для повторения после перезагрузки).
## `deploy/compose.yaml` (сокращённо)
## `deploy/compose.yaml`
```yaml
x-library-ro: &library-ro
type: bind
source: /srv/pipu/library
target: /library
read_only: true
bind: { propagation: rslave }
Актуальная конфигурация — сам файл [`deploy/compose.yaml`](../deploy/compose.yaml); здесь — как он устроен.
services:
nginx:
image: ${REGISTRY}/pipu-music-web:${PIPU_VERSION}
ports: ["443:443", "80:80"]
volumes:
- *library-ro
- /srv/pipu/cache:/cache:ro
- /srv/pipu/uploads:/uploads:ro # прослушивание очереди админом (internal location)
- ./certs:/etc/nginx/certs:ro
depends_on: [api]
- **Образы собираются на сервере** из клонированного репозитория (`build:` у каждого сервиса, контекст — корень репо),
в реестр ничего не публикуется. Теги локальные: `pipu-music-<сервис>:<версия>`, версия — `git describe` текущего тега
(её проставляет `update.sh` в `PIPU_VERSION`).
api:
image: ${REGISTRY}/pipu-music-api:${PIPU_VERSION}
env_file: .env
volumes:
- *library-ro
- /srv/pipu/cache:/cache
- /srv/pipu/updates:/updates
- /srv/pipu/uploads:/uploads
depends_on: [postgres, redis, meilisearch, storage-agent]
| Сервис | Собирается из | Особенности |
|---|---|---|
| `nginx` | `apps/web/Dockerfile` | SPA + конфиг nginx; единственный открытый порт (`HTTP_PORT`) или за Caddy |
| `api` | `services/api/Dockerfile`, target `api` | Миграции при старте |
| `storage-agent` | `services/api/Dockerfile`, target `storage-agent` | `CAP_SYS_ADMIN`, `apparmor:unconfined`, библиотека с `propagation: rshared` |
| `recommender`, `analyzer` | `services/recommender/Dockerfile` (один образ) | Команды `serve` и `analyze --workers 4` |
| `postgres` | `pgvector/pgvector:pg17` | Healthcheck `pg_isready` |
| `redis` | `redis:7-alpine` | AOF |
| `meilisearch` | `getmeili/meilisearch:v1.11` | |
| `caddy` (из `compose.tls.yaml`) | `caddy:2.10-alpine` | HTTPS на `DOMAIN`, nginx тогда без открытых портов |
storage-agent:
image: ${REGISTRY}/pipu-music-storage-agent:${PIPU_VERSION}
cap_add: [SYS_ADMIN]
security_opt: ["apparmor:unconfined"]
volumes:
- type: bind
source: /srv/pipu/library
target: /library
bind: { propagation: rshared }
- /srv/pipu/uploads:/uploads:ro # читает staging при импорте
# /library-rw/<id> монтируется агентом внутри своего контейнера, наружу не пробрасывается
environment: [INTERNAL_TOKEN, DATABASE_URL, PIPU_FILE_UID, PIPU_FILE_GID]
recommender:
image: ${REGISTRY}/pipu-music-recommender:${PIPU_VERSION}
command: ["serve"]
env_file: .env
depends_on: [postgres, redis]
analyzer:
image: ${REGISTRY}/pipu-music-recommender:${PIPU_VERSION}
command: ["analyze", "--workers", "4"]
env_file: .env
volumes: [*library-ro, /srv/pipu/models:/models]
deploy: { resources: { limits: { cpus: "4" } } }
postgres:
image: pgvector/pgvector:pg17
volumes: [/srv/pipu/postgres:/var/lib/postgresql/data]
redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
volumes: [/srv/pipu/redis:/data]
meilisearch:
image: getmeili/meilisearch:v1.11
environment: [MEILI_MASTER_KEY, MEILI_ENV=production]
volumes: [/srv/pipu/meili:/meili_data]
```
Наружу открыт только `nginx`. Все остальные — во внутренней сети compose.
- Библиотека монтируется в `nginx`, `api`, `analyzer` только на чтение с `propagation: rslave`.
- Наружу открыт только `nginx` (или `caddy`). Все остальные — во внутренней сети compose.
## Конфигурация (`.env`)
| Переменная | Пример / по умолчанию | Описание |
|---|---|---|
| `PIPU_VERSION` | `1.0.0` | Версия образов |
| `PIPU_VERSION` | проставляет `update.sh` | Версия собранных образов (`git describe`) |
| `PUBLIC_URL` | `https://music.home.lan` | Внешний адрес |
| `DATABASE_URL` | `postgres://pipu:…@postgres:5432/pipu` | |
| `REDIS_URL` | `redis://redis:6379/0` | |
@@ -150,7 +98,9 @@ services:
## Обновление
```bash
cd /opt/pipu && ./update.sh 1.3.0 # pull образов, up -d, миграции при старте api, проверка /readyz
cd /opt/pipu-music/deploy && ./update.sh # последний релизный тег
```
Откат: `./update.sh 1.2.4` (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить,
Скрипт: `git fetch` → checkout тега → `docker compose build --pull` → `up -d` → удаление старых образов →
ожидание `/readyz`; миграции применяются при старте api.
Конкретная версия или откат: `./update.sh v1.2.4` (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить,
потом — в следующем релизе — удалить).