DevOps / GitOps Interview Questions
How do you manage database schema migrations in a GitOps workflow?
Database schema migrations are inherently imperative and ordered — they run once, in sequence, and must complete successfully before the application starts. This sits awkwardly with GitOps's declarative, continuously-reconciled model. Three patterns handle this well.
1. Argo CD PreSync hook with a Kubernetes Job: Annotate a migration Job with argocd.argoproj.io/hook: PreSync. Argo CD runs the Job before applying any other resources in the sync. If the Job fails, the sync aborts and the application is not updated. Set hook-delete-policy: BeforeHookCreation to clean up the previous Job before creating a new one.
apiVersion: batch/v1
kind: Job
metadata:
name: db-migration
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
template:
spec:
containers:
- name: migrate
image: registry.example.com/my-app:v1.5.2
command: ["./migrate", "--run"]
restartPolicy: Never
2. Sync waves: If you don't want a PreSync hook, use argocd.argoproj.io/sync-wave: "1" on the migration Job and sync-wave: "2" on the Deployment. Argo CD waits for wave 1 to succeed before starting wave 2. The Job must complete (not just start) for the wave transition to occur.
3. Flyway / Liquibase as an init container: Embed migration logic directly in the application Pod as an init container. The init container runs flyway migrate or liquibase update against the database before the main container starts. Migration SQL files are packaged inside the application image. No separate Job needed — migrations run atomically with Pod startup. Downside: the application image must always include all historical migrations.
More Related questions...