4/24(금) 데이터베이스 마이그레이션 (Flyway)

dev_joo·2026년 4월 24일

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

분리되어있는 여러 서비스가 하나의 DB를 바라볼 때:

우리는 비용문제로 인해 각 서비스에 DB를 두지 않고, 학습하는 과정에서 하나의 DB인스턴스를 통해 MSA 애플리케이션을 운영(?)하기로 했다.

다만, 이를 관리하기 위해서 각 서비스별로 DATABASE를 나누어 사용하기로 했다.

도커 컨테이너 생성시 DDL문 실행하기

팀원분께서 인프라 관련 설정을 하는 infra-repo를 만들어주셨다.

/postgres/init/01-create-databases.sql
이 파일에 작성한 CREATE문이 도커가 올라갈 때 실행된다.

CREATE DATABASE pagely_meeting;
CREATE DATABASE pagely_book;
...
# 🚨🚨🚨 이 아래로 본인의 데이터베이스 추가!!

Docker Hub에 등록된 PostgreSQL 공식 이미지의 설계 방식

동작 방식을 이해하기 위해 조사해서 정리해보았다.

1. 왜 해당 폴더에 ddl을 넣으면 실행될까?

PostgreSQL 공식 이미지는 컨테이너가 처음 시작될 때 특정 폴더를 확인하도록 프로그래밍되어 있다.

  • 약속된 경로: 컨테이너 내부의 /docker-entrypoint-initdb.d/라는 폴더는 '초기화 스크립트 저장소'로 약속되어 있다.

  • 자동 실행: 컨테이너가 뜨면서 내부 데이터가 비어있는 것을 확인하면, 이 폴더 안에 있는 .sql, .sql.gz, 또는 .sh 파일들을 알파벳 순서대로 모두 실행합니다.

  • 볼륨 마운트의 역할: docker-compose.db.yml 파일의 volumes 설정으로 내 컴퓨터 파일이 컨테이너 내부로 연결가능 하게 한다.
services:
  postgres:
    image: postgres:16
    container_name: pagely-postgres
    restart: always
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    ports:
      - "${DB_PORT}:5432"
    volumes:
      - pagely_postgres_data:/var/lib/postgresql/data
      - ./postgres/init/01-create-databases.sql:/docker-entrypoint-initdb.d/01-create-databases.sql:ro

volumes: # <--- 이곳!
  pagely_postgres_data:
./postgres/init/01-create-databases.sql (내 컴퓨터 파일)

:/docker-entrypoint-initdb.d/01-create-databases.sql (컨테이너 내부 경로)
  • 결과: 내 컴퓨터에 있는 SQL 파일을 컨테이너의 초기화 폴더로 '꽂아넣었기' 때문에, 도커가 뜨면서 이 파일을 읽고 DB를 생성하게 된다.

어플리케이션 단위로 환경변수 설정하는 방법 (.env 파일 활용)

기존에는 IDE 실행 설정이나 OS 환경변수를 직접 등록하는 방식을 사용했다.
하지만 이 방법은 설정 변경이 번거롭고, 서비스별로 환경을 분리하기도 쉽지 않았다.

이 문제를 해결하기 위해 팀원분이 하루종일 다양한 방법을 고민해 주셨고,
그 결과 .env 파일을 활용해 애플리케이션 단위로 환경변수를 관리하는 방식을 도입하게 되었다.

방법 1: 쉘(Shell) 스크립트를 통한 OS 레벨 주입 (set -a & source)

cd ~/pagely/something-service # ./gradlew를 실행하는 해당 서비스의 루트 디렉토리

set -a 
# 이후 선언되는 모든 변수를 자동으로 export
# 원래는 export를 일일이 붙여야 하지만, 이 설정으로 생략 가능

source .env 
# .env 파일을 현재 쉘에서 실행하여 환경 변수로 등록

set +a 
# 자동 export 설정 해제 (불필요한 변수까지 등록되는 것 방지)

./gradlew bootRun 
# Spring Boot 애플리케이션 실행

이 방식은 .env 파일에 정의된 값을 OS 레벨 환경변수로 주입한 뒤,
Spring Boot가 이를 application.yml 또는 application.properties에 바인딩하여 사용하는 구조다.

방법 2: Spring Boot 설정 파일을 통한 직접 주입 (application.yml의 spring.config.import)

🪏

여러 서비스를 포함한 상위 디렉토리에서 실행하는 경우와,
개별 서비스를 IDE에서 단독 실행하는 경우의 실행 경로 차이로 인해 .env 파일을 찾지 못하는 문제가 발생했다.

예를 들어, IDE에서 user-service만 열어 실행하면
기본 실행 경로가 이미 user-service이기 때문에 user-service/.env 경로를 찾을 수 없다.

이를 해결하기 위해 두 가지 실행 경로를 모두 고려한 설정을 적용했다.

spring:
  application:
    name: userservice
  config:
    import:
      - optional:configserver:http://localhost:8888
      - optional:file:.env[.properties]              # 현재 디렉토리 기준 (단독 실행)
      - optional:file:user-service/.env[.properties] # 상위 디렉토리 기준 (전체 실행)

.env 파일을 resources 폴더에 넣는다.

# .gitignore
src/main/resources/.env
spring:
  application:
    name: userservice
  config:
    import:
      - optional:configserver:http://localhost:8888
      - optional:classpath:.env[.properties]
profile
풀스택 연습생. 끈기있는 삽질로 무대에서 화려하게 데뷔할 예정 ❤️🔥

0개의 댓글