읽는데 약 2분
서브모듈을 활용한 환경 변수 관리
안녕하세요? 이번 시간에는 서브모듈을 활용해 민감한 정보가 있는 환경 변수를 관리하는 방법에 대해 알아보겠습니다.
프로젝트를 개발하다보면 dev
환경에서 사용하는 변수들과 prod
환경에서 사용하는 변수들이 다릅니다. 예를 들어 dev
환경에서 데이터베이스 url
은 jdbc:mysql://localhost:3306/test?serverTimezone=UTC
이지만 prod
환경에서는 rds
로 데이터베이스를 생성했다면 jdbc:mysql://test.abcd.rds.amazonaws.com:3306/test
와 같은 형식일 것입니다. 따라서 환경 변수를 분리할 뿐만 아니라 프로덕션에 적용되는 변수들은 노출되지 않도록 주의해야합니다.
submodule 추가
Git에서 제공하는 기능 중 하나인 서브모듈을 통해 변수를 관리해보겠습니다. 서브모듈은 하나의 Git 저장소 안에 다른 Git 저장소를 포함시키는 방법을 말합니다. 상위 Repository인 backend-submodule-test
에서 하위 Repository인 submodule-test
을 포함하도록 하겠습니다.
우선 상위 레포지토리에서 아래 명령어를 입력하면 .gitmodules
파일이 생성됩니다.
git submodule add https://github.com/devbelly/submodule-test.git
기본적으로 서브모듈은 프로젝트 저장소의 이름으로 디렉토리를 만듭니다. 다만.gitmodules
파일에 있는 URL은 조건에 맞는 사람이라면 누구든지 clone하고 fetch할 수 있어야합니다. 실제 프로젝트에서 submodule-test
를 private으로 설정했다면 Collaborators에 같이 개발하는 동료를 추가해야 합니다.
이후 푸시를 하면 서브모듈의 특정 커밋을 가리키는 것을 확인할 수 있습니다.
submodule을 포함하는 프로젝트 Clone하기
만약 서브모듈을 위와 같이 추가한 상태에서 처음 동료가 서브모듈을 포함한 프로젝트를 클론 받는 상황을 가정해보겠습니다.
git clone
을 하더라도 서브모듈 디렉토리는 비어있습니다. 서브모듈과 관련된 두 명령을 실행해야 완전히 클론과정이 끝나게 됩니다. 처음에는 git submodule init
으로 .gitmodules
파일에 정의된 서브모듈 설정을 현재 Git 프로젝트에 추가해야합니다.
.git/config
에 서브모듈 관련 설정이 추가된 것을 확인할 수 있습니다.
이후 git submodule update
명령으로 서브모듈의 리모트 저장소에서 데이터를 가져오고 서브모듈을 포함한 프로젝트의 현재 스냅샷에서 Checkout 해야 할 커밋 정보를 가져와서 서브모듈 프로젝트에 대한 Checkout을 합니다.
주의할 점
git submodule update
는 기본적으로 특정 커밋으로 Checkout을 하므로 서브모듈 로컬 저장소는 Detached HEAD 상태가 됩니다. 이 상태에서는 수정한 내용에 대해 추적이 제대로 이뤄지지 않으므로 작업 브랜치로 Checkout을 해줘야합니다.
따라서 git submodule update --remote
명령어를 수행했다면 서브모듈에서 git checkout main
을 해야합니다.
이 과정이 번거롭다면 git submodule update --remote --merge
옵션을 사용하면 됩니다.
설정 파일 옮기기
서브모듈을 업데이트 했다면 가져온 application-test.yaml
파일을 적절한 위치로 옮겨줘야합니다. build.gradle.kts
에 아래 내용을 추가하면 파일이 옮겨집니다. 파일을 옮긴 뒤에 적절하게 gitignore
설정으로 프로덕션과 관련된 파일들을 제외하면 안전하게 환경 변수를 사용할 수 있습니다.
// build.gradle.tks
tasks {
val copySecret by register<Copy>("copySecret") {
from("./submodule-test") // 서브모듈 디렉토리 경로
include("application*.yaml") // 복사할 파일들
into("./src/main/resources") // 복사 위치
}
named("processResources") {
dependsOn(copySecret)
}
}