feat(deploy): visible prod-deploy jobs + manual prod-rollback
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 16s
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m23s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 16s
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m23s
- prod-deploy.yaml is now four visible sequential jobs (build -> deploy-main -> deploy-bot -> verify) so the rollout stages show in the Actions UI; the per-service rolling stays in the deploy-main log. - prod-rollback.yaml: a separate manual workflow_dispatch. Leave target_version blank to roll back to the previous deployed version (the host now tracks DEPLOYED_TAG + PREVIOUS_TAG), or pick a release tag. Re-deploys an already published image rolling + health-gated, image-only (no rebuild, no DB migration). - prod-deploy.sh tracks the previous tag (commit_tag) for the blank-input rollback. - Docs: ARCHITECTURE §13 + deploy/README runbook cover versioning + rollback.
This commit is contained in:
+19
-1
@@ -130,7 +130,25 @@ workflow manually (Gitea → Actions → prod-deploy → run from `master`, inpu
|
||||
compose/config/certs/env over SSH, deploys the main host with `prod-deploy.sh` (rolling,
|
||||
health-gated, **auto-rollback to the previous tag**), then the bot host, then probes the
|
||||
public site. After `master` is green this workflow is the **only** thing that touches
|
||||
prod — nothing auto-deploys there.
|
||||
prod — nothing auto-deploys there. It runs four visible jobs: **build → deploy-main →
|
||||
deploy-bot → verify** (the per-service rolling shows in the deploy-main log).
|
||||
|
||||
**Versioning.** Each release is a git tag `vX.Y.Z` on `master`; the deploy stamps
|
||||
`git describe --tags` into every image tag, every binary (`-ldflags` → `pkg/version` →
|
||||
the `service.version` telemetry attribute) and the SPA About screen. Tag the release
|
||||
before running the deploy:
|
||||
|
||||
```sh
|
||||
git tag -a v1.0.0 -m v1.0.0 && git push origin v1.0.0
|
||||
```
|
||||
|
||||
**Manual rollback** (any time after a successful deploy). Run the **`prod-rollback`**
|
||||
workflow (Gitea → Actions → prod-rollback, `confirm=rollback`). Leave `target_version`
|
||||
blank to roll back to the previously deployed version (read from the host's
|
||||
`PREVIOUS_TAG`), or set it to a release tag from the **Releases** page. It re-deploys
|
||||
that already-published image rolling + health-gated — no rebuild, no DB migration
|
||||
(image rollback is DB-safe under the expand-contract rule). The registry keeps every
|
||||
release tag, so any prior release is reachable.
|
||||
|
||||
**Migrations** must be **expand-contract** (backward-compatible; goose is forward-only):
|
||||
the automatic rollback is image-only and never restores the DB. A deploy that changes
|
||||
|
||||
+11
-2
@@ -36,6 +36,9 @@ MIGRATION="${MIGRATION:-0}"
|
||||
COMPOSE_DIR="${COMPOSE_DIR:-/opt/scrabble/compose}"
|
||||
DUMP_DIR="${DUMP_DIR:-/opt/scrabble/dumps}"
|
||||
STATE_FILE="${STATE_FILE:-/opt/scrabble/DEPLOYED_TAG}"
|
||||
# The prior deployed tag, preserved on every successful deploy so prod-rollback can
|
||||
# target "the previous version" with no operator input.
|
||||
PREV_STATE_FILE="${PREV_STATE_FILE:-/opt/scrabble/PREVIOUS_TAG}"
|
||||
PG_USER="${POSTGRES_USER:-scrabble}"
|
||||
PG_DB="${POSTGRES_DB:-scrabble}"
|
||||
|
||||
@@ -88,6 +91,12 @@ rollback() {
|
||||
[ "$MIGRATION" = 1 ] && echo "NOTE: the DB is forward-migrated; a pre-deploy dump is in $DUMP_DIR — restore manually ONLY if the migration was destructive (see deploy/README.md, prod runbook)."
|
||||
}
|
||||
|
||||
commit_tag() {
|
||||
# Record the just-deployed tag as current, preserving the prior one as previous.
|
||||
[ -f "$STATE_FILE" ] && cp "$STATE_FILE" "$PREV_STATE_FILE"
|
||||
echo "$TAG" > "$STATE_FILE"
|
||||
}
|
||||
|
||||
mkdir -p "$DUMP_DIR"
|
||||
echo "=== prod deploy: tag=$TAG prev=$PREV_TAG migration=$MIGRATION ==="
|
||||
use_tag "$TAG"
|
||||
@@ -99,7 +108,7 @@ if [ -z "$(docker ps -aq -f name=scrabble-backend)" ]; then
|
||||
dc up -d --no-build --remove-orphans || { echo "compose up failed"; exit 1; }
|
||||
health_backend || { echo "backend not ready"; exit 1; }
|
||||
health_landing || { echo "landing not ready"; exit 1; }
|
||||
echo "$TAG" > "$STATE_FILE"
|
||||
commit_tag
|
||||
echo "first deploy healthy ($TAG)."
|
||||
exit 0
|
||||
fi
|
||||
@@ -130,5 +139,5 @@ dc up -d --no-build --remove-orphans || { rollback; exit 1; }
|
||||
|
||||
# Final internal sanity before committing the new tag.
|
||||
health_backend || { rollback; exit 1; }
|
||||
echo "$TAG" > "$STATE_FILE"
|
||||
commit_tag
|
||||
echo "=== deploy healthy ($TAG) ==="
|
||||
|
||||
Reference in New Issue
Block a user