[Spring] 하나의 YAML을 여러 개로 나누어 환경 분리하기

Hyunjoon Choi·2023년 8월 19일
2

Spring

목록 보기
2/2
post-thumbnail

YAML (yml)

스프링에서는 환경 변수, 데이터 소스 (DataSource) 등 프로그램이 돌아갈 때 필요한 정보들을 보관할 수 있도록 application.properties 또는 application.yaml을 지원한다. 그런데 개발하는 환경이 달라질 때 마다 이들의 값들을 매번 바꾸는 것은 귀찮은 작업이 되기도 한다.

분리 이전 사용 예시

예시로, 실제 개발 환경에는 MySQL을 쓰고 ddl-autonone으로 되는 게 맞지만, 로컬 개발 환경에서는 매번 확인해보는 게 좋기 때문에 h2 인메모리 데이터베이스를 쓰면서 ddl-autocreate로 하는 게 적합할 것이다.

MySQL

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/디비_이름?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
    username: MySQL 관리자 이름
    password: MySQL 비밀번호 
  jpa:
    hibernate:
      ddl-auto: none

H2 (In-memory)

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:디비_이름
    username: sa
    password: 

이때 이 둘을 자주 바꿔 갈아끼우다보면 때로는 잘못 작성하는 일도 발생할 것이다. (일부분만 바꾼다거나, 값을 까먹거나, 또는 주석을 쓴다고 해도 깔끔하지 않은 측면이 있다.)

YAML 파일들을 분리하기 위한 규칙

이제 그렇다면 이러한 문제점을 해결하기 위해 YAML 파일들을 분리해보자.
크게 로컬 환경, 개발 환경으로 나누어보겠다. (운영 환경은 운영하고 있는 예가 없기 때문에 보류) (그 전에 지켜야 할 규칙들이 있다.)

1️⃣ 파일 이름 설정하기

먼저, YAML 파일 이름을 정할 때는 나름의 규칙을 지켜야 한다.
스프링에서는 application-{profile}.yml을 통해 이들을 구분하고 활용할 수 있다. 여기에서 {profile}에 원하는 이름을 작성하면 된다.

이 내용은 공식 문서에서도 나와있다.

Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).

2️⃣ 파일 보관 장소 지정하기

만약 파일 보관을 application.yml과 같은 곳에 전부 넣어둘 것이냐, 또는 다른 폴더들을 만들어 넣어둘 것이냐에 따라 작성 방식이 살짝 달라진다. 이 부분은 아래 설명을 참고한다.

3️⃣ application.yml 작성하기

마지막으로, application.yml을 작성하면 된다. 이 위치는 변경되면 안 된다. (추후 경로를 바꿀 수 있긴 하지만 그러지 않는 게 편하다.)

실전 예시

아직 정확히 어떤 식으로 작성해야 하는지 감이 잘 오지 않을테니, 실제 예시를 통해 보도록 하자.

구조

구조는 다음과 같이 되어있다.

project
├── src
│   ├── main
│   ├── java
│   ├── resources
│   │   ├── static
│   │   ├── templates
│   │   ├── yaml
│   │   │   ├── logging
│   │   │   │   └─ application-log.yml
│   │   │   ├── application-dev.yml
│   │   │   └─ application-local.yml
│   │   └─ application.yml
...

나는 기본적인 application.yml을 두고, 로그 기능들이 담겨진 application-log.ymlyaml/logging에, 개발 환경과 로컬 환경을 뜻하는 application-dev.ymlapplication-local.ymlyaml에 보관한다고 설정했다.

application-dev.yml

spring:
  config:
    activate:
      on-profile: dev
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul
    username: {데이터베이스 관리자 이름}
    password: {데이터베이스 비밀번호}
  jpa:
    hibernate:
      ddl-auto: none
  • 개발 환경을 뜻하는 문서다. (팀원들과 작업하는)
  • MySQL 데이터베이스를 활용한다.
  • ddl-auto 옵션을 none으로 적용했다.

application-local.yml

