Docker + Spring Boot 환경변수와 프로필, 제대로 이해하기

J_Eddy·어제
0
post-thumbnail

Docker + Spring Boot 환경변수와 프로필, 제대로 이해하기

Squad 프로젝트를 진행하면서 처음으로 Docker와 RDS를 사용하게 되었습니다. 개발 환경에서는 문제없이 동작하던 애플리케이션을 운영 환경에 배포하려고 하니, 환경변수, 프로필, 설정 파일의 관계가 명확하지 않아 어려움을 겪었습니다.

이 글에서는 제가 겪었던 시행착오를 바탕으로, Docker Compose와 Spring Boot가 어떻게 연결되는지 정리해보겠습니다.

.env.prod → docker-compose → container env → Spring Boot → application-prod.yml

기존 방식: 설정 파일을 직접 수정해서 배포

이전에 진행했던 프로젝트에서는 배포 방식이 단순했습니다.

개발할 때:

# application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=admin
spring.datasource.password=1234

배포할 때:
1. application.properties 운영 서버 cfg에 따로 존재
2. .env로 관리하지 않고 properties에 모든 내용이 작성

이 방식의 문제점:

  • 실수로 운영 DB 정보가 Git에 커밋된다면 보안성 위험

새로운 방식: Docker + 환경변수 + 프로필

그런데 Docker를 사용하면서 갑자기:

  • .env.prod 파일
  • docker-compose.yml
  • application-prod.yml
  • 환경변수 ${VARIABLE_NAME}

이런 개념들이 한꺼번에 등장했습니다.

"왜 이렇게 복잡해진 거지?"

처음에는 이런 생각이 들었습니다. 기존에는 파일 하나만 수정하면 됐는데, 이제는 여러 파일과 환경변수를 관리해야 한다니 오히려 더 복잡해 보였습니다.

하지만 이해하고 나니, 이 방식이 훨씬 더 안전하고 편리하다는 것을 알게 되었습니다:

  1. 설정과 코드의 분리: 민감한 정보(DB 비밀번호, API 키)를 코드에서 완전히 분리
  2. 환경별 자동 전환: SPRING_PROFILES_ACTIVE만 바꾸면 설정이 자동으로 전환
  3. Git 안전성: .env.prod.gitignore에 추가하면 절대 커밋되지 않음
  4. 재사용성: 같은 Docker 이미지로 여러 환경에 배포 가능

문제: Docker와 Spring Boot, 누가 무엇을 담당하는가?

하지만 이 새로운 방식을 처음 접했을 때 가장 혼란스러웠던 부분은 "어디서 어떤 값을 읽어오는가"였습니다. .env.prod 파일을 만들고, docker-compose.ymlenv_file을 지정했지만, 이 값들이 Spring Boot에서 어떻게 사용되는지 명확하지 않았습니다.

Docker Compose의 역할

Docker Compose에서 env_file을 지정하면:


services:
  app:
    ...
    env_file:
      - .env.prod
    environment:
      SPRING_PROFILES_ACTIVE: prod

Docker는 해당 파일의 모든 KEY=VALUE 쌍을 읽어 컨테이너의 환경변수로 등록합니다.

예를 들어 .env.prod 파일이 다음과 같다면:

SPRING_DATASOURCE_URL=jdbc:postgresql://my-rds:5432/squad
SPRING_DATASOURCE_USERNAME=admin
SPRING_DATASOURCE_PASSWORD=123123
APPLE_BUNDLE_ID=xxx.xxxx.xxxxxx
JWT_SECRET=xxxx

Docker는 파일 내용을 읽어 컨테이너 환경변수로 설정합니다. 이때 중요한 점은 Docker는 이 값들이 어디서 사용될지 알지 못한다는 것입니다. 단순히 환경변수를 설정하는 역할만 수행합니다.

핵심: Docker는 환경변수 전달자

Docker Compose의 역할은 명확합니다. .env.prod 파일의 내용을 읽어 컨테이너 환경변수로 설정하는 것이 전부입니다. Spring Boot가 어떤 값을 필요로 하는지, 어떻게 사용할지는 관여하지 않습니다.

Spring Boot의 역할

그렇다면 어떤 환경변수가 필요한지는 누가 결정할까요? 답은 Spring Boot입니다.

Spring Boot는 설정 파일에서 ${VARIABLE_NAME} 형태의 플레이스홀더를 발견하면, 런타임에 환경변수에서 해당 값을 읽어옵니다.

spring:
  datasource:
    url: ${SPRING_DATASOURCE_URL}
    username: ${SPRING_DATASOURCE_USERNAME}
    password: ${SPRING_DATASOURCE_PASSWORD}

apple:
  bundle-id: ${APPLE_BUNDLE_ID}

위 설정을 보고 Spring Boot는 SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME 등의 환경변수가 필요하다는 것을 인지하고, 컨테이너 환경변수에서 값을 가져옵니다.

역할의 분리

  • Docker: 환경변수를 컨테이너에 전달
  • Spring Boot: 필요한 환경변수만 선택적으로 사용

Profile(프로필)이란?

여기서 잠깐, "프로필"이라는 용어가 생소할 수 있습니다. 프로필은 쉽게 말해 "실행 환경"을 의미합니다.

같은 애플리케이션 코드를 여러 환경에서 실행할 때, 환경마다 설정이 달라야 합니다. 예를 들어:

  • 로컬 개발 환경(local): 내 컴퓨터의 localhost DB 사용
  • 운영 환경(prod): AWS RDS 사용, 실제 Apple 인증서와 JWT Secret 사용

