Kim Jinung

Flyway: database migration 본문

Computer Science/Database

Flyway: database migration

Kim Jinung 2022. 11. 16. 15:53
Reference - Flyway docs

Goal

1. flyway가 무엇인지 파악한다.

2. "가 왜 등장했는지 파악한다.

3. "를 어떻게 사용하는지 파악한다.

 

선행 조건

- Docker


Flyway

공식 문서에서 flyway를 데이터베이스 마이그레이션 툴로 소개하고 있다.

그렇다면 데이터베이스 마이그레이션은 왜 필요할까?

 

https://flywaydb.org/documentation/getstarted/why

 

오늘날 소프트웨어 개발에서 우리는 위와 같은 개발 프로세스를 흔하게 접할 수 있다. Axel과 Christian이 별도로 기능을 개발하고 하나로 합친다. 그리고 지속적으로 통합(Continuous Integration)한다. 해당 버전은 다시 Test를 거치면서 수정되고 최종적으로 Production 스테이지에서 서비스 한다. 그리고 어떠한 기능에 대한 니즈가 생기는 경우가 발생하면 다시 위와 비슷한 개발 과정을 거치게 된다. 개발자들은 깃과 같은 버전 컨트롤 툴을 통해서 위 과정을 잘 해오고 있다. 

 

flyway 공식 문서에서는 코드 사이드에 반해 데이터베이스의 경우 버전 컨트롤을 잘 해내지 못해왔으며, 많은 프로젝트에서 SQL 스크립트에만 의존하고 있음을 강조한다. 그리고 이로 인해 특정 머신에 있는 데이터베이스가 어느 상태인지, SQL 스크립트가 데이터베이스에 적용이 되었는지에 대한 여부, 프로덕션 레벨에서의 핫픽스가 테스트에서는 적용되었는지, 새로운 데이터베이스 인스턴스를 어떻게 생성할 것인지에 대한 문제가 발생한다. flyway 개발진은 데이터베이스 마이그레이션이 이러한 문제를 해결할 수 있는 훌륭한 방법임을 제시한다.


Flyway 작동 방식

가장 쉬운 시나리오

https://flywaydb.org/documentation/getstarted/how

flyway는 마이그레이션을 진행하기 위해서 가장 우선적으로 데이터베이스에서 스키마 기록 테이블을 찾으려고 시도한다. 위 이미지에서 왼쪽에는 Migration1, 2가 존재한다. flyway가 마이그레이션을 시도하면 Shiny DB는 비어있으므로 스키마 기록 테이블이 존재하지 않는다. 따라서 flyway는 우선 스키마 기록 테이블을 생성한다.

 

https://flywaydb.org/documentation/getstarted/how

flyway는 데이터베이스에 스키마를 기록하는 테이블을 생성했다. 이 테이블은 해당 데이터베이스(Shiny DB)의 상태를 추척하는 목적으로 사용한다.

https://flywaydb.org/documentation/getstarted/how

스키마 테이블을 생성했고, 그 이후의 모든 작업(SQL 스크립트)들은 접미사에 버전이 붙게 되며, 마이그레이션 적용 내역은 Shiny DB에 생성한 스키마 히스토리 테이블(flyway_schema_history)에 기록된다. flyway가 스키마 기록 테이블을 생성했으므로 이제 마이그레이션을 실행하면 Migration1, 2 버전 순서대로 실행한다. 이때 스키마 기록 테이블에 기록하지 않은 내역만 마이그레이션 한다. 위 과정에서 처음 생성한 스키마 기록 테이블에는 아무것도 존재하지 않을 것이므로 Migration1, Migration2 순서대로 실행할 것이다. 그런데 한 번 더 마이그레이션을 실행 한다면, flyway_schema_history 테이블에는 1, 2에 대한 기록이 존재하므로 어떠한 작업도 적용하지 않을 것이다. 이 과정을 flyway에서 제공하는 튜토리얼을 조금 응용해서 이해하기 쉽게 정리했다.


Flyway tutorial

본 튜토리얼에서 사용할 데모 프로젝트의 디렉토리 트리는 다음과 같다.

1. MySQL container 생성

데모 디렉토리를 생성하고 docker compose 명령어로 데모 MySQL 컨테이너를 하나 올린다.

mkdir -p ./FlywayDemo/MySQL && mkdir ./FlywayDemo/sql_dir
cd /FlywayDemo/MySQL

docker compose up

 

사용할 MySQL 도커 컴포즈 파일은 아래와 같다.

# docker-compose.yml

version: '3'

services:
  mysql:
    image: mysql:5.7
    platform: linux/amd64
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: flyway_demo
      MYSQL_USER: test
      MYSQL_PASSWORD: test
    volumes:
      - ./data:/var/lib/mysql
    command: ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']

2. 데이터베이스 확인

생성한 컨테이너 기반 MySQL에 연결해서 정상적으로 구동된 것을 확인한다. docker compose 파일에서 설정한 flyway_demo DB가 잘 생성되었다. 현재 DB는 비어있는 상태로 위에서 서술한 가장 쉬운 시나리오에 해당한다. 

