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
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:
1 parent
1633b28c1a
commit
01319c58d7
11 files changed
+201
-186
No files matched your search
+22
-72
@@ -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` (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить,
|
||||
потом — в следующем релизе — удалить).
|
||||
Reference in new issue
Block a user