aprs.me/k8s/README-migrations.md
Graham McIntire 9189579a02
Implement distributed migration locking for cluster deployments
- Add MigrationLock module using PostgreSQL advisory locks
- Prevent concurrent migrations across multiple nodes
- Update Release.migrate to use distributed lock when cluster enabled
- Disable auto-migrations in cluster mode to avoid race conditions
- Add init container configuration for Kubernetes deployments
- Document migration strategies in k8s/README-migrations.md

This ensures only one node runs database migrations at a time, preventing
conflicts and race conditions in distributed deployments.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-27 10:41:36 -05:00

69 lines
No EOL
2.2 KiB
Markdown

# Database Migration Strategy for Kubernetes
This document describes how database migrations are handled in the Kubernetes deployment to ensure only one node runs migrations at a time.
## Overview
In a distributed environment with multiple pods, we need to ensure that database migrations only run once, not multiple times concurrently. We use two strategies:
1. **PostgreSQL Advisory Locks** - For runtime migration coordination
2. **Init Containers** - For deployment-time migrations (recommended)
## Implementation
### 1. PostgreSQL Advisory Locks
The `Aprsme.MigrationLock` module uses PostgreSQL advisory locks to ensure only one node can run migrations at a time:
- Uses `pg_try_advisory_lock()` to acquire a non-blocking lock
- Other nodes wait for the lock to be released
- Automatically releases the lock after migrations complete
### 2. Init Container (Recommended)
The StatefulSet can be configured with an init container that runs migrations before the main pods start:
```bash
# Apply the init container patch
kubectl patch statefulset aprs -n aprs --patch-file k8s/statefulset-init-container-patch.yaml
```
This approach:
- Runs migrations sequentially before any pods start
- Prevents race conditions
- Makes migration failures visible in pod events
### 3. Auto-Migration Disabled in Cluster Mode
When `CLUSTER_ENABLED=true`, automatic migrations on startup are disabled to prevent race conditions.
## Manual Migration
To run migrations manually:
```bash
# Run on the first pod
kubectl exec -it aprs-0 -n aprs -- /app/bin/migrate
# Or create a one-off job
kubectl run migrate-job --rm -it --image=ghcr.io/aprsme/aprs.me:latest \
--env="DATABASE_URL=$DATABASE_URL" \
--env="SECRET_KEY_BASE=$SECRET_KEY_BASE" \
--env="MIX_ENV=prod" \
--env="SKIP_DB_CREATE=true" \
--restart=Never \
-- /app/bin/migrate
```
## Configuration
Environment variables:
- `CLUSTER_ENABLED=true` - Enables distributed locking
- `SKIP_DB_CREATE=true` - Skips database creation (for PgBouncer)
## Best Practices
1. **Use Init Containers** for production deployments
2. **Test migrations** in a staging environment first
3. **Monitor migration logs** during deployments
4. **Have rollback plan** ready with `mix ecto.rollback`