[Spring] Spring System Properties 그리고 Spring Profiles에 대해

최동근·2023년 5월 23일
2

안녕하세요 오늘은 Spring System properties 를 설정하는 방식과 이를 환경에 따라 효과적으로 설정하는 방법인 Spring Profile 에 대해 알아보겠습니다.

해당 포스팅을 읽어보기 전 Spring 설정 파일에 있는 설정 값을 애플리케이션에서 활용하는 방법 (@Value,@ConfigurationProperties) 을 참고하면 이번 포스팅을 이해하는 데 도움이 될 것입니다 🔥

🌱 시스템 프로퍼티란?

시스템 프로퍼티(System Properties) 란 JVM 시 구동할 때 자동으로 설정되는 시스템 속성값입니다. 시스템 프로퍼티는 키(Key) 와 값(Value)로 구성되어 있으며 운영체제에서 사용되는 파일 경로, 구분자, 운영체제의 종류 및 자바 프로그램을 실행시킨 사용자 아이디 JVM 버전등이 여기에 속합니다.

시스템 프로퍼티는 Enviroment 를 통해 확인 가능합니다.
Enviroment 란 말 그대로 스프링 환경이자 설정과 관련된 인터페이스입니다. 쉽게 이해하자면 스프링 Setting 이라고 보면 될 것 같습니다 💪

그리고 EnviromentApplication Context 에 또 다른 기능입니다.

