Netpulse_SasS/docker-compose.yml
byrsapty a0eb2ff5f1
Some checks are pending
CI / web (push) Waiting to run
CI / server (push) Waiting to run
CI / agent (push) Waiting to run
Пакування: образи, повний стек, TLS, CI, процедура бекапу
Два образи замість пʼяти: серверні команди їдуть з одного модуля й
мусять ходити в схему БД однією версією, а зонд лишається окремо —
у чужій мережі йому не місце з DSN і ключами шифрування.

Стек піднімає БД, кеш, міграції, API, колектор і Caddy з автоматичним
TLS. Міграції окремою службою, бо API піднімається в кількох
примірниках і гонка за схему нікому не потрібна.

deploy/README.md описує бекап як три речі: дамп, DEK і JWT-ключ.
Без DEK дамп не відновлюється — у БД лише шифротекст.

Дорогою виправлено .gitignore: голі "netpulse-agent" і
"netpulse-server" ігнорували ще й каталоги cmd/ з кодом команд.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 12:47:54 +03:00

171 lines
5.9 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Повний стек NetPulse: БД, кеш, міграції, API з інтерфейсом, колектор
# зондів і зворотний проксі з автоматичним TLS.
#
# Швидкий старт:
# cp deploy/.env.example .env # і заповнити секрети
# docker compose up -d
# docker compose run --rm api netpulse-user -tenant default -login admin -role owner
#
# Тільки стенд для розробки (БД і кеш, решта — з go run):
# docker compose up -d db cache
name: netpulse
x-server-env: &server-env
NETPULSE_DSN: postgres://netpulse:${POSTGRES_PASSWORD:?потрібен POSTGRES_PASSWORD}@db:5432/netpulse?sslmode=disable
NETPULSE_DEK: ${NETPULSE_DEK:?потрібен NETPULSE_DEK — див. deploy/README.md}
NETPULSE_LOG_LEVEL: ${NETPULSE_LOG_LEVEL:-info}
TZ: ${TZ:-Europe/Kyiv}
services:
db:
image: timescale/timescaledb:2.17.2-pg16
environment:
POSTGRES_USER: netpulse
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?потрібен POSTGRES_PASSWORD}
POSTGRES_DB: netpulse
TIMESCALEDB_TELEMETRY: "off"
command:
- postgres
- -c
- shared_preload_libraries=timescaledb
- -c
- max_connections=200
- -c
- shared_buffers=${PG_SHARED_BUFFERS:-512MB}
- -c
- timescaledb.max_background_workers=8
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U netpulse -d netpulse"]
interval: 5s
timeout: 5s
retries: 20
restart: unless-stopped
cache:
image: docker.dragonflydb.io/dragonflydb/dragonfly:v1.25.5
ulimits:
memlock: -1
volumes:
- cache-data:/data
restart: unless-stopped
# Міграції окремою службою, а не на старті API.
#
# API запускається в кількох примірниках, і накочування схеми зі старту
# означало б гонку між ними. Тут же — один запуск, який мусить
# завершитись успіхом, перш ніж піднімуться API й колектор.
migrate:
build: &server-build
context: .
dockerfile: deploy/Dockerfile.server
args:
VERSION: ${NETPULSE_VERSION:-dev}
COMMIT: ${NETPULSE_COMMIT:-none}
image: netpulse/server:${NETPULSE_VERSION:-dev}
entrypoint: ["netpulse-migrate"]
environment: *server-env
depends_on:
db:
condition: service_healthy
restart: "no"
api:
build: *server-build
image: netpulse/server:${NETPULSE_VERSION:-dev}
entrypoint: ["netpulse-api"]
command:
- -listen=:8080
- -alert-interval=${NETPULSE_ALERT_INTERVAL:-30s}
environment:
<<: *server-env
NETPULSE_JWT_SECRET: ${NETPULSE_JWT_SECRET:?потрібен NETPULSE_JWT_SECRET — не менше 32 байтів}
depends_on:
migrate:
condition: service_completed_successfully
cache:
condition: service_started
healthcheck:
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/healthz"]
interval: 10s
timeout: 3s
retries: 6
start_period: 15s
restart: unless-stopped
# Колектор зондів. TLS знімає Caddy, всередині мережі — h2c, тому
# -insecure. Порт назовні сам не публікує: до нього ходять через
# проксі, який має справжній сертифікат.
collector:
build: *server-build
image: netpulse/server:${NETPULSE_VERSION:-dev}
entrypoint: ["netpulse-server"]
command:
- -listen=:9443
- -insecure
environment: *server-env
depends_on:
migrate:
condition: service_completed_successfully
restart: unless-stopped
proxy:
image: caddy:2.8-alpine
environment:
NETPULSE_DOMAIN: ${NETPULSE_DOMAIN:?потрібен NETPULSE_DOMAIN}
# Порожній рядок Caddy не приймає: директива email без значення —
# помилка розбору, і проксі не підніметься взагалі. Тому підстановка
# спрацьовує і на незадану змінну, і на задану порожньою.
ACME_EMAIL: ${ACME_EMAIL:-admin@${NETPULSE_DOMAIN}}
volumes:
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
ports:
- "80:80"
- "443:443"
# Окремий порт для зондів: вони говорять gRPC, а не HTTP, і
# ділити з ним 443 означало б розрізняти протоколи за шляхом —
# зайва крихкість там, де порт коштує нічого.
- "9443:9443"
depends_on:
- api
- collector
restart: unless-stopped
# Зонд на тому ж хості, що й сервер: базовий моніторинг самої
# інсталяції. Профіль, а не звичайна служба: у типовому розгортанні
# зонди стоять у мережах клієнтів, а не поруч із сервером.
agent:
build:
context: .
dockerfile: deploy/Dockerfile.agent
args:
VERSION: ${NETPULSE_VERSION:-dev}
COMMIT: ${NETPULSE_COMMIT:-none}
image: netpulse/agent:${NETPULSE_VERSION:-dev}
profiles: ["agent"]
command:
- -server=collector:9443
- -insecure
- -modules=icmp,snmp,topology,ncm
environment:
NETPULSE_ENROLL: ${NETPULSE_ENROLL:-}
NETPULSE_NAME: ${NETPULSE_AGENT_NAME:-локальний зонд}
TZ: ${TZ:-Europe/Kyiv}
cap_add:
- NET_RAW
volumes:
- agent-identity:/var/lib/netpulse
depends_on:
- collector
restart: unless-stopped
volumes:
db-data:
cache-data:
caddy-data:
caddy-config:
agent-identity: