IT·테크/인프라

Docker Compose에서 .env 파일 하나만 바꿔 끼우기

레루루 2026. 7. 28. 21:50
반응형

이 글은 2022년 10월 기준 기록입니다.

 

앞서 환경마다 docker-compose.dev.yml, docker-compose.prod.yml을 따로 두는 방식으로 설정을 분리했습니다. 그런데 이 방식은 환경이 늘어날 때마다 거의 같은 내용의 파일이 한 벌씩 늘어납니다. 여러 개의 docker-compose.yml 파일을 사용하지 않고, 하나의 파일에 설정만 다르게 적용하는 방법은 없을까요.

Compose는 이미 .env 파일을 찾고 있다

docker compose 명령은 기본적으로 ".env"라는 이름의 파일을 찾아서 읽습니다. 따로 설정하지 않아도 동작하는 규칙이므로, 별도의 이름을 쓰고 싶을 때만 --env-file 옵션으로 지정하면 됩니다.

Compose 파일에서 값을 비우고 ${}로 남긴다

값을 직접 적는 대신 ${} 표기법으로 자리만 남겨 둡니다.

name: spring-db-test
services:
  postgres-db:
    image: postgres-iochord
    expose: 
      - "5432"
    volumes: 
      - postgres_data:/var/lib/postgresql/data
      - ${INIT_LOCAL_CONTEXT}/${INIT_LOCAL_FOLDER_NAME}:/docker-entrypoint-initdb.d
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}

  spring-crud:
    image: test-crud-app:latest
    depends_on: 
      - postgres-db
    expose:
      - ${INTERNAL_PORT}
    environment:
      - SPRING_DATASOURCE_URL=${SPRING_DATASOURCE_URL}
      - SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME}
      - SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
      - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE}
      - JAR_FILE=${JAR_FILE}

  load-balancer:
    image: nginx
    ports:
      - ${EXTERNAL_PORT}:${LOAD_BALANCER_APP_PORT}
    expose:
      - ${LOAD_BALANCER_DB_PORT}
    depends_on:
      - spring-crud
      - postgres-db
    volumes:
      - ./nginx-docker/load-balancer.conf:/etc/nginx/nginx.conf:ro

volumes:
  postgres_data:
    driver: local
    name : postgres_test

 

이제 이 파일에는 환경에 따라 달라질 값이 하나도 남아 있지 않습니다. 포트 번호도, DB 이름도, 초기화 스크립트 경로도 전부 변수입니다.

환경의 차이는 .env 파일의 차이로만 남는다

첫 번째 환경(test.env)입니다.

# postgreSQL
POSTGRES_USER=springtest  # postgres 슈퍼유저 생성
POSTGRES_PASSWORD=springtest # postgres 슈퍼유저 비밀번호
POSTGRES_DB=postgres # postgres default db

INIT_LOCAL_CONTEXT=.
INIT_LOCAL_FOLDER_NAME=init_db

# spring boot app
SPRING_DATASOURCE_URL=jdbc:postgresql://load-balancer:5432/postgres
SPRING_DATASOURCE_USERNAME=springtest
SPRING_DATASOURCE_PASSWORD=springtest

JAR_FILE=app.jar

HOST_PORT=8080
INTERNAL_PORT=8080 # 내부 스프링 앱이 compose 내부에 노출할 포트 번호

# nginx Load Balancer
EXTERNAL_PORT=80 # 호스트에 노출될 포트 번호
LOAD_BALANCER_APP_PORT=80 # 내부 로드밸런서가 리슨할 웹 포트 번호
LOAD_BALANCER_DB_PORT=5432 # 내부 로드밸런서가 리슨할 디비 포트 번호

 

두 번째 환경(dev.env)입니다. DB 이름이 postgres1로 바뀌었고, SPRING_PROFILES_ACTIVE=dev가 추가되었으며, 호스트에 노출되는 포트가 81로 달라졌습니다.

# postgreSQL
POSTGRES_USER=springtest  # postgres 슈퍼유저 생성
POSTGRES_PASSWORD=springtest # postgres 슈퍼유저 비밀번호
POSTGRES_DB=postgres1 # postgres default db

INIT_LOCAL_CONTEXT=.
INIT_LOCAL_FOLDER_NAME=init_db

# spring boot app
SPRING_DATASOURCE_URL=jdbc:postgresql://load-balancer:5432/postgres1
SPRING_DATASOURCE_USERNAME=springtest
SPRING_DATASOURCE_PASSWORD=springtest

SPRING_PROFILES_ACTIVE=dev # application-dev.properties 선택

JAR_FILE=app.jar

HOST_PORT=8080
INTERNAL_PORT=8080 # 내부 스프링 앱이 compose 내부에 노출할 포트 번호

