4.6 KiB
Flask-Migrate in Docker Deployments
Overview
Docker containers typically don't include Git repositories, so we can't use Git commands to extract historical schemas. This guide explains how to use Flask-Migrate in Docker environments.
Initial Setup (First Deployment)
When deploying with Flask-Migrate for the first time:
Automatic Setup (via startup scripts)
The startup.sh and startup_postgres.sh scripts now automatically handle migration initialization:
-
For existing databases with data:
- Creates a baseline migration from current models
- Stamps the database as current (no changes applied)
- Ready for future migrations
-
For empty databases:
- Creates a baseline migration from current models
- Applies it to create all tables
- Ready for future migrations
Manual Setup
If you need to set up manually:
# Inside your Docker container
python docker_migrate_init.py
# For existing database with tables:
flask db stamp head
# For new empty database:
flask db upgrade
Creating New Migrations
After initial setup, create new migrations normally:
# 1. Make changes to your models
# 2. Generate migration
flask db migrate -m "Add user preferences"
# 3. Review the generated migration
cat migrations/versions/*.py
# 4. Apply the migration
flask db upgrade
Helper Script
The docker_migrate_init.py script creates a migrate.sh helper:
# Check current migration status
./migrate.sh status
# Apply pending migrations
./migrate.sh apply
# Create new migration
./migrate.sh create "Add company settings"
# Mark database as current (existing DBs)
./migrate.sh mark-current
Docker Compose Example
version: '3.8'
services:
web:
build: .
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/timetrack
- FLASK_APP=app.py
volumes:
# Persist migrations between container restarts
- ./migrations:/app/migrations
depends_on:
- db
command: ./startup_postgres.sh
db:
image: postgres:13
environment:
- POSTGRES_DB=timetrack
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Important Notes
1. Migrations Directory
- The
migrations/directory should be persisted between deployments - Either use a volume mount or include it in your Docker image
- Don't regenerate migrations on each deployment
2. Environment Variables
Always set these in your Docker environment:
FLASK_APP=app.py
DATABASE_URL=your_database_url
3. Production Workflow
- Development: Create and test migrations locally
- Commit: Add migration files to Git
- Build: Include migrations in Docker image
- Deploy: Startup script applies migrations automatically
4. Rollback Strategy
To rollback a migration:
# Inside container
flask db downgrade # Go back one migration
flask db downgrade -2 # Go back two migrations
Troubleshooting
"No Git repository found"
This is expected in Docker. Use docker_migrate_init.py instead of the Git-based scripts.
"Can't locate revision"
Your database references a migration that doesn't exist:
# Reset to current state
python docker_migrate_init.py
flask db stamp head
Migration conflicts after deployment
If migrations were created in different environments:
# Merge migrations
flask db merge -m "Merge production and development"
flask db upgrade
Best Practices
- Always test migrations in a staging environment first
- Back up your database before applying migrations in production
- Include migrations in your Docker image for consistency
- Don't generate migrations in production - only apply pre-tested ones
- Monitor the startup logs to ensure migrations apply successfully
Migration State in Different Scenarios
Scenario 1: Fresh deployment, empty database
- Startup script runs
docker_migrate_init.py - Creates baseline migration
- Applies it to create all tables
Scenario 2: Existing database, first Flask-Migrate setup
- Startup script runs
docker_migrate_init.py - Creates baseline migration matching current schema
- Stamps database as current (no changes)
Scenario 3: Subsequent deployments with new migrations
- Startup script detects
migrations/exists - Runs
flask db upgradeto apply new migrations
Scenario 4: Container restart (no new code)
- Startup script detects
migrations/exists - Runs
flask db upgrade(no-op if already current)
This approach ensures migrations work correctly in all Docker deployment scenarios!