📑 목차 (Table of Contents)
- 들어가며: 왜 DB도 형상관리가 필요한가
- 협업의 현실: Java 개발자와 DBA의 역할 분리
- 실전 접근: DB를 위한 독립 프로젝트 구조
- 형상관리 도구로서의 Flyway
- GitLab과 CI/CD: DB 배포 자동화 구성
- 기존 프로시저 마이그레이션 방법
- 실무 팁과 마무리
1. 들어가며: 왜 DB도 형상관리가 필요한가
많은 프로젝트에서 애플리케이션 코드는 Git을 통해 관리되고, CI/CD를 통해 자동 배포됩니다. 하지만 DB는 여전히 수동으로 운영되고 있거나, 로컬 쿼리창에서 직접 작성되는 경우가 많습니다.
- “누가 이 프로시저를 마지막으로 수정했지?”
- “운영 DB는 개발 DB랑 다른 구조인데?”
- “배포 순서가 잘못돼서 의존성이 깨졌다...”
이런 문제는 DB가 형상관리 되지 않기 때문에 생기는 아주 현실적인 문제들입니다.
그렇다면, DB도 애플리케이션 코드처럼 Git으로 형상관리하고, CI/CD로 자동 배포하면 어떨까요?
이 글에서는 실제 업무에 적용 가능한 방식으로 DB를 형상관리하고 자동 배포하는 전략을 제시합니다.
2. 협업의 현실: Java 개발자와 DBA의 역할 분리
현업에서 Java 개발자와 DBA는 명확하게 다른 관심사를 갖고 있습니다.
✅ Java 개발자
- 비즈니스 로직에 집중
- MyBatis 또는 JPA를 통해 DB에 접근
- CALL 프로시저(...) 또는 SELECT 위주 쿼리 작성
✅ DBA
- 테이블 구조(Shape), 인덱스, 제약조건 관리
- 프로시저, 뷰, 트리거 등 서버 객체 설계 및 성능 튜닝
- 데이터 정합성, 보안, 배포 안정성 중시
💥 문제는 "경계 없음"에서 발생한다
예를 들어 Java 개발자가 다음과 같은 코드를 작성했다고 해보겠습니다:
<select id="getUserById" resultType="User">
CALL get_user_by_id(#{id})
</select>
하지만 get_user_by_id 프로시저는 아직 존재하지 않거나, 인자가 달라서 실행 오류가 발생할 수 있습니다. 더 큰 문제는 이런 변경이 운영 DB에서 수작업으로 처리되기 때문에 변경 이력이 남지 않고, 추적도 어렵다는 것입니다.
🔄 해결 방법: 관심사를 분리하자
- Java 개발자는 오직 프로시저 호출만 작성
- DBA는 프로시저 정의 및 변경 사항을 별도 프로젝트로 형상관리
- 양측은 **스키마 명세와 계약된 인터페이스(입출력 파라미터)**만 공유
이를 가능하게 하는 도구가 바로 Flyway + Git + CI/CD입니다.
3. 실전 접근: DB를 위한 독립 프로젝트 구조
DB 형상관리를 애플리케이션 프로젝트 내부에 억지로 묶으면 다음과 같은 문제가 생깁니다.
- 하나의 변경 사항이 여러 프로젝트에 중복 적용되어야 한다
- 스키마 변경과 코드 변경의 배포 주기가 다르다
- 공통 DB 객체(프로시저, 뷰 등)의 변경 내역을 프로젝트별로 관리하기 어렵다
이러한 문제를 해결하기 위한 실질적인 방법은 DB 스키마를 별도 프로젝트로 분리하는 것입니다.
🗂️ 디렉터리 구조 예시
/db-schema-management/
├── README.md
├── flyway.conf
├── db/
│ ├── hr_db/
│ │ ├── schema/
│ │ │ └── V1__init_schema.sql
│ │ ├── procedure/
│ │ │ ├── V2__create_proc_get_employee.sql
│ │ │ └── V3__update_proc_get_employee.sql
│ ├── finance_db/
│ │ ├── schema/
│ │ └── procedure/
│ │ └── V1__create_proc_get_invoice.sql
✍️ 설명
- db/ 디렉터리 아래에 실제 DB 이름 또는 스키마 명으로 분리
- schema/에는 테이블 및 인덱스, 시퀀스 정의 등 구조 중심
- procedure/에는 저장 프로시저, 함수, 뷰 등 서버 객체 관리
🧩 각 프로젝트의 역할 분리
구성 요소 담당자 설명
Java 프로젝트 | 개발자 | 비즈니스 로직, 프로시저 호출 쿼리 |
DB 프로젝트 | DBA | 프로시저 정의, 테이블 구조, 뷰 등 |
CI/CD 파이프라인 | 공통 | GitLab 등으로 자동 배포 연동 |
이제부터는 개발자는 인터페이스만 맞추고, DBA는 정의와 변경을 책임지고, Git은 이력을 기억합니다.
이런 방식이 정착되면 개발자도, DBA도 훨씬 깔끔하고 신뢰도 높은 협업을 할 수 있습니다.
4. 형상관리 도구로서의 Flyway
DB 형상관리 도구는 여러 가지가 있지만, 그중에서도 Flyway는 가장 널리 사용되면서도 실무에 적합한 도구입니다.
Flyway는 간단한 규칙을 기반으로 작동하면서도, SQL 스크립트 버전관리 + 마이그레이션 추적 + 자동 실행까지 지원합니다.
🚀 Flyway의 기본 개념
- 마이그레이션 파일 = SQL 파일
- V1__create_table.sql, V2__create_proc.sql 등의 이름으로 작성
- flyway_schema_history 테이블로 실행 이력 관리
- 어떤 SQL 파일이 언제 실행되었는지 자동 추적
- 버전 순서대로 실행
- V1 → V2 → V3 순으로만 실행됨
🧪 예시 마이그레이션 파일
-- 파일명: V2__create_proc_get_employee.sql
CREATE OR ALTER PROCEDURE get_employee
@emp_id INT
AS
BEGIN
SELECT id, name, position FROM employee WHERE id = @emp_id;
END;
- 파일명 규칙: V<버전번호>__<설명>.sql
- 내용: 표준 SQL 또는 해당 DB 전용 문법 사용 가능
- MSSQL이라면 CREATE OR ALTER를 적극적으로 사용하여 idempotent(중복 실행 안전)하게 관리 가능
🛠 Flyway CLI로 마이그레이션 실행
flyway -url=jdbc:sqlserver://10.0.0.1:1433;databaseName=hr_db \
-user=sa \
-password=secret \
-locations=filesystem:./db/hr_db/procedure \
migrate
- 지정한 위치의 SQL 파일을 순서대로 실행
- 실행된 항목은 DB 내부 테이블에 기록되어 다시 실행되지 않음
🧠 실무 적용 포인트
항목 설명
✅ 장점 | 코드처럼 관리 가능, 변경 이력 추적, CI/CD 연동 쉬움 |
🔁 반복 실행 | CREATE OR ALTER 사용으로 반복 실행에도 안전 |
👥 팀 협업 | Git에서 충돌 없이 SQL 이력 관리 가능 |
Flyway는 단순하면서도 강력하며, 팀과 DB를 연결하는 훌륭한 인터페이스 역할을 해줍니다.
이제 Flyway를 기반으로 CI/CD에 연결하는 방법을 살펴보겠습니다.
5. GitLab과 CI/CD: DB 배포 자동화 구성
이제 Flyway를 사용해 SQL 스크립트를 버전 관리할 수 있게 되었지만, 실무에서는 배포 자동화 없이는 진정한 생산성을 기대하기 어렵습니다.
특히 DBA가 관리하는 별도의 DB 프로젝트에서는 GitLab CI/CD를 통해 자동 배포 파이프라인을 구성하는 것이 핵심입니다.
🛠 목표
- Git에 Push하거나 Merge되면 자동으로 Flyway가 실행
- SQL 스크립트가 순서대로 실행되며 변경 이력은 DB에 기록
- 운영, 스테이징, 개발 환경에 따라 분기 가능
📁 프로젝트 구성 예시
/db-schema-management/
├── .gitlab-ci.yml
├── flyway.conf
├── db/
│ └── hr_db/
│ └── procedure/
│ ├── V1__init_schema.sql
│ └── V2__create_proc_get_employee.sql
📄 .gitlab-ci.yml 예시
stages:
- deploy
deploy_hr_db:
stage: deploy
image: flyway/flyway:latest
script:
- flyway -configFiles=flyway.conf -locations=filesystem:./db/hr_db/procedure migrate
only:
- main
- Flyway의 Docker 이미지를 사용해 SQL을 실행
- GitLab의 CI/CD Variable을 사용해 DB 접속 정보 안전하게 관리
- 브랜치 조건을 설정해 운영 브랜치에서만 배포 가능
📄 flyway.conf 예시
flyway.url=jdbc:sqlserver://db.example.com:1433;databaseName=hr_db
flyway.user=${DB_USER}
flyway.password=${DB_PASS}
flyway.baselineOnMigrate=true
⚠️ DB_USER, DB_PASS는 GitLab > Settings > CI/CD > Variables 에 등록해서 민감 정보 보호
🔄 배포 플로우 예시
flowchart TD
A[DB GitLab Repo - main branch] -->|Push 또는 Merge| B[GitLab Runner]
B --> C[Flyway Docker 실행]
C --> D[DB 접속 후 SQL 실행]
D --> E[flyway_schema_history 테이블에 이력 기록]
✅ 실무 적용 팁
항목 팁
수동 배포 | .gitlab-ci.yml에 when: manual을 넣어 수동 배포 가능 |
멀티 환경 | flyway.conf.dev, flyway.conf.prod 등으로 환경 분리 |
롤백 전략 | Flyway는 기본적으로 롤백이 없으므로, 트랜잭션 단위 처리 고려 필요 |
CI/CD가 연동되면 DBA는 직접 접속해서 SQL을 실행할 필요가 없고, 모든 배포는 Git 기록과 함께 이력에 남게 됩니다.
이제 진정한 “DB도 코드처럼” 관리하는 환경이 완성됩니다.
6. 기존 프로시저 마이그레이션 방법
현실적으로 Flyway를 도입하는 시점에서 이미 운영 중인 데이터베이스에는 많은 프로시저, 함수, 뷰, 트리거, 테이블이 존재하고 있을 가능성이 높습니다.
그렇다면 이 기존 객체들을 어떻게 Flyway 프로젝트로 안전하게 마이그레이션할 수 있을까요?
🎯 목표
- 현재 운영 DB의 상태를 기준으로 Flyway 관리 시작
- 기존 프로시저는 이력 보존용 파일로 등록
- 이후 변경부터는 Flyway로 관리
✅ 방법 1: baseline으로 현재 상태 기준선 잡기
Flyway는 처음 적용할 때 다음 명령어로 기존 DB 상태를 기준점(baseline)으로 설정할 수 있습니다:
flyway baseline -baselineVersion=1 -baselineDescription="existing prod schema"
이렇게 하면 Flyway는 V1까지는 이미 배포된 것으로 간주하고, 이후 V2__...부터 실행합니다.
✅ 방법 2: 기존 프로시저 덤프 후 파일화
운영 DB에서 이미 존재하는 프로시저들을 추출하고, V1__...sql 파일로 저장합니다.
예시: V1__existing_procedures.sql
CREATE OR ALTER PROCEDURE get_employee
@emp_id INT
AS
BEGIN
SELECT id, name, position FROM employee WHERE id = @emp_id;
END;
CREATE OR ALTER PROCEDURE list_departments
AS
BEGIN
SELECT * FROM departments;
END;
Tip: MSSQL에서는 SSMS, DataGrip, sqlpackage, Redgate 등으로 모든 프로시저를 스크립트로 추출할 수 있습니다.
🧠 실무 적용 시 주의사항
항목 설명
📌 덤프 파일은 1회용 | 기존 이력용으로만 사용하고, 이후 변경은 별도 파일(V2, V3...)로 관리 |
✅ idempotent | CREATE OR ALTER를 사용해 중복 실행에 안전하게 작성 |
🧪 개발 DB 반영 | 덤프된 파일을 개발 환경에도 반영하여 버전 일치시켜야 함 |
✅ 이후는 어떻게 관리하나?
- 프로시저 변경 → V2__update_proc_get_employee.sql 작성
- 프로시저 삭제 → V3__drop_proc_list_departments.sql 작성
- Flyway가 실행 순서와 히스토리를 자동으로 추적해줌
이렇게 하면 운영 중인 프로시저들도 안전하게 형상관리로 편입할 수 있으며, 이후부터는 개발팀과 협업도 훨씬 투명해집니다.
7. 실무 팁과 마무리
지금까지 우리는 DB를 코드처럼 관리하는 접근법, Flyway 도입, GitLab CI/CD 구성, 그리고 기존 객체 마이그레이션까지 전반적인 흐름을 살펴봤습니다.
이제 실제 적용 시 도움이 될 실무 노하우들을 정리하고 글을 마무리해보겠습니다.
✅ 실무 팁 모음
1. CREATE OR ALTER로 작성하라 (MSSQL 기준)
- 동일한 SQL이 여러 환경에서 실행되더라도 문제가 없도록 만들어야 합니다.
- DROP 후 CREATE보다 안전하고 재실행 가능성이 높은 실무에 더 적합합니다.
2. 마이그레이션 단위를 작게 쪼개라
- 테이블 생성, 인덱스 추가, 프로시저 수정은 각각 독립된 파일로 관리합니다.
- 버전 충돌 방지와 롤백 대비에 유리합니다.
3. Git 브랜치 전략과 DB 환경을 연동하라
- dev 브랜치 → 개발 DB
- release 브랜치 → 스테이징 DB
- main 브랜치 → 운영 DB
👉 이렇게 연동하면 실수 없이 환경 별로 분리된 배포가 가능합니다.
4. when: manual로 수동 승인 배포를 설정하라 (운영 안전성)
deploy_prod:
stage: deploy
script: ...
when: manual
environment: production
5. baseline은 딱 한 번만, 정말 조심해서 사용하라
- Flyway가 어떤 마이그레이션부터 적용할지를 결정하는 기준점입니다.
- 잘못 사용하면 스크립트가 무시되거나 덮어씌워질 수 있습니다.
6. 테이블/프로시저 명세는 Markdown 등으로 함께 관리하라
- Git 리포지토리 내 /docs/schema.md 같은 문서로 스키마 구조와 파라미터 명세를 함께 버전 관리하면 협업 효율이 매우 높아집니다.
🧾 정리: 이 글에서 다룬 흐름
1. 왜 DB도 형상관리가 필요한가?
2. 개발자 vs DBA 역할 분리의 필요성
3. DB 전용 Git 프로젝트 구조
4. Flyway로 버전 관리 시작
5. GitLab CI/CD로 자동 배포 구성
6. 기존 운영 DB도 안전하게 마이그레이션
7. 실무 적용을 위한 노하우 정리
✨ 마무리하며
이제는 DB도 코드처럼, 버전관리하고 협업하며 자동 배포하는 시대입니다.
Flyway는 간단하지만 강력한 도구입니다. Git과 CI/CD를 곁들이면, DB 변경도 애플리케이션 코드처럼 안전하고 투명하게 관리할 수 있습니다.
그리고 이 변화는 DBA와 개발자 모두에게 이득이 됩니다.
📢 다음에 다룰 수 있는 주제 (후속 글 예고)
- Flyway + Spring Boot 통합 사용 방법
- Redgate와 같은 GUI 툴과의 차이점
- Flyway 대신 Liquibase를 써야 하는 경우는?