DevOps & Kubernetes (50 Qs)•Part 4: CI/CD Pipelines, GitOps & Progressive Delivery (36 - 42)
Zero-Downtime Database Migrations in CI/CD: The Expand-and-Contract (Parallel Run) migration pattern.
Decoupling Schema Migrations from Code Deployments
The fatal flaw in traditional CI/CD is running database migrations (e.g., alembic upgrade head or prisma migrate deploy) that drop or rename a column while old application code is still running, immediately causing widespread production crashes.
sql
Phase 1: EXPAND (Additive Schema Change)
[ Old DB: { phone } ] ---> Add nullable column `phone_number`
Old App v1 still reads/writes `phone`. Database is backwards-compatible!
Phase 2: DUAL-WRITE / READ TRANSITION (Deploy New Code)
Deploy App v2: Writes to both `phone` and `phone_number`. Reads from `phone_number`.
Execute background asynchronous backfill script to migrate historical records.
Phase 3: CONTRACT (Subtractive Schema Change)
Deploy App v3: Drops all references to old column `phone`.
Execute migration: `ALTER TABLE users DROP COLUMN phone;`
Golden Rules for Zero-Downtime Database Pipelines
- Every migration must be backwards-compatible: Never rename a column, never drop a column, and never add a
NOT NULLcolumn without a default value in a single step. - Migrations run in a separate pipeline stage: Run migrations before deploying the new pods, verified with pre-deployment sanity checks.
- Locks must have strict timeouts: Always set
SET lock_timeout = '2s';in PostgreSQL migrations to prevent long-running table locks from stalling incoming user queries.