spring:
  config:
    activate:
      on-profile: local
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:test
    username: sa
    password: 
  • 로컬 개발 환경을 뜻하는 문서다.
  • H2 인메모리 데이터베이스를 활용한다.
  • 인메모리이기 때문에 ddl-auto를 작성하지 않아도 문제 없다.

application-log.yml

spring:
  config:
    activate:
      on-profile: log
  jpa:
    properties:
      hibernate:
#       show_sql: true # System.out 방식 로그
        format_sql: true
        highlight_sql: true
        use_sql_comments: true
logging:
  level:
    org:
      hibernate:
        SQL: debug # logger 방식 로그
        orm:
          jdbc:
            bind: trace
  • SQL을 출력하고, 꾸미는 기능이다.

application.yml

spring:
  config:
    import:
      - classpath:/yaml/application-prod.yml
      - classpath:/yaml/application-dev.yml
      - classpath:/yaml/application-local.yml
      - classpath:/yaml/logging/application-log.yml
  profiles:
    group:
      logging: dev, log
    active: logging
#    active: local
  • 공통적인 문서다.
  • 만약 다른 폴더에 없이, 문서들이 application.yml과 같은 곳에 있다면 spring.config.import를 작성할 필요가 없다. 이것은 다른 폴더에 있을 때 스프링이 인식할 수 있도록 하기 위해 작성한 것이다.
  • 특정 문서를 하나 쓰고 싶을 때는 spring.profiles.active에 해당 profile 값을 넣으면 된다.
  • 여러 개의 문서를 쓰고 싶을 때는 spring.profiles.group{원하는 이름}: {profile 1}, {profile 2}등과 같이 그룹화시키고, spring.profiles.active에 해당 {원하는 이름}을 작성해두면 된다.

또한, application.yml을 제외한 각 문서들을 보면 다음과 같은 내용이 있다.

spring:
  config:
    activate:
      on-profile: log

이것은 자신이 실행될 profile을 의미한다. 만약 이것을 작성해놓지 않는다면, application.yml에서 import 한 순서에 따라 맨 마지막에 작성된 yml로 덮어씌워지게 된다. (모두 다 같은 폴더에 위치시킨 다음 spring.config.activate.on-profile을 작성해놓지 않을 수도 있겠지만 이 경우는 시도해보진 않았다.)

실전 결과

application-local.yml & application-log.yml 조합

application-log.yml을 사용했기에 쿼리가 나오고, application-local.yml을 사용했기에 create table이 나온다.

drop table if exists member
[Hibernate] 
    drop table if exists member
2023-08-19T16:47:04.656+09:00 DEBUG 12287 --- [           main] org.hibernate.SQL                        : 
    create table member (
        id bigint not null auto_increment,
        name varchar(255),
        primary key (id)
    ) engine=InnoDB
[Hibernate] 
    create table member (
        id bigint not null auto_increment,
        name varchar(255),
        primary key (id)
    ) engine=InnoDB

application-dev.yml만 사용

application-dev.yml만 사용했기에 쿼리가 나오지 않는다.

2023-08-19T16:47:32.556+09:00  INFO 12294 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-08-19T16:47:32.593+09:00  INFO 12294 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-08-19T16:47:32.928+09:00  WARN 12294 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-08-19T16:47:33.307+09:00  INFO 12294 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2023-08-19T16:47:33.318+09:00  INFO 12294 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 4.435 seconds (process running for 5.046)
2023-08-19T16:47:37.165+09:00  INFO 12294 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-08-19T16:47:37.166+09:00  INFO 12294 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-08-19T16:47:37.168+09:00  INFO 12294 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

느낀 점

  • 함께하고 있는 프로젝트에서도 이와 비슷한 방식으로 yml 파일들을 관리하고 있는데 이제야 나도 이러한 부분에 있어 기여할 수 있겠다는 생각이 들었다.
  • 테스트에서는 어떻게 쓸 수 있을지 고민이 든다. 아직 시도해보지 않는 방법이라 더 익혀야 할 것 같다.

참고 글


부족하거나 보완할 점이 있다면 댓글 부탁드립니다 😃

profile
개발을 좋아하는 워커홀릭

0개의 댓글

관련 채용 정보