13 KiB
db / migration 기준
목적
이 문서는 Kubernetes 상의 PostgreSQL과 Flyway를 기준으로
- 데이터베이스를 어떻게 나눌지
- 어떤 operator / 도구로 운영할지 (CNPG, Zalando, Crunchy, self-managed StatefulSet)
- migration을 어디서 어떻게 실행할지
- migration과 배포(Helm / Argo CD)의 순서를 어떻게 보장할지
- validate / migrate / rollback / backup / PITR을 어떤 순서로 볼지
- zero-downtime을 위한 expand-migrate-contract를 어떻게 적용할지 를 먼저 고정한다.
이 문서의 목표는 다음과 같다.
- app rollout과 schema 변경을 분리한다
- Keycloak DB와 auth-server DB 경계를 먼저 고정한다
- Flyway를 앱 시작 로직에 숨기지 않는다
- PostgreSQL backup/restore 전략과 migration 전략을 함께 본다
- 1000+ 서비스 규모에서 일관된 migration Job 표준을 만든다
공식 의미
pg_dump는 logical export다. 정기 production 전체 백업 기본값으로는 보통 적합하지 않다.pg_basebackup은 실행 중인 PostgreSQL cluster의 base backup을 만들며 PITR/standby 시작점으로 쓴다.- PostgreSQL PITR은 base backup + WAL archiving 결합이다.
- 운영 표준 물리 백업 도구: pgBackRest, WAL-G. 또는 operator-native (CNPG Barman Cloud, Crunchy PGO).
- PostgreSQL의 대부분 DDL은 트랜잭션 내에서 실행 가능하지만,
CREATE INDEX CONCURRENTLY,REINDEX CONCURRENTLY,ALTER TYPE ... ADD VALUE,VACUUM은 트랜잭션 밖에서만 실행된다. - CloudNativePG operator는 CNCF Sandbox 프로젝트로 K8s-native Postgres 운영 표준 후보다.
- Flyway
validate는 적용된 migration과 로컬 migration 사이의 이름/타입/checksum 차이, 로컬에 없는 적용 버전, 아직 적용되지 않은 로컬 버전을 검증한다. - Flyway
validateOnMigrate기본값은true,cleanDisabled기본값은true(Flyway 9+). - Flyway
migrate는 schema history table을 자동 생성하고 최신 migration까지 적용한다. - Flyway Community(OSS)는 undo(U__) migration을 지원하지 않는다. Undo는 Teams/Enterprise 전용이다.
- Flyway는 migration 실행 시 schema history table에 advisory lock을 걸어 동시 실행을 방지한다.
RPO / RTO
모든 DB는 다음을 runbook에 먼저 적는다.
- RPO / RTO / Retention
- 복구 목표 (cluster restore / PITR / standby seed)
- 운영 tier (gold / silver / bronze)
이 값들이 없으면 backup 도구 선택이 되지 않는다. backup-restore.md 참조.
기본 규칙
1. DB 경계는 애플리케이션 경계보다 먼저 고정
다음을 명시적으로 정한다.
- Keycloak DB와 auth-server DB를 물리적 cluster로 분리할지, 같은 cluster 내 logical DB / schema로 분리할지
- test-server가 DB를 가지는지
- migration 소유권이 누구에게 있는지 (보통 서비스 팀)
기본:
- 인증 critical data (Keycloak)와 앱 data (auth-server)는 cluster 분리 권장
- 같은 cluster를 쓰더라도 database / role / schema ownership을 섞지 않음
- 한 migration tool/job이 여러 서비스 schema를 동시에 소유하지 않음
2. K8s 위 Postgres 운영 기본은 operator
1000+ 서비스 규모에서 self-managed StatefulSet은 운영 부담이 너무 크다. Operator를 기본 후보로 둔다.
우선순위 (2026 기준):
- CloudNativePG (CNPG) — CNCF Sandbox, K8s-native, Barman Cloud 내장,
Cluster/Backup/ScheduledBackupCRD - Crunchy PGO — 상용 지원, pgBackRest 내장
- Zalando postgres-operator — Spilo 기반, 레거시 환경
operator를 쓰면 자동으로 얻는 것:
- primary/standby 구성 + failover
- rolling minor upgrade
- WAL archiving + continuous backup
- pg_basebackup, PITR, replica re-clone
- PodMonitor 연동
3. migration은 앱 startup에 숨기지 않는다
Flyway migration은 독립 실행 단계다.
기본:
validate→ (필요시info) →migrate→ app rollout
기본 금지:
- app container 시작 시 자동 migration (Spring Boot
spring.flyway.enabled=true+@SpringBootApplication부팅 시 migrate) - readiness/liveness와 migration 실패를 섞는 구조
- "서버가 뜨면 알아서 schema를 맞춘다" 방식
4. Flyway 실행 기본값은 Kubernetes Job
운영 환경에서 Flyway는 다음 중 하나로만 실행한다.
- Kubernetes Job (권장)
- CI/CD 명시 단계
- 운영자 명시 실행 절차
장기 실행 Deployment에 넣지 않는다. Flyway 예시는
docs/examples/infra/flyway.md 참조.
5. migration Job은 배포 흐름 안에서 app보다 먼저 실행
migration을 app보다 선행시키는 것은 manifest 메타데이터로 선언한다.
패턴 A — Helm hook:
metadata:
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 + hook:
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1"
argocd.argoproj.io/hook: Sync
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
기본:
- migration은 sync wave가 app보다 작은 값 (먼저 실행)
- app Deployment는 wave
0또는 그 이상 - Helm과 Argo CD를 혼용하는 경우 한 쪽으로 통일 (둘 다 hook을 걸면 순서가 꼬인다)
6. migration Job 안전 설정
모든 migration Job은 다음을 명시한다.
parallelism: 1— 병렬 실행 금지 (Flyway advisory lock이 막아주지만, Job 수준에서도 명시)completions: 1backoffLimit: 0또는 작은 값 (1~2) — 실패 시 무한 재시도 금지activeDeadlineSeconds— 타임아웃 (예: 1800)ttlSecondsAfterFinished— 완료 후 자동 정리 (예: 86400)restartPolicy: Never- 이미지는 digest pinning (
flyway/flyway@sha256:...) resources.requests/limits명시securityContextrestricted PSA 준수
7. validate를 먼저, migrate를 나중에
운영 절차 기본 순서:
flyway info(pending migration 확인)flyway validateflyway migrateflyway info(결과 확인)- app rollout
validateOnMigrate=true 기본값이 있더라도, 운영 runbook에서는 validate 단계를
분리 Job 또는 initContainer로 분리한다.
docs/examples/infra/flyway.md 참조.
8. migration source는 Git이 source of truth
중요한 것은 아래다.
- versioned migration script (
V__) - repeatable migration script (
R__) - migration ordering
- schema history table 상태
기본 금지:
- 운영 서버에서 migration 파일 수동 수정
- 적용된 migration 파일을 사후 편집 (checksum mismatch)
- Flyway schema history table을 사람이 직접 UPDATE/DELETE
9. Flyway undo(U__)는 쓰지 않는다
Flyway Community(OSS)는 U__ 파일을 지원하지 않는다. Teams/Enterprise에서만 undo 명령이 동작한다.
기본:
- undo migration 파일을 만들지 않음
- rollback은 forward-only migration + PITR로 수행
- 운영 기본은 "다음 migration으로 앞으로 수정"
10. DB backup 전략과 migration 전략을 같이 본다
schema 변경이 production에 들어간다면, 같은 변경 계획 안에 아래가 같이 있어야 한다.
- rollback 가능 여부
- 변경 직전 backup 시점 (예: on-demand CNPG
Backup실행) - restore 단위 (전체 cluster / logical DB)
- PITR 필요 여부 + targetTime 후보
- migration 실패 시 중단 지점 (어느 V__에서 멈췄는지)
11. PostgreSQL 운영 기본 백업은 continuous physical backup
운영 기본 복구 목표가 cluster-level restore / PITR / standby seed 중 하나면 continuous WAL archiving + base backup이 기본이다.
도구 선택:
- K8s + CNPG → Barman Cloud (내장)
- K8s + Crunchy → pgBackRest (내장)
- 자체 운영 → pgBackRest 또는 WAL-G
pg_dump는 다음 용도로 제한:
- 선택적 logical export
- 로컬/테스트 seed
- 일부 schema/table 보존
- migration 검증용 비교 데이터
12. PITR 필요 여부를 초기에 결정
다음 질문에 "예"면 PITR을 우선 검토한다.
- 잘못된 migration/DDL을 특정 시점 직전으로 되돌려야 하는가
- 운영 데이터 손실 허용 시간이 짧은가 (RPO < 1h)
- 인증 관련 데이터 정합성이 중요한가
13. schema ownership은 서비스별로 분리
기본:
- auth-server schema는 auth-server 팀이 소유
- keycloak schema는 keycloak이 소유
- 공용 schema 남발 금지
- "편해서" 하나의 migration 프로젝트로 통합 관리 금지
14. Flyway history table 전략을 먼저 고정
초기에 결정:
flyway.table(기본flyway_schema_history)flyway.defaultSchemaflyway.schemasflyway.createSchemas- 필요 시
flyway.initSql
기본:
- history table을 service별 schema에 배치 (예:
auth_server.flyway_schema_history) - 여러 서비스의 history table을 하나의 schema에 몰지 않음
15. baseline / repair는 예외 절차
baseline과 repair는 정상 운영 흐름이 아니다.
허용 예:
- legacy DB를 처음 Flyway 관리로 편입 (baseline)
- 의도적 migration 수정 후 공식 절차로 checksum 회복 (repair)
- history corruption 복구 (repair)
기본 금지:
- CI/CD에서 습관적 baseline/repair
- validate 오류를 없애기 위해 무분별하게 repair
16. migration은 forward-only를 기본값으로
운영 기본값:
- 새 migration으로 앞으로 수정
- rollback용 SQL을 미리 기대하지 않음
- 실패 시 restore/PITR 또는 다음 migration으로 교정
17. Keycloak DB와 auth-server DB는 따로 본다
둘 다 PostgreSQL을 써도 운영 기준은 별도로 둔다.
- migration 파이프라인 분리
- backup/restore 영향도 분리
- schema/table ownership 분리
- 버전 업그레이드 절차 분리
- Keycloak은 자체 migration을 내장하므로 Flyway로 관리하지 않는다
18. test-server는 DB를 기본 전제로 두지 않는다
test-server가 DB 연결이 없으면 migration 대상 아님, DB secret 불필요, rollout 절차도 DB 의존 없이 단순화된다.
19. destructive migration은 expand → migrate → contract
Zero-downtime을 위한 3단계 릴리즈:
- Expand — 새 컬럼/테이블 추가 (NULL 허용 또는 default 값 있음). 기존 앱 호환.
- Migrate — 앱을 새 스키마 기준으로 배포 + 데이터 backfill.
- Contract — 기존 컬럼/테이블/제약 제거. 한 릴리즈 이상 뒤.
각 단계는 별도 릴리즈로 나간다. 같은 릴리즈에서 expand와 contract를 같이 하지 않는다.
인증/권한/토큰 관련 테이블은 특히 보수적으로.
20. DB 변경은 애플리케이션 호환성 윈도우를 고려
migration 문서는 다음을 포함한다.
- 이전 앱 버전과 호환 여부
- 새 앱 버전과 호환 여부
- 중간 배포 구간에서 허용되는 상태 (N-1 ↔ N 동시 운영 가능 여부)
- 롤백 시 DB가 이미 바뀐 상태일 때의 대응
21. 대용량 / long-running DDL은 트랜잭션 밖에서
Postgres에서 다음은 트랜잭션 밖에서 실행해야 한다.
CREATE INDEX CONCURRENTLYREINDEX CONCURRENTLYALTER TYPE ... ADD VALUE(Postgres 12+에서는 트랜잭션 내에서도 제한적으로 가능)VACUUM
Flyway에서는 해당 migration 파일 상단에 다음을 적는다:
-- flyway:executeInTransaction=false
CREATE INDEX CONCURRENTLY idx_users_email ON users(email);
22. restore 테스트 없는 backup/migration 전략 금지
다음은 반드시 drill이 있어야 한다.
- PostgreSQL base backup 복구
- WAL/PITR 절차
- Flyway 적용 후 실패 시 중단 및 복구 절차
- Keycloak/auth-server 개별 DB restore 절차
현재 스택 기본 권장안
- auth-server DB: CNPG
Cluster3 instances, Barman Cloud, RPO 5분, Flyway Job으로 migration - keycloak DB: CNPG
Cluster별도, Keycloak 자체 migration (Flyway 밖) - test-server: DB 없음
- migration-flyway: Kubernetes Job (Helm/Argo hook), 앱 Deployment보다 먼저 실행
- backup: CNPG Barman continuous WAL + daily base backup,
pg_dump는 보조
프로젝트 기준 요약
- app rollout과 migration을 분리 (app startup migration 금지)
- Postgres on K8s는 CNPG operator를 기본 후보로
- migration Job은 Helm hook 또는 Argo CD sync wave로 app보다 먼저 실행
- migration Job은
parallelism: 1,backoffLimit: 0, digest pinning, restricted PSA - Flyway undo(U__) 파일 만들지 않음 (OSS 미지원)
- validate → migrate → app rollout 순서
- CNPG Barman Cloud (또는 pgBackRest / WAL-G) 물리 백업 + PITR,
pg_dump는 보조 - schema ownership은 서비스별 분리
- destructive migration은 expand → migrate → contract, 여러 릴리즈에 걸쳐
- non-transactional DDL은
-- flyway:executeInTransaction=false