# [Docker Compose 개념] 환경 변수와 시작 순서 설계
- 환경 변수와 시작 순서 설계 ← 현재 문서
Compose 파일에서 가장 많이 헷갈리는 부분은 환경 변수다. .env가 있고, env_file도 있고, environment도 있다. 셋 다 비슷해 보이지만 역할이 다르다.
예시 프로젝트에서는 이 구분이 특히 중요하다. DB 비밀번호, JWT secret, AWS S3 key, Admin 계정 정보가 모두 .env에 들어 있다. 이 값을 아무 컨테이너에나 통째로 넣으면 "실행은 되지만 관리하기 불편한 상태"가 된다.
.env는 Compose 파일을 채우는 값 저장소다
Compose는 기본적으로 프로젝트 디렉터리의 .env 파일을 읽어 ${...} 자리에 값을 넣을 수 있다.
environment:
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE}
SPRING_DATASOURCE_URL: ${SPRING_DATASOURCE_URL}
이때 .env는 Compose 파일을 해석하는 시점에 쓰인다. 이것을 보간이라고 부른다. .env에 값이 있다고 해서 모든 값이 자동으로 컨테이너 안에 들어가는 것은 아니다. 컨테이너 안으로 넣으려면 environment나 env_file을 통해 전달해야 한다.
정리하면 다음과 같다.
| 위치 | 역할 | 컨테이너 안에 자동 주입되는가 |
|---|---|---|
.env | Compose 파일의 ${...} 값을 채움 | 아니다 |
environment | 해당 서비스 컨테이너에 환경 변수 주입 | 그렇다 |
env_file | 파일의 변수를 해당 서비스 컨테이너에 통째로 주입 | 그렇다 |
env_file은 편하지만 넓다
현재 Compose 파일은 app과 db에 모두 .env를 연결한다.
app:
env_file: .env
db:
env_file:
- .env
이렇게 하면 .env의 모든 값이 두 컨테이너에 들어간다. 그 결과 DB 컨테이너에도 AWS key, JWT secret, Admin 계정 정보 같은 값이 들어간다. PostgreSQL 컨테이너는 이 값들을 사용할 필요가 없다.
실행에는 큰 문제가 없어 보일 수 있지만, 좋은 경계는 아니다. 컨테이너마다 필요한 환경 변수만 좁게 전달해야 한다.
db:
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
이렇게 하면 DB 컨테이너에는 PostgreSQL 초기화에 필요한 값만 들어간다.
Spring Boot 설정은 환경 변수로 덮어쓸 수 있다
현재 application-prod.yml에는 DB URL이 다음처럼 들어 있다.
spring:
datasource:
url: jdbc:postgresql://localhost:5432/discodeit_prod
이 값은 컨테이너 환경에서는 맞지 않다. 앱 컨테이너의 localhost는 DB 컨테이너가 아니기 때문이다. Compose에서는 환경 변수로 이 값을 덮어쓴다.
app:
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/${POSTGRES_DB}
SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER}
SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD}
Spring Boot는 SPRING_DATASOURCE_URL을 spring.datasource.url 설정으로 해석할 수 있다. 그래서 이미지 안의 설정 파일을 다시 빌드하지 않고도 실행 환경에 맞는 DB 주소를 주입할 수 있다.
이 방식은 컨테이너에서 특히 중요하다. 이미지는 최대한 환경 독립적으로 만들고, 실제 주소와 비밀번호는 실행 시점에 주입하는 편이 낫다.
depends_on은 시작 순서이고 healthcheck는 준비 상태다
현재 Compose 파일에는 좋은 설정이 하나 있다.
app:
depends_on:
db:
condition: service_healthy
db:
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
depends_on만 쓰면 DB 컨테이너를 먼저 시작한 뒤 앱 컨테이너를 시작한다. 하지만 PostgreSQL 프로세스가 실제로 연결을 받을 준비가 되었는지는 보장하지 않는다.
condition: service_healthy를 쓰면 DB의 healthcheck가 통과한 뒤 앱 컨테이너가 생성된다. Spring Boot가 시작하자마자 DB에 연결하려다 실패하는 상황을 줄일 수 있다.
depends_on은 시작 시점의 순서를 제어한다. 실행 중 DB가 죽었다가 살아나는 상황까지 앱의 연결 복구를 완벽하게 보장하지는 않는다. 애플리케이션의 커넥션 풀, 재시도 정책, 로그 확인도 함께 필요하다.
현재 프로젝트에 맞는 환경 변수 분리 기준
예시 프로젝트의 환경 변수는 용도별로 나누면 이해하기 쉽다.
| 묶음 | 변수 예시 | 전달 대상 |
|---|---|---|
| PostgreSQL 초기화 | POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD | db |
| Spring DB 접속 | SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD | app |
| Spring 프로필과 JPA | SPRING_PROFILES_ACTIVE, SPRING_JPA_HIBERNATE_DDL_AUTO, SPRING_JPA_SHOW_SQL | app |
| AWS S3 | AWS_S3_ACCESS_KEY, AWS_S3_SECRET_KEY, AWS_S3_REGION, AWS_S3_BUCKET | app |
| 인증과 관리자 | JWT_SECRET, ADMIN_EMAIL, ADMIN_USERNAME, ADMIN_PASSWORD | app |
| JVM | JVM_OPTS | app |
이 표를 기준으로 Compose 파일을 보면 db에 들어갈 값과 app에 들어갈 값이 자연스럽게 갈린다.
참고한 공식 문서
- Environment variables in Docker Compose
- Variable interpolation
- Control startup and shutdown order in Compose