- Spring 프로젝트에서의 환경변수는 다양한 방법으로 설정이 가능하다.
- 거기에 Spring을 도커로 이미지화하고, 배포하는 과정에서도 환경변수를 처리하는 방식이 나눠지기도 한다.
- 갈수록 많아지는 환경변수를 간편하고 안전하게 처리하여 배포할 수 있도록 복잡한 환경변수 설정을 이 포스트로 정리하고자 한다.
기존 환경변수

- github action을 사용한 배포 아키텍처이다.
- Spring 프로젝트를 도커로 빌드하여 ubuntu에서 해당 도커파일을 실행하도록 설계하였다.
- 프로젝트의
application.yaml
파일은 아래와 같은 방식으로 처리하였다.
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${PROD_DB_URL}
username: ${PROD_DB_USERNAME}
password: ${PROD_DB_PASSWORD}
- 여기서 보안 이슈로 유출되어선 안되는 변수값들은 repository에 push되어서는 안된다.
github secrets
를 사용해 변수를 안전하게 관리하였다.
github actions
의 동작을 설정하는 gradle.yaml
에서 ${{ secrets.PROD_DB_USERNAME }}
과 같이 repository에 업로드 하지 않고도 환경변수에 접근할 수 있도록 하였다.
- docker build를 통해 이미지화 된 Spring 프로젝트는
github actions
를 통해 서버에서 pull
받게 된다.
- 이 과정에서 빌드된 .jar파일은 환경변수를 주입하지 않은 파일로, 해당
.jar
파일을 환경변수와 함께 실행해야 환경변수가 주입된 채로 실행이 가능해진다.
docker run --name=${{ project_name }} -d -p 8080:8080 \
-e PROD_DB_URL=${{ secrets.PROD_DB_URL }} \
-e PROD_DB_USERNAME=${{ secrets.PROD_DB_USERNAME }} \
-e PROD_DB_PASSWORD=${{ secrets.PROD_DB_PASSWORD }} \
-e REDIS_USERNAME=${{ secrets.REDIS_USERNAME }} \
-e REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }} \
${{ secrets.DOCKER_USERNAME }}/${{ project_name }}:latest
- 하지만 이 방식에는 환경변수가 많아질 수록 작성해야하는 명령어가 증가하며,
- github secrets으로 매번 설정해줘야한다는 번거로움과, github secrets특성 상 어떤 값을 value로 설정했는지 확인하기 어렵다는 문제가 있다.
보완한 아키텍처
- 이를 해결해보고자
.env
라는 환경변수 파일을 도입하기로 결정했다.
.env
파일에 PROD_DB_URL, PROD_DB_USERNAME 와 같은 민감한 정보들을 key=value형태로 저장한다.
- 해당 파일을
github secrets
에 한 번에 설정한다.

- 이 과정에서
.env
파일을 서버로 복사하는 과정이 필요하다.
sudo touch ~/.env
echo "${{ secrets.ENV }}" > ~/.env
docker run --name=${{ project_name }} -d -p 8080:8080 \
--env-file ~/.env ${{ secrets.DOCKER_USERNAME }}/${{ project_name }}:latest
- 컨테이너 실행 전, 서버의
home
디렉토리에 .env
파일을 생성하고, secrets값을 주입해준다.
- 도커 실행 시,
--env-file
옵션으로 해당 .env
파일을 지정해주면 Spring 프로젝트는 .env
파일을 인식하여 민감한 정보를 주입받을 수 있게 된다.
장점
- 여러 개의 민감한 환경변수를 단일 변수로 설정하지 않고 하나의 파일로 관리가 가능해진다.
- 프로젝트 프로필별로 환경변수 파일을 설정하여 필요 시 유연하게 변수를 교체할 수 있다.
.env
파일은 local
-> github secret
-> server
의 흐름으로 이어지므로 github repository에 push되지 않아 공개되지 않는다.