코드는 동일하지만, DB 주소나 API 키 같은 설정만 환경에 따라 달라지는 것이죠.

프로필의 실제 사용 예시

# application-local.yml (로컬 개발용)
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/squad
    username: admin
    password: 1234

apple:
  bundle-id: com.myapp.squad.dev

# application-prod.yml (운영 서버용)
spring:
  datasource:
    url: ${SPRING_DATASOURCE_URL}  # .env.prod에서 가져옴
    username: ${SPRING_DATASOURCE_USERNAME}
    password: ${SPRING_DATASOURCE_PASSWORD}

apple:
  bundle-id: ${APPLE_BUNDLE_ID}

실행할 때 어떤 프로필을 사용할지 지정하면:

  • SPRING_PROFILES_ACTIVE=localapplication-local.yml 사용
  • SPRING_PROFILES_ACTIVE=prodapplication-prod.yml 사용

프로필을 사용하는 이유

  1. 코드 수정 없이 환경만 바꿔서 실행 가능
  2. 민감 정보(DB 비밀번호 등)를 환경마다 다르게 관리
  3. 로컬에서 개발하다가 배포할 때 설정만 전환하면 됨

프로필 덕분에 하나의 코드베이스로 여러 환경을 유연하게 관리할 수 있습니다.

기존 방식과의 비교

기존 방식 (properties 직접 수정):

개발 완료 → properties 파일 수정 → 빌드 → 배포
         ↑ 내용이 properties에 그대로 작성

새로운 방식 (프로필 + 환경변수):

개발 완료 → 빌드 (코드는 그대로!) → 배포 시 SPRING_PROFILES_ACTIVE=prod만 지정
                                        ↑ .env.prod는 서버에만 존재, Git에는 없음

코드와 설정이 완전히 분리되어, 같은 JAR 파일로 여러 환경에 배포할 수 있게 된 것입니다.

Profile 기반 설정 파일 로딩

Spring Boot가 application-prod.yml 파일을 자동으로 읽는 원리는 간단합니다.

environment:
  SPRING_PROFILES_ACTIVE: prod

위와 같이 SPRING_PROFILES_ACTIVE 환경변수를 설정하면, Spring Boot는 다음 순서로 설정 파일을 로딩합니다:

  1. application.yml (기본 설정)
  2. application-prod.yml (프로필별 설정)
  3. 중복되는 설정은 프로필 파일이 우선

이는 Spring Boot의 Profile 기반 설정 메커니즘에 따른 것으로, application-{profile}.yml 네이밍 규칙을 따르면 자동으로 로딩됩니다.

전체 흐름

전체 과정을 정리하면 다음과 같습니다:

[1] .env.prod
    실제 환경변수 값 정의 (Git에는 커밋하지 않음!)
    ↓
[2] docker-compose.prod.yml
    env_file로 .env.prod 로딩
    SPRING_PROFILES_ACTIVE=prod 설정
    ↓
[3] Docker Container
    모든 환경변수가 컨테이너에 등록됨
    ↓
[4] Spring Boot
    SPRING_PROFILES_ACTIVE=prod 확인
    → application-prod.yml 자동 로딩
    → ${VARIABLE_NAME} 형태의 값을 환경변수에서 조회

로컬 개발 환경에서의 주의사항

IntelliJ에서 애플리케이션을 실행할 때는 Docker가 개입하지 않으므로, 환경변수를 별도로 설정해야 합니다.

기본 실행

  • application.yml만 로딩됩니다.
  • 프로필별 설정 파일은 사용되지 않습니다.

Profile을 지정한 실행

Run Configuration에서 SPRING_PROFILES_ACTIVE=prod를 설정하면:

  • application-prod.yml이 로딩됩니다.
  • 필요한 환경변수를 Run Configuration의 Environment Variables에 직접 입력해야 합니다.
SPRING_DATASOURCE_URL=...
SPRING_DATASOURCE_USERNAME=...
APPLE_BUNDLE_ID=...
JWT_SECRET=...

Docker처럼 .env 파일이 자동으로 로딩되지 않으므로, 로컬에서 운영 환경을 재현하려면 환경변수를 수동으로 관리해야 합니다.

정리

구성 요소역할
.env.prod환경변수 값을 저장하는 파일 (Git에 커밋 안 함)
docker-compose.yml.env.prod를 읽어 컨테이너 환경변수로 설정
컨테이너 환경변수Spring Boot가 런타임에 참조하는 실제 값
SPRING_PROFILES_ACTIVE로딩할 프로필 설정 파일 결정
application-prod.yml프로필별 추가 설정 정의

마치며

Docker와 Spring Boot의 역할을 명확히 구분하면, 환경변수와 설정 파일의 관계를 쉽게 이해할 수 있습니다.

  • Docker: 환경변수 전달
  • Spring Boot: 프로필에 따라 설정 파일을 로딩하고, 필요한 환경변수 참조

처음에는 기존의 단순한 방식보다 복잡해 보였지만, 이 구조 덕분에:

  • 민감한 정보를 안전하게 관리할 수 있고
  • 같은 코드로 여러 환경에 배포할 수 있으며
  • 실수로 운영 정보가 Git에 노출될 위험이 사라졌습니다.

Squad(스쿼드) 프로젝트를 배포하면서 겪었던 시행착오가 좋은 학습 경험이 되었습니다. 다음에는 처음부터 이런 구조로 프로젝트를 설계할 수 있을 것 같습니다.

profile
논리적으로 사고하고 해결하는 것을 좋아하는 개발자입니다.

0개의 댓글