← 전체 글로 돌아가기

Docker

Docker Compose의 env_file과 environment, 뭐가 다른가

두 방식 모두 컨테이너에 환경 변수를 주입하지만 우선순위와 보안 동작이 다르다. 혼용할 때 어떤 값이 이기는지 정리했다.

Docker Compose에서 환경 변수를 주입하는 방법은 크게 두 가지다. env_file로 파일을 통째로 읽히는 방법, environment로 compose.yml 안에서 직접 정의하는 방법. 언뜻 비슷해 보이지만 동작 방식이 다르다.

기본 차이

services:
  app:
    env_file:
      - .env.production
    environment:
      - DATABASE_URL=postgresql://localhost/prod
      - NODE_ENV=production

env_file은 지정한 파일을 읽어서 컨테이너에 주입한다. environment는 compose 파일 안에서 직접 값을 지정한다.

우선순위: environmentenv_file보다 높다. 둘 다 같은 키를 정의하면 environment의 값이 이긴다.

# 실제 주입된 값 확인
docker inspect container-name | jq '.[0].Config.Env'
# 또는
docker exec container-name env

env_file 사용 시 주의할 것

.env 파일은 KEY=VALUE 형식으로 작성한다. Bash 처럼 export를 붙이면 안 된다. 따옴표는 값의 일부로 처리된다.

# 올바른 형식
DATABASE_URL=postgresql://user:pass@host/db
SECRET_KEY=abcdef123

# 틀린 형식 (따옴표가 값에 포함됨)
SECRET_KEY="abcdef123"  # 실제 값: "abcdef123"

env_file에 경로를 상대 경로로 쓰면 docker compose 명령을 실행하는 디렉토리 기준으로 해석된다. 프로젝트 루트가 아닌 곳에서 실행하면 파일을 못 찾는다.

environment에서 값을 참조하는 방법

environment에서는 호스트 환경 변수를 그대로 주입할 수 있다.

environment:
  - DATABASE_URL  # 호스트의 DATABASE_URL 값을 그대로 주입
  - SECRET_KEY=${MY_HOST_SECRET}  # 호스트 변수 이름이 다를 때

값 없이 키만 쓰면 호스트에서 해당 이름의 환경 변수 값을 가져온다. 호스트에 없으면 빈 값이 된다.

어느 걸 써야 하나

개인적으로 이렇게 구분해서 쓴다.

상황권장 방식
로컬 개발, 여러 서비스가 공통 설정을 공유env_file
특정 서비스만 다른 값이 필요할 때environment 오버라이드
시크릿을 버전 관리에 올리지 않을 때env_file (파일을 .gitignore에 추가)
CI/CD에서 동적으로 값을 주입할 때environment + 파이프라인 시크릿

.env 파일을 .gitignore에 추가하는 건 기본이다. environment에 직접 값을 쓰면 compose.yml이 버전 관리에 들어가는 순간 시크릿이 노출된다.