실서버에서 사용하는 크리티컬한 YML 파일들을 프로젝트 외부에서 프라이빗하게 관리하면서 버전관리까지 깔끔하게 할 수 없을까? 이런 고민 끝에 찾아낸 나만의 방법을 정리해보았다.

 

우리 프로젝트는 다음과 같은 YML 파일들을 사용한다.

  • application.yml # 디폴트로 application-local 을 사용하게 함
  • application-local.yml # 개발환경의 테스트용 H2 DB에 대한 설정정보
  • application-real.yml # 실서버의 MariaDB에 대한 설정정보
  • application-oauth.yml # 소셜로그인에 필요한 critical한 정보

또한 우리 프로젝트는 깃허브의 public 리포지토리를 사용하고 있다.


그런데 application-real.yml, application-oauth.yml 은 public 리포지토리에 올라가서는 안되는 민감한 정보를 가지고있다.

따라서 이 파일들을 별도로 관리할 방법이 필요했다.

 

real 과 local 을 나누는 것은 어렵지 않았다. 디폴트로 application-local.yml 을 사용하게 하고, 실서버에서 실행할 때는 -Dspring.profiles.active=real 옵션을 주어 application-real 을 사용하게 했다.

java -Dspring.profiles.active=real -jar rush-0.0.1-SNAPSHOT.jar

 

여기까지는 어렵지 않았다. 하지만 문제는

application-real, application-oauth가 public 리포지토리에 올라가면 안된다는 점이었다.

그렇다고 실서버에서 hard 하게 관리하자니 불편한게 이만저만이 아니었다.

 

이 문제를 해결하기 위해서 원격 리포지토리를 다음과 같이 구성하기로 했다.

그것은 바로!!! 크리티컬한 정보들만 private 리포지토리에서 따로 관리하는 것이다.

 

주변의 조언을 들어보니 깃 서브모듈이라는게 있다고 하는데.... 할일은 많고 공부할것도 많은지라 그냥 private 리포지토리를 쓰기로 했다.

 

원격 리포지토리 구성 계획은 끝났으니 이제 로컬과 실서버의 구조를 고민할 차례!

로컬과 실서버에서 프로젝트를 실행하는 과정은 각각 다음과 같게 하고싶었다.

실서버 옵션으로 실행할 경우, 프로젝트는 /app/config 의 yml 정보들을 사용해야한다.

 

application-real 과 application-local 을 분리하는것은 쉬웠다.

그러나 문제는 application-oauth 였다.

 

실서버에서는 /app/config/application-oauth.yml 을 사용하게 하고싶고,

로컬에서는 프로젝트 내의 resources 밑에 application-oauth.yml을 위치시켜서 쓰고싶었다.

로컬용 application-oauth.yml 파일과 실서버용 application-oauth.yml 파일 내용이 살짝 달랐기 때문이다.

 

그러나 아무리 해도 이렇게 구현되지가 않았다.

심지어 또다른 문제도 터졌다. 클라우드서버의 무료기간이 끝나서 집에 라즈베리파이를 설치하고 여기로 서버를 옮겼는데, 원래 잘 동작하던 -Dspring.profiles.active=real 옵션이 라즈베리파이에서 제대로 동작하지 않는 것이었다.

 

마일스톤 마지막날까지 계속 삽질을 하다가 결국 포기하고 잠자리에 누웠다.

누워서 계속 생각을 해봤는데 갑자기 이런생각이 들었다.

"main 메서드의 args 를 사용하면 되지 않을까??"

 

기존의 main 메서드는 다음과 같았다.

@EnableConfigurationProperties(AppProperties.class)
@SpringBootApplication
public class RushApplication {

    private static final String APPLICATION_LOCATIONS = "spring.config.location="
        + "classpath:application.yml,"
        + "classpath:application-local.yml,"
        + "optional:/app/config/application-real.yml";

    public static void main(String[] args) {
        new SpringApplicationBuilder(RushApplication.class)
            .properties(APPLICATION_LOCATIONS)
            .run(args);
    }
}

 

그런데 이것을 다음과 같이 바꾸는 것이다.

@EnableConfigurationProperties(AppProperties.class)
@SpringBootApplication
public class RushApplication {

    private static final String REAL_SERVER_OPTION = "REAL";
    private static final String REAL_SERVER_PROPERTY_LOCATION = "/app/config/";
    private static final String LOCAL_SERVER_PROPERTY_LOCATION = "classpath:";

    public static void main(String[] args) {
        final String PROPERTY_LOCATIONS = makeSApplicationLocations(args);

        new SpringApplicationBuilder(RushApplication.class)
            .properties(PROPERTY_LOCATIONS)
            .run(args);
    }

    private static String makeSApplicationLocations(String[] mainMethodArguments) {
        if (mainMethodArguments.length > 0
                && mainMethodArguments[0].equalsIgnoreCase(REAL_SERVER_OPTION)) {
            return "spring.config.location="
                + REAL_SERVER_PROPERTY_LOCATION + "application.yml,"
                + REAL_SERVER_PROPERTY_LOCATION + "application-oauth.yml,"
                + REAL_SERVER_PROPERTY_LOCATION + "application-real.yml";
        }
        return "spring.config.location="
            + LOCAL_SERVER_PROPERTY_LOCATION + "application.yml,"
            + LOCAL_SERVER_PROPERTY_LOCATION + "application-oauth.yml,"
            + LOCAL_SERVER_PROPERTY_LOCATION + "application-local.yml";
    }
}

 

이렇게하면 굳이 스프링의 기능을 이용해서 환경분리를 구현할 필요가 없어진다.

또한 기존의 `optional:/app/config/application-real.yml` 이 조잡한 설정도 없앨 수 있었다.

게다가 실서버에서 프로그램을 실행하는 명령도 더 간단해졌다.

 // 기존의 실서버 옵션 실행방법
 // java -Dspring.profiles.active=real -jar rush-0.0.1-SNAPSHOT.jar
 
 // 실서버 옵션 실행방법 바뀐 버전
 java -jar rush-0.0.1-SNAPSHOT.jar REAL

 

이렇게 해서 모든 실서버 yml 파일 뿐만아니라 쉘스크립트까지!! private 리포지토리에서 관리할 수 있게 되었다!

 

+ Recent posts