# nginx Load Balancer
EXTERNAL_PORT=81 # 호스트에 노출될 포트 번호
LOAD_BALANCER_APP_PORT=80 # 내부 로드밸런서가 리슨할 웹 포트 번호
LOAD_BALANCER_DB_PORT=5432 # 내부 로드밸런서가 리슨할 디비 포트 번호

 

".env" 파일에서 설정된 환경 변수 값을 ${} 표기법으로 docker-compose.yml 파일에서 읽어 오는 구조입니다.

config 명령이 치환된 최종 결과를 보여 준다

변수 치환이 제대로 되었는지는 컨테이너를 띄워 보기 전에 config로 확인할 수 있습니다. 먼저 test.env입니다.

$ docker compose --env-file test.env -f docker-compose.yml config

time="2022-10-07T15:11:45+09:00" level=warning msg="The \"SPRING_PROFILES_ACTIVE\" variable is not set. Defaulting to a blank string."
name: spring-db-test
services:
  load-balancer:
    depends_on:
      postgres-db:
        condition: service_started
      spring-crud:
        condition: service_started
    expose:
    - "5432"
    image: nginx
    networks:
      default: null
    ports:
    - mode: ingress
      target: 80
      published: "80"
      protocol: tcp
    volumes:
    - type: bind
      source: C:\Users\사용자명\workspace\test\build\libs\docker_compose\nginx-docker\load-balancer.conf
      target: /etc/nginx/nginx.conf
      read_only: true
      bind:
        create_host_path: true
  postgres-db:
    environment:
      POSTGRES_DB: postgres
      POSTGRES_PASSWORD: springtest
      POSTGRES_USER: springtest
    expose:
    - "5432"
    image: postgres-iochord
    networks:
      default: null
    volumes:
    - type: volume
      source: postgres_data
      target: /var/lib/postgresql/data
      volume: {}
    - type: bind
      source: C:\Users\사용자명\workspace\test\build\libs\docker_compose\init_db
      target: /docker-entrypoint-initdb.d
      bind:
        create_host_path: true
  spring-crud:
    depends_on:
      postgres-db:
        condition: service_started
    environment:
      JAR_FILE: app.jar
      SPRING_DATASOURCE_PASSWORD: springtest
      SPRING_DATASOURCE_URL: jdbc:postgresql://load-balancer:5432/postgres
      SPRING_DATASOURCE_USERNAME: springtest
      SPRING_PROFILES_ACTIVE: ""
    expose:
    - "8080"
    image: test-crud-app:latest
    networks:
      default: null
networks:
  default:
    name: spring-db-test_default
volumes:
  postgres_data:
    name: postgres_test
    driver: local

 

test.env에는 SPRING_PROFILES_ACTIVE가 없으므로 경고가 뜨고, 값은 빈 문자열로 치환되었습니다. 정의하지 않은 변수가 있으면 조용히 넘어가지 않고 이렇게 알려 줍니다.

 

같은 Compose 파일에 dev.env를 물리면 결과가 달라집니다.

$ docker compose --env-file dev.env -f docker-compose.yml config

name: spring-db-test
services:
  load-balancer:
    depends_on:
      postgres-db:
        condition: service_started
      spring-crud:
        condition: service_started
    expose:
    - "5432"
    image: nginx
    networks:
      default: null
    ports:
    - mode: ingress
      target: 80
      # =====================================================================================
      published: "81"
      # =====================================================================================
      protocol: tcp
    volumes:
    - type: bind
      source: C:\Users\사용자명\workspace\test\build\libs\docker_compose\nginx-docker\load-balancer.conf
      target: /etc/nginx/nginx.conf
      read_only: true
      bind:
        create_host_path: true
  postgres-db:
    environment:
      POSTGRES_DB: postgres1
      POSTGRES_PASSWORD: springtest
      POSTGRES_USER: springtest
    expose:
    - "5432"
    image: postgres-iochord
    networks:
      default: null
    volumes:
    - type: volume
      source: postgres_data
      target: /var/lib/postgresql/data
      volume: {}
    - type: bind
      source: C:\Users\사용자명\workspace\test\build\libs\docker_compose\init_db
      target: /docker-entrypoint-initdb.d
      bind:
        create_host_path: true
  spring-crud:
    depends_on:
      postgres-db:
        condition: service_started
    environment:
      JAR_FILE: app.jar
      SPRING_DATASOURCE_PASSWORD: springtest
      SPRING_DATASOURCE_URL: jdbc:postgresql://load-balancer:5432/postgres1
      SPRING_DATASOURCE_USERNAME: springtest
      # =====================================================================================
      SPRING_PROFILES_ACTIVE: dev
      # =====================================================================================
    expose:
    - "8080"
    image: test-crud-app:latest
    networks:
      default: null
networks:
  default:
    name: spring-db-test_default
volumes:
  postgres_data:
    name: postgres_test
    driver: local

 

노출 포트는 81이 되었고 SPRING_PROFILES_ACTIVEdev로 채워졌습니다. Compose 파일은 한 글자도 건드리지 않았습니다.


반응형