본문 바로가기
IT & Tech 정보

DB 마이그레이션 자동화 끝판왕 가이드

by 지식과 지혜의 나무 2025. 5. 26.
반응형


주제 8: Flyway · Liquibase + GitHub Actions 연동

1. 서론: 왜 ‘끝판왕’ 마이그레이션인가

수백 개 마이크로서비스·다중 환경(Dev/Staging/Prod)·다양한 데이터베이스(MySQL, PostgreSQL, Oracle 등)를 운영하는 톱티어 IT기업에서는, 마이그레이션 오류 하나가 고객 가용성·데이터 무결성을 순식간에 붕괴시킬 수 있습니다. 교과서 수준 ‘수동 스크립트 실행’은 더 이상 답이 아닙니다.
• 버전 관리 일원화: 코드 리포지토리로 모든 변경 이력 추적
• 자동 검증·롤백: CI 단계에서 스키마 충돌·데이터 손실 사전 탐지
• 환경별 전략: Preview DB 생성 후 샌드박스 마이그레이션 테스트
• 동시 배포: 여러 서비스가 공유하는 공통 테이블·파티셔닝 안정 지원

이제 Flyway와 Liquibase의 고급 기능을 결합하고, GitHub Actions 파이프라인에서 완전 자동화하는 ‘끝판왕’ 워크플로우를 구성해 보겠습니다.



2. 아키텍처 개관

┌───────────────────┐      ┌─────────────────────────┐
│   GitHub Repo     │─────▶│ GitHub Actions CI/CD    │
│ (migrations/,     │      │ ├─ Flyway 검사·마이그레이트 │
│  services/, .github) │   │ ├─ Liquibase 검증·리포트  │
└───────────────────┘      │ └─ Preview DB → Smoke Test │
                              └─────────────────────────┘
                                        │
                                        ▼
                           ┌────────────────────────┐
                           │  실제 DB (Dev/Staging/Prod) │
                           └────────────────────────┘

