This commit is contained in:
+12
-1
@@ -43,6 +43,11 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
expose:
|
expose:
|
||||||
- "3000"
|
- "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:
|
worker:
|
||||||
build:
|
build:
|
||||||
@@ -66,9 +71,15 @@ services:
|
|||||||
dockerfile: Dockerfile.web
|
dockerfile: Dockerfile.web
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- api
|
api:
|
||||||
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- "${WEB_PORT:-8080}:80"
|
- "${WEB_PORT:-8080}:80"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--spider", "--quiet", "http://127.0.0.1/health"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres-data:
|
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`
|
application and serves it through Nginx with SPA fallback and internal `/api`
|
||||||
proxying.
|
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
|
## Reverse proxy
|
||||||
|
|
||||||
Responsible for:
|
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