Skip to content

chore(deploy): automate alembic migrations across k8s and docker-compose#7

Merged
AdamDiStefanoAI merged 1 commit intomainfrom
chore/auto-migrations
Apr 8, 2026
Merged

chore(deploy): automate alembic migrations across k8s and docker-compose#7
AdamDiStefanoAI merged 1 commit intomainfrom
chore/auto-migrations

Conversation

@AdamDiStefanoAI
Copy link
Copy Markdown
Owner

Summary

Schema migrations were a manual step ("run `alembic upgrade head` before the gateway") that's easy to forget on deploy. This PR bakes the step into both deployment surfaces so it can't be skipped.

Changes

File Change
scripts/run-migrations.sh New shared entrypoint. Resolves the app root, asserts `DATABASE_URL`, and runs `alembic upgrade head`. Idempotent — replicas racing each other are safe.
Dockerfile Installs the script onto PATH as `run-migrations` so the same image services both the gateway process and the migration job without a second build.
deploy/k8s/base/gateway-deployment.yaml Adds an `alembic-upgrade` initContainer that runs `run-migrations` before the gateway container starts. Inherits the same configmap + secret so DB URL can never drift. Same hardened securityContext (non-root, read-only root fs, all caps dropped).
docker-compose.yml Adds a one-shot `acr-migrate` service. `acr-gateway` now waits for it via `service_completed_successfully`. `docker compose up` will always apply pending migrations before starting the gateway.

Why this works

  • Idempotent. Re-running on an up-to-date schema is a no-op.
  • Race-safe. Alembic wraps each migration in a transaction; the loser of a multi-replica race observes the schema as already at head and exits 0.
  • Same image, no drift. Both surfaces invoke the same script baked into the runtime image, so the migration tool is always at the exact version of the deployed code.
  • Belt and braces. Production already defaults to `SCHEMA_BOOTSTRAP_MODE=validate` (via `effective_schema_bootstrap_mode` in `config.py`), which makes the gateway refuse to start with a missing schema. This PR makes that failure path impossible to hit by ensuring migrations are always applied first.

Test plan

  • `alembic history` shows the chain ends at `0012 (head)`
  • All 28 identity tests pass
  • Both YAMLs parse cleanly (compose only emits the pre-existing harmless `version:` warning)
  • `docker compose up` from a clean volume completes with the gateway healthy
  • `kubectl apply -k deploy/k8s/base` against a fresh cluster results in the gateway Pod becoming Ready after the initContainer exits 0

🤖 Generated with Claude Code

Schema migrations were a manual step ("run alembic upgrade head before
the gateway") that's easy to forget on deploy. Bake the step into both
deployment surfaces so it can't be skipped.

* scripts/run-migrations.sh — shared entrypoint that resolves the app
  root, asserts DATABASE_URL, and runs `alembic upgrade head`. Idempotent
  by design (Alembic wraps each migration in a transaction; replicas
  racing each other are safe). Used by every surface below.

* Dockerfile — installs the script onto PATH as `run-migrations` in
  the runtime image, so the same image services both the gateway
  process and the migration job without a second build.

* deploy/k8s/base/gateway-deployment.yaml — adds an `alembic-upgrade`
  initContainer that runs `run-migrations` before the gateway container
  starts. Inherits the same configmap+secret as the gateway, so the
  database URL never drifts. Same hardened securityContext (non-root,
  read-only root fs, all caps dropped).

* docker-compose.yml — adds a one-shot `acr-migrate` service that runs
  `run-migrations` and exits. The `acr-gateway` service now waits for
  it via `service_completed_successfully`, so `docker compose up` will
  always apply pending migrations before starting the gateway.

The production default of SCHEMA_BOOTSTRAP_MODE=validate (set by
effective_schema_bootstrap_mode in config.py) means the gateway will
already refuse to start with a missing schema — this PR makes the
"missing schema" failure path impossible to hit by ensuring migrations
are always applied first.

Verified: alembic chain ends at 0012 (head), all 28 identity tests
pass, both YAMLs parse cleanly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AdamDiStefanoAI AdamDiStefanoAI merged commit af5ddc3 into main Apr 8, 2026
1 check failed
@AdamDiStefanoAI AdamDiStefanoAI deleted the chore/auto-migrations branch April 8, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant