This commit is contained in:
+12
-1
@@ -43,6 +43,11 @@ services:
|
||||
condition: service_healthy
|
||||
expose:
|
||||
- "3000"
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then((response) => process.exit(response.ok ? 0 : 1)).catch(() => process.exit(1))"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
worker:
|
||||
build:
|
||||
@@ -66,9 +71,15 @@ services:
|
||||
dockerfile: Dockerfile.web
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- api
|
||||
api:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "${WEB_PORT:-8080}:80"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--spider", "--quiet", "http://127.0.0.1/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
|
||||
@@ -45,6 +45,42 @@ worker images share the same Node workspace image; the web image builds the Vue
|
||||
application and serves it through Nginx with SPA fallback and internal `/api`
|
||||
proxying.
|
||||
|
||||
## Health Checks
|
||||
|
||||
Production Compose waits for healthy PostgreSQL, Redis, and API services before
|
||||
starting the web service. The API health endpoint is `GET /health`; the web
|
||||
container checks its `/health` response through Nginx.
|
||||
|
||||
## Backup And Restore
|
||||
|
||||
Create a PostgreSQL custom-format dump from the running production stack:
|
||||
|
||||
```sh
|
||||
BACKUP_DIR=/secure/backups \
|
||||
POSTGRES_DB=inventory \
|
||||
POSTGRES_USER=inventory \
|
||||
POSTGRES_PASSWORD='use-secret-storage' \
|
||||
./scripts/backup-postgres.sh
|
||||
```
|
||||
|
||||
Restore only during a planned maintenance window because `pg_restore` replaces
|
||||
matching database objects:
|
||||
|
||||
```sh
|
||||
BACKUP_FILE=/secure/backups/inventory-20260909T000000Z.dump \
|
||||
POSTGRES_DB=inventory \
|
||||
POSTGRES_USER=inventory \
|
||||
POSTGRES_PASSWORD='use-secret-storage' \
|
||||
./scripts/restore-postgres.sh
|
||||
```
|
||||
|
||||
Back up image storage and the deployment `.env` through the NAS secret/backup
|
||||
system as well. Never commit either one. Before upgrading, record the current
|
||||
image tags and database migration state. To roll back, stop the application
|
||||
services, restore the previous image tags, restore the database dump if the
|
||||
schema changed, then start the stack and verify `/health` and a read-only
|
||||
catalog request.
|
||||
|
||||
## Reverse proxy
|
||||
|
||||
Responsible for:
|
||||
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${BACKUP_DIR:?Set BACKUP_DIR to the destination directory}"
|
||||
: "${POSTGRES_DB:?Set POSTGRES_DB}"
|
||||
: "${POSTGRES_USER:?Set POSTGRES_USER}"
|
||||
: "${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}"
|
||||
|
||||
timestamp=$(date -u '+%Y%m%dT%H%M%SZ')
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
output_path="$BACKUP_DIR/${POSTGRES_DB}-${timestamp}.dump"
|
||||
|
||||
docker compose -f compose.production.yaml exec -T \
|
||||
-e PGPASSWORD="$POSTGRES_PASSWORD" postgres \
|
||||
pg_dump -U "$POSTGRES_USER" -Fc "$POSTGRES_DB" > "$output_path"
|
||||
|
||||
printf '%s\n' "$output_path"
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${BACKUP_FILE:?Set BACKUP_FILE to a PostgreSQL custom-format dump}"
|
||||
: "${POSTGRES_DB:?Set POSTGRES_DB}"
|
||||
: "${POSTGRES_USER:?Set POSTGRES_USER}"
|
||||
: "${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}"
|
||||
|
||||
if [ ! -f "$BACKUP_FILE" ]; then
|
||||
printf '%s\n' "Backup file not found: $BACKUP_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker compose -f compose.production.yaml exec -T \
|
||||
-e PGPASSWORD="$POSTGRES_PASSWORD" postgres \
|
||||
pg_restore --clean --if-exists --no-owner -U "$POSTGRES_USER" -d "$POSTGRES_DB" < "$BACKUP_FILE"
|
||||
Reference in New Issue
Block a user