[Spring Boot] 개발-운영 환경 resource 나누기 (Gradle)
들어가며
서비스를 제공하다 보면 운영환경과 개발환경이 서로 다른 경우들이 있다. 예를 들면, 운영 DB와 개발 DB 환경이 다르거나, 로그 레벨을 다르거나 하는 경우이다. 그럴 때마다 매번 application.yml 혹은 logback.xml 파일을 수정할 수 있지만, 매우 비효율적이다. 이번 게시글에서는 실행환경(profile)에 따라 다른 설정 파일을 사용하는 방법에 대해서 알아보려고 한다.
이번 게시글은 스프링 2.4 이상 버전을 기준으로 작성하였다. 2.4 버전을 기준으로 application.yml에서 active profile을 설정하는 방법이 바뀌었다.
<2.4 미만>
spring:
profiles:
active: dev
<2.4 부터>
spring:
config:
activate:
on-profile: dev
1. resources 구성
공통으로 사용하는 자원들은 resources 폴더에, 각 환경에 따라 사용할 자원들은 resources-{profile} 폴더에 위치하도록 구성했다. 실행환경에 따라 다르게 사용하고 싶은 파일들을 각 폴더에 맞게 넣어주면 된다.
이번 게시글에서는 실행환경을 dev, prod로 나누어 각각 DB 환경과 로그 레벨, logback-spring 설정을 다르게 구성하도록 테스트해보려고 한다.
2. application.yml 작성
resources/application.yml
spring:
profiles:
active: dev # default profile
그 외 공통 설정들...
공통 설정 정보들을 입력한다. spring.profiles.active 설정을 적용하여 기본 실행환경(profile)을 dev로 설정한다.
resources-dev/application-dev.yml
spring:
config:
activate:
on-profile: dev
datasource:
hikari:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:mysql://localhost:3306/test_master?characterEncoding=UTF-8
username: root
password: 1234
logging:
level:
web: info
root: info
com.jdh.resourceEnvTest: info
resources-dev/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%boldMagenta(%d{MM-dd HH:mm:ss}) [%boldYellow(%-5level)] %cyan(%logger{5}.%M) - %msg %n</pattern>
</encoder>
</appender>
<logger name="jdbc" level="OFF" />
<logger name="jdbc.sqlonly" level="INFO" />
<logger name="jdbc.sqltiming" level="OFF" />
<logger name="jdbc.audit" level="OFF" />
<logger name="jdbc.resultset" level="OFF" />
<logger name="jdbc.resultsettable" level="OFF" />
<logger name="jdbc.connection" level="OFF" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
dev 환경에서 사용할 DB 정보와 로그 레벨을 info로 설정하는 yaml 파일을 작성한다. dev 환경에선 test_master 스키마를 사용하였다. 또한, 실행 쿼리를 확인할 수 있도록 logback-spring의 sqlonly 레벨을 info로 설정하였다.
spring.config.activate.on-profile: dev 설정으로 실행환경(profile)이 dev인 경우 해당 yaml 파일을 사용하도록 했다.
resources-prod/application-prod.yml
spring:
config:
activate:
on-profile: prod
datasource:
hikari:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:mysql://localhost:3306/test_slave?characterEncoding=UTF-8
username: root
password: 1234
logging:
level:
web: error
root: error
com.jdh.resourceEnvTest: error
resources-prod/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%boldMagenta(%d{MM-dd HH:mm:ss}) [%boldYellow(%-5level)] %cyan(%logger{5}.%M) - %msg %n</pattern>
</encoder>
</appender>
<logger name="jdbc" level="OFF" />
<logger name="jdbc.sqlonly" level="OFF" />
<logger name="jdbc.sqltiming" level="OFF" />
<logger name="jdbc.audit" level="OFF" />
<logger name="jdbc.resultset" level="OFF" />
<logger name="jdbc.resultsettable" level="OFF" />
<logger name="jdbc.connection" level="OFF" />
<root level="ERROR">
<appender-ref ref="STDOUT" />
</root>
</configuration>
prod 환경에선 test_slave 스키마를 사용하고, 로그 레벨을 error로 설정하였다. 또한, 실행 쿼리를 볼 수 있는 로그 레벨을 OFF로 설정하여 로그가 출력되지 않도록 했다.
spring.config.activate.on-profile: prod 설정으로 실행환경(profile)이 prod인 경우 해당 yaml 파일을 사용하도록 했다.
3. build.gradle 작성
// Default는 dev 로 지정
ext.profile = (!project.hasProperty('profile') || !profile) ? 'prod' : profile
// 리소스 폴더 지정
sourceSets {
main {
resources {
srcDirs "src/main/resources", "src/main/resources-${profile}"
}
}
}
build.gradle에 해당 내용을 추가한다. build and run 시 각 실행환경(profile) 별로 사용할 resource 폴더를 지정한다.
그리고 해당 내용을 추가한다.
tasks {
processResources {
duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.INCLUDE
}
}
공통으로 사용하는 application.yml과 실행환경마다 사용하는 application-{profile}.yml을 동시에 사용하는 경우 중복된다는 에러가 발생하는데, 해당 에러를 방지해주는 설정이다.
4. 빌드
방법 1.
#개발: 아래 둘 다 가능
gradle clean bootRun
gradle clean bootRun -Pprofile=dev
#운영
gradle clean bootRun -Pprofile=prod
방법 2. gradle task
별다른 설정이 없는 경우 dev 환경에서 실행된다.
prod 환경에서 실행하기 위해 gradle bootRun 시 2가지 설정을 추가하였다.
- gradle build 시 어떤 resources 폴더를 사용할지에 대한 project property를 추가했다.
- bootRun -Pprofile=prod
- spring boot 프로젝트가 실행될 때 실행환경(profile)을 환경변수로 설정하여 해당하는 yaml 파일을 읽어오도록 설정한다.
- Environment variables: SPRING_PROFILES_ACTIVE=prod
두 가지를 모두 설정해줘야 gradle task에서 정상적으로 동작한다.
방법 3. Spring Boot Run (IntelliJ Build)
흔히 사용하는 실행 방법이다.
방법 2와 마찬가지로 별다른 설정이 없는 경우 dev 환경에서 실행된다.
방법 3에서도 prod 환경을 설정할 때 방법 2와 같은 2가지 설정을 추가한다.
위와 같이 Active profiles를 prod로 설정한다. 이렇게 하면 spring boot 프로젝트가 실행될 때 실행환경(profile)을 환경변수로 설정하여 해당하는 yaml 파일을 읽어오도록 설정한다.
build.gradle
ext.profile = (!project.hasProperty('profile') || !profile) ? 'prod' : profile
위에서 설정한 build.gradle의 profile 변수의 기본값을 prod로 변경해준다. gradle build를 사용할 때와 다르게 방법 3은 gradle에 직접 profile property를 할당하지 않고 이와 같이 편하게 설정할 수 있다.
5. 결과
필자는 실행 전 각 DB의 데이터를 조회하여 logging 해주는 기능을 추가하여 실행환경에 따른 설정 변화를 확인하였다.
@Autowired TestService testService;
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("log info -> {}", testService.getTest());
log.error("log error -> {}", testService.getTest());
}
1. dev
The following 1 profile is active: "dev"
프로젝트를 실행하면 console 창에 이와 같이 실행환경이 출력된다.
dev 환경에서는 log level을 info로 설정하였고, 실행 쿼리를 로그로 출력하도록 설정했기 때문에 관련된 log가 모두 출력되는 것을 볼 수 있다. 또한 DB에서 조회한 dev라는 데이터를 함께 출력한다.
2. prod
prod 환경에서는 log level을 error로 설정하였고, 실행 쿼리 등 다른 쿼리는 전부 OFF로 설정했기 때문에 error 로그만 출력되는 것을 볼 수 있다. 또한 DB에서 조회한 prod라는 데이터를 함께 출력한다.
관련 소스 코드는 깃허브를 참고하면 된다.
링크 : https://github.com/JangDaeHyeok/sprint_resource_env_practice