1. GitHub Repo
• migrations/flyway/, migrations/liquibase/ 디렉터리로 분리
• services/*/.github/workflows/db-migrate.yml 에서 환경별 워크플로우 정의
2. GitHub Actions
• PR 이벤트: flyway validate & liquibase diff → 결과 코멘트
• main 머지: flyway migrate → liquibase update 순차 실행 → 자동 롤백 프로세스
• Preview DB: ephemeral 인스턴스 프로비저닝 후 마이그레이션 & 테스트
3. 실제 DB 클러스터
• 환경별 Credential/접속 정보는 GitHub Secrets·HashiCorp Vault 연동



3. Flyway 고급 활용

3.1 폴더 구조

migrations/
└─ flyway/
   ├─ sql/
   │  ├─ V1__create_users.sql
   │  ├─ V2__add_email_idx.sql
   │  └─ R__cleanup_legacy.sql   ← Repeatable Migration
   ├─ conf/
   │  └─ flyway.conf             ← 공통 설정
   └─ Dockerfile                 ← CI 컨테이너 빌드

3.2 conf 설정

# migrations/flyway/conf/flyway.conf
flyway.url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
flyway.user=${DB_USER}
flyway.password=${DB_PASS}
flyway.locations=filesystem:sql
flyway.baselineOnMigrate=true
flyway.outOfOrder=true
flyway.target=latest
flyway.validateOnMigrate=true
flyway.schemas=public,extensions
flyway.repeatableSqlMigrationPrefix=R__

• outOfOrder: 브랜치별 병렬 개발 시 순서 뒤엉킴 방지
• repeatable migrations: 뷰·프로시저 등 idempotent 로직 자동 재적용

3.3 Docker로 실행

# migrations/flyway/Dockerfile
FROM flyway/flyway:9-alpine
COPY sql/ /flyway/sql/
COPY conf/flyway.conf /flyway/conf/

• 이미지 버전 고정: flyway/flyway:9.16.1
• CI 캐시: 빌드된 Docker 이미지 캐싱으로 속도 최적화

3.4 검증 & 마이그레이션

# validate stage
docker run --rm \
  -e DB_HOST -e DB_PORT -e DB_NAME -e DB_USER -e DB_PASS \
  flyway/flyway validate

# migrate stage
docker run --rm \
  -e DB_HOST -e DB_PORT -e DB_NAME -e DB_USER -e DB_PASS \
  flyway/flyway migrate

• validate 실패 시 CI 중단
• -ignorePendingMigrations=false 기본값으로, 미적용 마이그레이션 감지



4. Liquibase 고급 활용

4.1 폴더 구조

migrations/
└─ liquibase/
   ├─ changelogs/
   │  ├─ master.xml
   │  ├─ 2025-01-15-add-orders-table.xml
   │  └─ 2025-02-10-modify-customers.yaml
   ├─ drivers/
   │  └─ postgresql.jar
   └─ liquibase.properties

4.2 properties 설정

# migrations/liquibase/liquibase.properties
url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
username=${DB_USER}
password=${DB_PASS}
changeLogFile=changelogs/master.xml
contexts=dev,staging,prod
liquibase.hub.mode=off
liquibase.sqlFormat=yaml,json,xml
liquibase.rollbackFile=rollback.sql
liquibase.diffChangeLogFile=diff_changelog.xml

• contexts: 환경별 분기(예: <changeSet context="dev">)
• diffChangeLogFile: 현행 스키마 vs 코드 차이 자동 추출

4.3 마스터 체인리스트

<!-- migrations/liquibase/changelogs/master.xml -->
<databaseChangeLog
    xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="...">
  <includeAll path="changelogs/" relativeToChangelogFile="true"/>
</databaseChangeLog>

• includeAll: 파일명 타임스탬프 순 정렬

4.4 검증·롤백

# diff 검증
liquibase \
  --defaultsFile=liquibase.properties \
  diff

# update
liquibase \
  --defaultsFile=liquibase.properties \
  update

# rollback
liquibase \
  --defaultsFile=liquibase.properties \
  rollbackCount 1

• diff 로 코드에 없는 테이블·컬럼 감지 → 자동 fail PR
• rollbackCount 대신 tag 기반 롤백(rollback <tag>)



5. GitHub Actions 연동

# .github/workflows/db-migrate.yml
name: DB Migration CI

on:
  pull_request:
    paths:
      - 'migrations/**'
  push:
    branches: [ main ]

jobs:
  validate:
    runs-on: ubuntu-latest
    env:
      DB_HOST: ${{ secrets.DB_HOST }}
      DB_PORT: ${{ secrets.DB_PORT }}
      DB_NAME: ${{ secrets.DB_NAME_PREVIEW }}
      DB_USER: ${{ secrets.DB_USER }}
      DB_PASS: ${{ secrets.DB_PASS }}
    steps:
      - uses: actions/checkout@v3

      # Flyway Validate
      - name: Build Flyway Image
        run: docker build -t flyway-ci -f migrations/flyway/Dockerfile migrations/flyway
      - name: Flyway Validate
        run: |
          docker run --rm -e DB_HOST -e DB_PORT -e DB_NAME -e DB_USER -e DB_PASS flyway-ci validate

      # Liquibase Diff
      - name: Liquibase Diff
        run: |
          cd migrations/liquibase
          docker run --rm \
            -v $(pwd):/liquibase/changelogs \
            liquibase/liquibase \
            --defaultsFile=liquibase.properties diff

  migrate:
    needs: validate
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    env:
      DB_HOST: ${{ secrets.DB_HOST }}
      DB_PORT: ${{ secrets.DB_PORT }}
      DB_NAME: ${{ secrets.DB_NAME_PROD }}
      DB_USER: ${{ secrets.DB_USER }}
      DB_PASS: ${{ secrets.DB_PASS }}
    steps:
      - uses: actions/checkout@v3

      - name: Flyway Migrate
        run: |
          docker run --rm -e DB_HOST -e DB_PORT -e DB_NAME -e DB_USER -e DB_PASS flyway-ci migrate

      - name: Liquibase Update
        run: |
          cd migrations/liquibase
          docker run --rm \
            -v $(pwd):/liquibase/changelogs \
            liquibase/liquibase \
            --defaultsFile=liquibase.properties update

• Preview 환경(PR): validate job만 실행
• Production(main 머지): migrate job 자동 호출
• Job Output: 결과 스캔하여 PR 코멘트(actions/github-script)



6. 실전 팁 & “아, 이런 방법도”
1. Migration Preview Mode

flyway migrate -dryRunOutput=output.sql

• 실제 DB 변경 없이 SQL 덤프로 사전 리뷰

2. Branch Merging 자동 Diff

- name: Generate Flyway Diff
  run: |
    BASE_SHA=$(git merge-base origin/main HEAD)
    git diff $BASE_SHA HEAD -- migrations/flyway/sql > flyway_changes.sql


3. Liquibase ChangeLog Lock 해제

liquibase releaseLocks


4. Database Container in CI

services:
  postgres:
    image: postgres:13
    ports: ['5432:5432']
    env:
      POSTGRES_DB: testdb
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test


5. Semantic Versioning:
• V{major}_{minor}__description.sql → V2_3__add-table.sql



7. 결론: “끝판왕” 마이그레이션 자동화
• Flyway: Versioned & Repeatable Migration으로 스키마 일관성 보장
• Liquibase: Diff 기반 검증·Rollback 지원
• GitHub Actions: Preview DB 검증 → Main 자동 마이그레이션

“교과서론 절대 다루지 않는, 실리콘밸리·심천 IT기업 최정예 개발자 수준의 DB 마이그레이션 자동화”를 직접 구현해 보세요. 데이터 무결성과 가용성 모두 잡는 그날까지, 이 워크플로우가 든든한 파트너가 되어 드립니다!

반응형