public interface ApplicationContext extends EnviromentCapable, ListableBeanFactory, 
HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {

위의 코드는 ApplicationContext 의 인터페이스 선언부입니다.
여기서 집중해야할 부분은 EnviromentCapable 인터패이스를 부모 인터페이스로 두고 있는 것을 확인할 수 있는데 이는 바로 ApplicationContext 가 DI 기능 뿐만 아니라 Enviroment 까지 제공하고 있다는 것입니다 ❗️

public interface EnviromentCapable {
	Enviroment getEnviroment();
}

해당 코드는 위에서 나왔던 EnviromentCapable 인터페이스의 선언부입니다.
getEnviroment 를 통해 Enviroment 에 접근할 수 있는 것을 알 수 있습니다.

@Component
public class Runner implements AppicationRunner {
	
    @Autowired
    ApplicationContext ctx;
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
      Enviroment env = ctx.getEnviroment(); // Enviroment 객체 
      System.out.println(Arrays.toString(enviroment.getActiveProfiles());
    }
}

해당 코드는 ApplicationContext 타입의 ctx 객체를 통해 Enviroment 를 가져오는 코드입니다.

이야기가 너무 길어졌는데, 결국 스프링 구동시 설정되는 값들은 시스템 프로퍼티 라고 하며 이는 스프링의 설정 값들을 추상화해놓은 Enviroment 로 읽어올 수 있습니다.

🌱 Spring Profile에 대해

서비스를 개발하다보면 하나의 서버 Application에 대해서 다양한 환경에서 실행하는 일이 빈번하게 생깁니다. 예를 들어 로컬 환경에서 개발하다가 테스트 환경에서 테스트를 진행하기도 하고 실제 운영 환경에서 어플리케이션을 구동해보기도 합니다.
이때 환경마다 필요한 설정값이 다른데 환경 변경마다 해당 설정값들을 바꾸는 일은 개발자 입장에서는 번거로운 일입니다 🥲

이를 해결하기 위해 Spring 에 Spring Profile 이라는 기능을 제공합니다.
Spring Profile 은 각 환경마다의 설정 값들을 프로파일로 미리 정의해놓아 특정 환경에서 가동시 해당 프로파일을 주입하는 방식으로 동작합니다.

application.properties

application.properties을 통해 각 환경마다 설정값을 다르게 하는 법을 알아보겠습니다.
application.properties 를 사용하면, 환경별로 각기 다른 파일을 만들어야 합니다.
보통 환경은 사용자가 정의하기 나름이지만 dev(개발),test(테스트),local(로컬),prod(운영) 등이 사용됩니다.

환경별로 다른 파일을 만드는 경우 무조건 application-{사용할 환경 이름}.properties 형식으로 파일 이름을 지정해야합니다 ❗️

해당 이미지에는 총 4개의 properties 파일이 존재합니다.
특정 환경에 맞는 profiles 를 설정은 default 로 제공되는 application.properties 파일에 spring.profiles.active={활성화할 환경} 을 통해 할 수 있습니다. local profile 을 활성화 해볼까요?

application.properties 안에 spring.profiles.active=local 을 설정 후에 프로그램을 run 하면 local profile이 동작하는 것을 확인할 수 있습니다.

application.yml

앞서 살펴본바와 같이 .properties 로는 각 profile 에 맞는 파일을 모두 생성해야 했습니다.
하지만 .yml 타입의 파일로는 더욱 간편하게 profile 을 설정할 수 있습니다 ❗️
위에 제시된 application.yml 에서 볼 수 있듯이 --- 로 프로파일 영역별 경계를 설정하는 것이 가능합니다.
즉, 하나의 yml 파일로 여러가지 프로파일의 경계를 설정할 수 있습니다.

spring:config:activate:on-profile 에 값은 선택할 수 있는 profile 이 주입되게 됩니다.
따라서 spring:profiles:active 에 들어가는 profile 적용됩니다 ❗️

Spring 에서 기본으로 제공되는 application.yml 에 spring:active:profiles = local 로 설정했기 때문에 spring:config:activate.on-profile = local 즉, local profile 이 동작합니다.
만약 spring:profiles:active 에 A 라는 프로퍼티가 있지만 spring:config:activate:on-profile 에는 A 라는 프로퍼티가 없다면 활성화된 profile 과 무관하게 모든 profile 에 공통적으로 사용됩니다.

🌱 Edit Configuration을 통한 여러가지 설정

지금까지 profile 별 설정값을 나누어서 해당하는 환경에 맞는 profile 을 지정하는 방식을 알아보았습니다.
이번에는 Edit Configuration을 통해서 여러가지 시스템 프로퍼티와 profile 을 지정하는 방식을 알아보겠습니다 ❗️

인텔리제이 Edit Configuration

인텔리제이 상단에 Edit Configuration 버튼을 누르면 이와 같이 빌드 및 실행에 대한 설정을 할 수 있는 창이 뜹니다.

오른쪽 옵션 수정을 누르면 입력할 수 있는 방식인 VM 옵션환경 변수 를 사용할지를 결정할 수 있습니다 👨‍💻
두가지 옵션과 활성화된 프로파일 을 통해 원하는 Profile 및 여러가지 JVM 프로퍼티를 주입할 수 있습니다.

활성화된 프로파일

인텔리제이 구성 편집 기능에서는 기본적으로 프로파일을 지정할 수 있는 기능을 제공합니다.

그림과 같이 활성화된 프로파일 부분에 원하는 profile 의 이름을 설정하고 구동하면 해당 profile 로 서버 어플리케이션이 구동합니다.
그렇다면 앞서 다룬 application.yml 에서 spring:profiles:active = local 로 설정 후 구성 편집 에서 test profile 로 구동하면 어떻게 될까요? 🤔

구동 결과 구성 편집 에서 설정한 test profile 로 서버 어플리케이션이 구동되는 것을 확인할 수 있습니다.

즉 개발자는 디폴트로 참조할 profile 을 applicaiton.yml 에 spring:profiles:active 로 지정하고 상황에 따라 구성 편집 을 통해 원하는 profile 을 새로 설정하는 식으로 사용하면 좋을 것 같습니다 🙋

VM 옵션

VM 옵션이란 JVM 수준에서 특정 시스템 프로퍼티 값을 주입할 수 있는 기능입니다. 기본적으로는 Configuration Edit 창에 VM 옵션을 선택할 수 있는 부분이 노출되지 않으므로 개발자는 오른쪽 상단에 있는 옵션 수정(M) 을 통해 VM 옵션 기능을 체크해 주어야합니다.
VM 옵션은 -D{주입할 시스템 프로퍼티 or 설정값} 형식으로 주입해야합니다.
여기에는 다양한 값을 넣을 수 있는데 앞서 이야기 했던 Profile 도 주입할 수 있습니다.
Profile 을 VM 옵션으로 설정하기 위해서는 -Dspring.profiles.active={profile} 식으로 주입하면 됩니다 ❗️
해당 이미지는 prod(운영 환경) profile 을 VM 옵션으로 주입하는 방법입니다.
profile 지정 외에도 어플리케이션을 구동하면서 필요한 여러가지 값들(ex 데이터베이스 관련 값, JWT 관련 값) 들을 해당 기능을 통해 주입할 수 있습니다 💪

운영체제 내 시스템 환경변수

다음은 OS 자체에 시스템 환경변수 를 설정하는 방법입니다.
이는 앞서 살펴본 VM 옵션과 동일한 기능을 수행하지만 OS 수준에서 값을 주입한다는 차이점을 가집니다.
또한 CONSTANT_CASE 방식으로 작성해야합니다 ❗️

해당 이미지는 운영체제 내 시스템 환경변수를 통해서 Profile 을 prod 로 설정하는 방법을 나타냅니다 👨‍💻

🌱 마치며

이번 포스팅에서는 다양한 기능을 통해 스프링 Profiles 를 설정하는 방식을 알아보았습니다.
물론 이미지에서 나와 있듯히 VM 옵션과 운영체제 내 시스템 환경변수 를 사용하지 않고 기본적으로 Configuration Edit 창에서 제공하는 활성화된 프로파일 을 통해 사용할 Profiles 를 지정해도 됩니다.

하지만 앞서 살펴본 두가지 기능은 Profiles 를 지정하는 것 외에도 다양한 값들을 주입하는데 사용하므로 꼭 알아야합니다 ✅

예를 들어 외부에 들어나면 안되는 값들(Secret Key, DB 관련 사용자명 혹은 비밀번호)는 직접 소스코드에 하드코딩하게 되었을 때 이를 무심코 원격 저장소에 올리면 보안에 심각한 문제를 야기할 수 있습니다 🚨
물론, .gitignore 에 application 파일을 추가하여 깃의 관리 대상에서 완전히 누락시키는 방안을 생각해볼 수 있지만 CI/CD 과정에서 지속적인 수정이 필요하기에 개발 프로세스 과정에서 굉장한 부담이 될 수 있습니다.

또한 application 파일에서 외부에 숨겨야하는 비밀 정보는 극히 일부분이기 때문에 특정 비밀 정보 때문에 application 파일 전체를 제외하는 것은 옳지 않습니다.

하지만 VM 옵션과 운영체제 내 시스템 환경변수 를 활용한다면 하드코딩을 하지 않기에 이러한 문제점을 깔끔하게 해소할 수 있습니다 👍


참고
1. [spring-boot] 2.4 부터 변경된 구성파일 처리방식 살펴보기
2. Spring Environment 스프링 애플리케이션의 환경에 접근하여 설정 값을 얻어오는 방법(feat. ApplicationContext의 다른 기능, profiles, @Profile)
3. Spring - 프로파일, 프로퍼티
4. Spring Boot - Profile에 따른 properties(yml) 파일 설정하기
5. Springboot Profile 설정방법 및 가져오기
6. Environment / Property / 외부 설정을 다루는 방법
7. Spring Profile: yml 파일 하나로 프로퍼티 관리하기

profile
비즈니스가치를추구하는개발자

0개의 댓글