3. SQL 스크립트 작성

이제 스크립트 기반으로 PERSON 테이블을 생성할 것이다. 

cd /FlywayDemo/sql_dir

vi V1__Create_person_table.sql
# V1__Create_person_table.sql

create table PERSON (
    ID int not null,
    NAME varchar(100) not null
);

4. 데이터베이스 마이그레이션

sql_dir 디렉토리 위치에서 아래 명령어로 flyway migration을 실행한다.

docker run -it --rm --network=host -v $(pwd):/flyway/sql flyway/flyway:7.15-alpine -url="jdbc:mysql://host.docker.internal:3306/flyway_demo" -user=test migrate

DB 패스워드를 요청하는데, 도커 컴포즈 파일에서 설정한 패스워드 test를 입력한다.

성공적으로 1개의 마이그레이션을 성공했다는 로그를 확인할 수 있다.

 

flyway_demo 데이터베이스에 flyway_schema_history 테이블이 생성되었다. 해당 테이블에 첫 번째 마이그레이션 내역이 기록되었다. 

 

DDL 명령어인 V1__Create_person_table.sql 스크립트가 마이그레이션 되어 PERSON 테이블이 생성되었다. 

 

다시 sql_dir 디렉토리로 돌아가서 V2__Add_people.sql 스크립트를 작성한다.

# V2__Add_people.sql

insert into PERSON (ID, NAME) values (1, 'Axel');
insert into PERSON (ID, NAME) values (2, 'Mr. Foo');
insert into PERSON (ID, NAME) values (3, 'Ms. Bar');

 

다시 한 번 마이그레이션 한다.

docker run -it --rm --network=host -v $(pwd):/flyway/sql flyway/flyway:7.15-alpine -url="jdbc:mysql://host.docker.internal:3306/flyway_demo?useSSL=False" -user=test migrate

두 개의 migration이 검증되었다는 문구를 확인할 수 있고, 마이그레이션은 한 개가 적용되었다. flyway_schema_history 테이블에 V1이 기록되어 있으므로 V2만 마이그레이션 된 것이다.

 

PERSON 테이블에는 V2 스크립트에서 작성한 유저 3명이 추가되었다.

 

flyway_schema_history 테이블에는 2번째 마이그레이션에 대한 기록이 추가되었다.

5. 테스트

이제 flyway가 어떻게 작동하는지를 테스트 한다.

flyway_shcema_history 테이블에서 2번째 마이그레이션을 기록한 row를 제거한다.

 

다시 마이그레이션을 시도한다.

docker run -it --rm --network=host -v $(pwd):/flyway/sql flyway/flyway:7.15-alpine -url="jdbc:mysql://host.docker.internal:3306/flyway_demo?useSSL=False" -user=test migrate

마이그레이션 하나가 적용된 것을 확인할 수 있다. flyway_schema_history 테이블에서 2번째 기록만 제거했으니, V2 스크립트가 적용되지 않았다고 판단하여 마이그레이션 한 것이다. 테이블에는 또 다시 유저 3명이 추가되어 총 6명의 유저가 존재할 것이다.

 

ID 1, 2, 3 유저가 다시 한 번 추가된 것을 확인할 수 있다. 만약 flyway_shcema_history 테이블에 존재하는 모든 마이그레이션 기록을 지우고, 마이그레이션을 시도하면 V1 -> V2 순서대로 마이그레이션을 시도할 것이다. 더 나아가 현재 DB의 사본을 생성한다면 flyway를 이용해서 버전별로 정리된 스크립트를 순서대로 실행하여 원본과 같은 상태로 인스턴스 DB에 마이그레이션 할 것이다. 


정리

flyway를 소개했던 처음의 관점과 결합하여 생각해보자. 원본 DB에 대한 작업을 모두 SQL 스크립트를 기반으로 진행했다면 flyway는 flyway_schema_history 테이블에 해당 내역을 모두 기록한다. 해당 DB의 인스턴스를 생성하고자 할 때, flyway는 스크립트의 버전 순서대로 마이그레이션을 실행하므로 원본 DB와 동일한 사본을 생성할 수 있다. 또한 마이그레이션 이후로 원본 DB에 어떠한 작업이 스크립트 기반으로 진행이 되었다고 가정해보자. 해당 스크립트로 다시 인스턴스 DB에 마이그레이션을 진행한다면 인스턴스 DB에는 flyway_schema_history 테이블이 존재하므로 내역이 기록되지 않은 스크립트만 버전 순서대로 실행하며 마이그레이션을 진행할 수 있다. flyway는 이러한 방식으로 데이터베이스를 마이그레이션 한다.


'Computer Science > Database' 카테고리의 다른 글

DB 이론  (0) 2023.07.27
[JPA] Entity Mapping  (0) 2023.05.23
DBMS Architecture  (0) 2023.05.15
JPA Architecture  (0) 2023.04.19
JDBC 그리고 ORM  (0) 2023.04.18