13 KiB
Flyway 기준
목적
이 문서는 PostgreSQL 기반 서비스에서 Flyway를
- 어디서 실행할지 (Kubernetes Job)
- 어떤 순서로 실행할지 (validate / info / migrate / app rollout)
- 어떤 배포 흐름과 맞물릴지 (Helm hook / Argo CD sync-wave)
- config를 어떻게 공급할지 (env var + Secret via Vault Secrets Operator)
- schema history table을 어떻게 둘지
- baseline / repair / out-of-order / undo를 어떻게 다룰지
- non-transactional DDL을 어떻게 처리할지 를 먼저 고정한다.
이 문서의 목표는 다음과 같다.
- Flyway를 앱 startup 내부 로직처럼 숨기지 않는다
- validate / migrate / repair / baseline의 역할을 분리한다
- schema history table을 운영 감사 추적의 일부로 본다
- migration Job을 1000+ 서비스 규모에서 재현 가능하게 표준화한다
- DB 변경을 애플리케이션 rollout과 분리해 운영한다
공식 의미
- Flyway
validate는 적용된 migration과 로컬 migration 사이의 이름/타입/checksum 차이, 로컬에 없는 적용 버전, 아직 적용되지 않은 로컬 버전을 검증한다. migrate는 schema history table이 없으면 자동 생성하고 최신 migration까지 적용한다.- schema history table은 migration 실행 내역, checksum, 성공/실패 상태를 기록하는 audit trail이다.
repair는 schema history table을 수정하는 명령이며, 실패한 migration 엔트리 제거, checksum/description/type 재정렬, missing migration 삭제 표시를 수행한다. user object는 정리하지 않는다.- schema history table 기본 이름은
flyway_schema_history다. - schema history table 위치는
table,defaultSchema,schemas로 제어할 수 있다. createSchemas=false일 때 history table이 들어갈 schema가 미리 준비되지 않으면 migrate가 실패할 수 있다.- 기존 non-empty schema에 Flyway를 도입할 때 history table이 없으면
baseline또는baselineOnMigrate가 필요할 수 있다. - schema history에는
Pending,Success,Missing,Out of Order,Outdated,Superseded,Deleted등 상태가 기록될 수 있다. - Flyway는 migration 실행 중 schema history table에 advisory lock을 걸어 동시 실행을 직렬화한다. 다중 replica Job 수준의 race를 방지한다.
cleanDisabled는 Flyway 9 이후 기본true. production에서는 반드시true를 명시한다.- Flyway 8.2+ 에서
-- flyway:executeInTransaction=falsedirective로 migration 파일 단위 트랜잭션 비활성화가 가능하다. - Flyway Community(OSS)는 undo(U__) migration을 지원하지 않는다. Undo는 Teams/Enterprise 상용 기능이다.
- 환경변수 config 지원:
FLYWAY_URL,FLYWAY_USER,FLYWAY_PASSWORD,FLYWAY_LOCATIONS,FLYWAY_SCHEMAS,FLYWAY_DEFAULT_SCHEMA,FLYWAY_TABLE,FLYWAY_BASELINE_ON_MIGRATE,FLYWAY_VALIDATE_ON_MIGRATE,FLYWAY_CLEAN_DISABLED,FLYWAY_OUT_OF_ORDER, 그 외FLYWAY_*.
기본 규칙
1. Flyway는 앱 startup이 아니라 독립 실행 단계
운영 환경에서 Flyway는 다음 중 하나로만 실행한다.
- Kubernetes Job (권장)
- CI/CD 명시 단계
- 운영자 명시 실행 절차
기본 금지:
- 애플리케이션 startup 시 자동 migration
- Spring Boot
spring.flyway.enabled=true로 앱 부팅 경로에 포함 - readiness/liveness와 migration 실패를 섞는 구조
2. 기본 순서는 info → validate → migrate → info → app rollout
운영 기본 순서:
flyway info(pending 확인)flyway validateflyway migrateflyway info(결과 확인)- 애플리케이션 rollout
validateOnMigrate=true가 기본값이지만, 운영 절차상 validate를 분리 initContainer 또는 사전 단계로 둔다.
3. 배포 흐름 안에서 app보다 먼저 실행 — 두 가지 패턴
패턴 A: Helm hook
annotations:
"helm.sh/hook": "pre-upgrade,pre-install"
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded"
패턴 B: Argo CD sync-wave
annotations:
argocd.argoproj.io/sync-wave: "-1"
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
기본:
- 두 패턴을 혼용하지 않는다 (Argo CD가 Helm chart를 렌더링할 때 Helm hook을 일반 리소스로 취급해 순서가 꼬임)
- 배포 도구에 맞춰 한쪽만 사용
4. migration Job 안전 설정 체크리스트
Job manifest에 반드시 다음이 있어야 한다.
parallelism: 1,completions: 1backoffLimit: 0또는 작은 값 (1~2)activeDeadlineSeconds(권장 1800 = 30분, 대형 migration은 더 길게)ttlSecondsAfterFinished(권장 86400 = 1일)restartPolicy: Never- 이미지 digest pinning (
flyway/flyway@sha256:...) imagePullPolicy: IfNotPresentresources.requests/limitssecurityContext:runAsNonRoot: true,readOnlyRootFilesystem: true,capabilities: drop: [ALL]- Pod-level
seccompProfile: RuntimeDefault fsGroup명시 (필요 시)
5. config는 환경변수 + Secret
Flyway CLI는 FLYWAY_* 환경변수를 읽는다. Secret은 Vault Secrets Operator(VSO) 또는 External Secrets Operator를 통해 클러스터에 동기화된 Secret에서 주입한다.
필수 env var:
FLYWAY_URL—jdbc:postgresql://host:5432/dbFLYWAY_USERFLYWAY_PASSWORD— Secret에서 주입FLYWAY_LOCATIONS—filesystem:/flyway/sql
운영 권장 env var:
FLYWAY_SCHEMAS— 대상 schemaFLYWAY_DEFAULT_SCHEMA— history table 위치FLYWAY_TABLE— 기본flyway_schema_historyFLYWAY_VALIDATE_ON_MIGRATE=trueFLYWAY_BASELINE_ON_MIGRATE=false(운영 기본값)FLYWAY_CLEAN_DISABLED=true(production 필수)FLYWAY_OUT_OF_ORDER=falseFLYWAY_MIXED=false
6. cleanDisabled=true는 production 필수
flyway clean은 모든 object를 drop 하는 파괴적 명령이다.
- production:
FLYWAY_CLEAN_DISABLED=true반드시 명시 (Flyway 9+ 기본값이지만 명시적으로 선언) - dev/test: 필요 시
false허용, 단 접근 권한 분리
7. migration SQL은 ConfigMap 또는 이미지 레이어로
옵션:
- ConfigMap: 서비스 manifest와 함께 Argo CD로 관리. small/medium migration set에 적합. ConfigMap 1MiB 제한 주의.
- 이미지 레이어: 서비스 repo에서 migration SQL을 Docker image로 빌드하고 Flyway image와 합쳐 사용. 대규모 migration set에 적합.
기본:
- 두 방식 모두 Git이 source of truth
- 운영 서버에서
kubectl edit configmap으로 migration 편집 금지
8. schema history table은 운영 감사 추적의 일부
수동 UPDATE / DELETE 금지. 위치는 명시적으로 결정.
기본:
- service별 schema를
FLYWAY_DEFAULT_SCHEMA로 지정 (예:auth_server) - history table 이름은 기본값
flyway_schema_history유지 - 여러 서비스의 history table을 하나의 schema에 몰지 않음
9. createSchemas=false면 history schema를 사전 준비
createSchemas=false를 쓰면 history table이 들어갈 schema를 별도 준비해야 한다.
기본:
FLYWAY_INIT_SQL로CREATE SCHEMA IF NOT EXISTS지시 가능- 또는 CNPG
Cluster.bootstrap.initdb.postInitSQL에서 schema 사전 생성 - 생성 책임이 누구인지 문서화
10. baseline은 예외 절차
허용 예:
- legacy DB를 처음 Flyway 관리로 편입
- 기존 non-empty schema를 Flyway에 편입할 때
기본 금지:
- 새 프로젝트인데 baseline부터 쓰기
- 운영 배포 파이프라인에서 습관적으로 baseline 사용
11. baselineOnMigrate는 기본값 아님
baselineOnMigrate=true는 도입/전환 시 편의를 줄 수 있지만, 운영 기본값으로 두지 않는다.
이유:
- 예상치 못한 기존 schema를 "정상 상태"처럼 받아들일 수 있다
- 실수 탐지력이 떨어진다
FLYWAY_BASELINE_ON_MIGRATE=false로 명시.
12. repair는 예외 절차
허용 예:
- 의도적으로 migration 파일을 수정했고 checksum 정렬이 필요
- missing migration을 문서화된 절차로 정리
- failed repeatable migration 이후 history 정리
기본 금지:
- validate 오류가 나면 원인 분석 없이 바로 repair
- CI/CD에서 습관적으로 repair 실행
13. repair는 user object를 고쳐주지 않는다
repair는 schema history table만 정리한다. 실패한 migration이 남긴 DB object 정리, 불완전한 DDL/DML 정리는 별도 절차로 수행해야 한다.
14. 적용된 migration 파일은 수정 금지
이유:
- checksum mismatch
- 재현 불가
- 환경 간 drift
대응:
- 새 migration으로 교정
- 정말 예외적인 수정만 공식 repair 절차와 함께 수행
15. out-of-order는 기본 금지
Out-of-order migration은 전체 migration history를 다시 실행할 때 다른 결과를 만들 수 있다.
기본:
FLYWAY_OUT_OF_ORDER=false- 뒤늦게 빠진 migration을 넣는 방식을 기본값으로 두지 않음
- 예외 허용 시 영향 범위 검토 문서 필수
16. repeatable migration(R__)은 목적 제한
Repeatable migration은 다음 용도에 제한한다.
- view 정의
- function / procedure
- trigger 재생성
- reference / static data refresh
기본 금지:
- 순서가 중요한 핵심 schema change를 repeatable로 남발
- versioned migration 대신 repeatable로 대체
17. Undo(U__) migration은 만들지 않는다
Flyway Community(OSS)는 undo를 지원하지 않는다.
- U__ 파일을 repo에 두지 않음 (오해 유발)
- rollback은 forward-only 새 migration + PITR로 대응
18. locations는 environment별로 흔들지 않는다
migrate와 repair는 같은 locations 전제를 가져야 한다.
기본:
- env마다 location 구조가 달라지지 않게 유지
- 운영과 개발에서 전혀 다른 migration set을 쓰지 않음
- env별 변수는
placeholders(FLYWAY_PLACEHOLDERS_*)로 분리
19. migration은 서비스 소유권 단위로 분리
기본:
- auth-server는 auth-server migration set
- keycloak은 keycloak 고유 migration (사실 Keycloak은 내부 migration을 사용하므로 Flyway 대상이 아님)
- 공용 migration 프로젝트 금지
20. migration naming / versioning
기본:
- versioned:
V<N>__<snake_case>.sql, N은 증가하는 정수 또는 점표기(예:V12__,V1.2.3__) - repeatable:
R__<snake_case>.sql - 이름은 변경 의도를 드러나게 작성
예:
V42__add_refresh_token_audit_columns.sqlR__refresh_user_views.sql
21. destructive change는 expand → migrate → contract
db-and-migration.md #19 참조. Flyway 입장에서 각 단계는 별도 릴리즈의 versioned migration으로 나간다.
22. non-transactional DDL은 executeInTransaction=false
Postgres에서 트랜잭션 밖 실행이 필요한 DDL:
CREATE INDEX CONCURRENTLYREINDEX CONCURRENTLYALTER TYPE ... ADD VALUEVACUUM
migration 파일 상단:
-- flyway:executeInTransaction=false
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
기본:
- 이런 DDL은 전용 migration 파일로 분리 (다른 statement와 섞지 않음)
- runtime 추정치 주석
- low-traffic window로 배포 일정 조정
23. rollback은 Flyway 명령에 기대지 않는다
운영 기본 rollback:
- 새 migration으로 수정
- PostgreSQL PITR (CNPG bootstrap.recovery)
- 애플리케이션 버전 rollback + DB 호환 윈도우 유지 (expand-contract의 효과)
rollout undo가 DB schema rollback을 대신하지 않는다.
24. 현재 스택 기준 기본 권장안
- auth-server
- Flyway Job (Helm hook 또는 Argo sync-wave)
FLYWAY_DEFAULT_SCHEMA=auth_server- validate → migrate → app rollout
- digest pinning
- keycloak
- Keycloak 자체 migration 사용, Flyway 대상 아님
- test-server
- DB가 없으면 Flyway 대상 아님
- 운영 절차
- repair/baseline은 예외 승인 절차
- applied migration 수정 금지
- CLEAN_DISABLED=true 필수
프로젝트 기준 요약
- Flyway는 독립 실행 단계 (Kubernetes Job)
- info → validate → migrate → info → app rollout
- 배포 흐름 내 순서는 Helm hook 또는 Argo CD sync-wave 중 하나로 통일
- Job:
parallelism: 1,backoffLimit: 0,ttlSecondsAfterFinished, digest pinning, restricted PSA - config는
FLYWAY_*env var + Secret (VSO / ESO) FLYWAY_CLEAN_DISABLED=true필수,FLYWAY_BASELINE_ON_MIGRATE=false,FLYWAY_OUT_OF_ORDER=false- schema history table 위치를
FLYWAY_DEFAULT_SCHEMA로 명시 - baseline / repair / out-of-order는 예외 절차
- applied migration 수정 금지
- Undo(U__) 파일 만들지 않음 (OSS 미지원)
- non-transactional DDL은
-- flyway:executeInTransaction=false로 파일 단위 분리 - service별 migration ownership 분리
- destructive migration은 expand → migrate → contract