feat(ci): automated docker update script + nightly cron
CI / runtime-diagnostics (push) Skipped
CI / check (push) Successful in 33s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m3s

- scripts/docker-update.sh: git pull --ff-only, host db:migrate, docker compose
  build + up -d, health-check wait, keeps host-side PM2 'next' stopped.
  Fails safe on dirty working tree (exit 1) and on health failure (exit 3).
- cron entry: daily 03:30 -> logs/docker-update.cron.log
- README: Automatic Updates section + docker commands row
This commit is contained in:
openhands committed 2026-09-02 12:25:42 +02:00
1 parent cb927db78d
commit 037b295b93
2 files changed
+113

No files matched your search

+24
View File
@@ -154,6 +154,29 @@ The CMS will be available at `http://localhost:3002`.
> **Reverse proxy:** This setup is designed to run behind the existing nginx on the host. nginx serves the Nitro/Octane client (`/client/`, `/nitro-client/`) and `/gamedata/` directly from `/var/www/Octane/dist` and `/var/www/Gamedata`, and proxies `/` to the CMS on `127.0.0.1:3002`. Point `APP_URL`/`NEXT_PUBLIC_APP_URL` at the public site URL.
### Automatic Updates
A cron-safe update script is included: `scripts/docker-update.sh`. It pulls the
latest `main`, runs CMS migrations on the host, rebuilds the image, recreates the
container, waits for a healthy status, and makes sure the stale host-side PM2 CMS
(`pm2 stop next`) stays stopped so it can't clash on port 3002.
```bash
./scripts/docker-update.sh # run once manually
# log: logs/docker-update.log
```
Set it up as a nightly cron job (03:30 example):
```bash
crontab -e
# 30 3 * * * /var/www/atom-nexst/scripts/docker-update.sh >> /var/www/atom-nexst/logs/docker-update.cron.log 2>&1
```
The script aborts safely (exit 1) if the working tree has uncommitted changes so
a `git pull` can never clobber local edits, and leaves the container running if
health fails so you can debug it (exit 3).
### Docker Commands
| Command | Description |
@@ -165,6 +188,7 @@ The CMS will be available at `http://localhost:3002`.
| `docker compose restart cms` | Restart the CMS container |
| `docker compose pull && docker compose up -d --build` | Update and redeploy |
| `pnpm db:migrate` (on the **host**) | Run database migrations (slim image has no source) |
| `./scripts/docker-update.sh` | Full automated update (manual or cron) |
### How Package Manager Detection Works
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env bash
# ==============================================================================
# docker-update.sh — Automatic daily update for the Dockerized EpicNext-CMS.
#
# Steps:
# 1. Verify the working tree is clean (uncommitted changes abort).
# 2. git pull (fast-forward only).
# 3. Run CMS migrations on the HOST (the slim runtime container has no source).
# 4. docker compose build (auto-detects pnpm/yarn/npm via lockfile).
# 5. docker compose up -d && wait for a healthy container.
# 6. Record everything in update.log.
#
# Exit codes: 0 ok, 1 update skipped, 2 build/deploy failed, 3 health failed.
# ==============================================================================
set -uo pipefail
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$DIR" || exit 2
LOG_FILE="${LOG_FILE:-$DIR/logs/docker-update.log}"
PM2_APP="${PM2_APP:-next}" # host-side CMS that must stay stopped (port 3002)
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
die() { log "ERROR: $*"; exit "${2:-2}"; }
touch "$LOG_FILE"
log "=== Start docker-update ==="
# --- 0. Guard: uncommitted changes would break git pull / taint deploys ---
if ! { git diff --quiet --exit-code && git diff --cached --quiet --exit-code; }; then
die "working tree has uncommitted changes; commit or stash first" 1
fi
# --- 1. Pull latest ---
git pull --ff-only --quiet 2>>"$LOG_FILE"
pull_status=$?
if [ $pull_status -ne 0 ]; then
die "git pull failed (status $pull_status)" 1
fi
log "git pull OK: $(git rev-parse --short HEAD)"
# --- 2. Host-side migrations (idempotent; only applies CMS-owned tables) ---
if [ -f pnpm-lock.yaml ] && command -v pnpm >/dev/null 2>&1; then
pnpm db:migrate >>"$LOG_FILE" 2>&1 || die "db:migrate (pnpm) failed"
elif command -v npm >/dev/null 2>&1; then
npm run db:migrate >>"$LOG_FILE" 2>&1 || die "db:migrate (npm) failed"
else
die "no package manager found for migrations" 2
fi
log "db:migrate OK"
# --- 3. Rebuild the image ---
docker compose build >>"$LOG_FILE" 2>&1 || die "docker compose build failed" 2
log "docker compose build OK"
# --- 4. Recreate the container ---
docker compose up -d >>"$LOG_FILE" 2>&1 || die "docker compose up failed" 2
log "docker compose up OK"
# --- 5. Wait for health (up to ~4 min) ---
healthy=0
for i in $(seq 1 16); do
status="$(docker inspect --format='{{.State.Health.Status}}' epicnext-cms 2>/dev/null || true)"
case "$status" in
healthy) healthy=1; break ;;
unhealthy) break ;;
esac
sleep 15
done
if [ "$healthy" -eq 1 ]; then
log "CMS healthy after update (commit $(git rev-parse --short HEAD))"
else
log "WARNING: container not healthy (status='${status:-unknown}')"
# Leave the container running so it can be debugged; report failure exit.
exit 3
fi
# --- 6. Make sure the stale host-side PM2 CMS stays stopped ---
if command -v pm2 >/dev/null 2>&1 && pm2 jlist >/dev/null 2>&1; then
if pm2 list 2>/dev/null | grep -q "${PM2_APP}"; then
pm2 stop "$PM2_APP" >/dev/null 2>&1 && log "pm2 '${PM2_APP}' kept stopped (avoids port 3002 clash)"
fi
fi
log "=== docker-update finished OK ==="
exit 0