이 글은 2022년 10월 기준 기록입니다.
Docker 이미지는 한 번 만들어지면 변하지 않는 상태를 유지합니다. 그렇다면 동일한 이미지로 여러 설정이 적용된 다른 컨테이너들을 만들려면 어떻게 해야 할까요.
설정이 바뀔 때마다 이미지를 굽는 것은 비합리적이다
문제는 이미지의 불변성 자체가 아니라, 그 불변성 때문에 생기는 반복입니다. 동일한 프로그램을 다른 설정으로 실행시키기 위해 매번 이미지를 만드는 것은 비합리적입니다. 개발용과 운영용의 차이가 DB 주소 한 줄뿐이어도 이미지를 두 벌 관리해야 합니다.
그래서 질문은 이렇게 좁혀집니다. 이미지 내부의 설정을 컨테이너가 동작할 때 지정해 줄 수는 없을까?
환경 변수가 이미지와 설정 사이의 통로다
환경 변수는 운영 체제에서 관리되는 변수입니다. 그리고 각 컨테이너는 리눅스 또는 윈도우 기반으로 동작하고 있으므로, 각 컨테이너가 생성될 때 컨테이너의 환경 변수 값을 전달할 수 있습니다.
따라서 방향은 정해집니다. 이미지를 생성할 때는 값을 박아 넣는 대신 미리 생각해 둔 환경 변수 이름으로 값을 불러오도록 설정해 두고, 실제 값은 컨테이너를 띄우는 시점에 넣습니다.
Dockerfile은 jar를 직접 실행하는 대신 스크립트를 실행한다
이전 Dockerfile은 jar 파일을 곧바로 실행하도록 작성되어 있었습니다.
# Before
FROM openjdk:11
ARG JAR_FILE=test-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
여기서는 실행 명령이 이미지 안에 고정되어 있어 실행 시점에 인자를 끼워 넣을 자리가 없습니다. 그래서 셸 스크립트 파일을 먼저 실행하도록 바꿉니다.
# After
FROM openjdk:11
ENV JAR_FILE=test-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
COPY runner.sh runner.sh
ENTRYPOINT ["sh", "./runner.sh"]
runner.sh는 다음과 같습니다.
#!/bin/bash
echo Run the application...
echo "java -jar $JAR_FILE $DB_CONNECTION_ENV" >> ./runner_run.sh
chmod a+x ./runner_run.sh
cat ./runner_run.sh
sh runner_run.sh
하는 일은 JAR_FILE과 DB_CONNECTION_ENV라는 환경 변수들을 이용해 jar 파일을 실행하는 셸 스크립트 파일을 다시 생성(runner_run.sh)하고 실행하는 것입니다. 실행 명령이 이미지 빌드 시점이 아니라 컨테이너 기동 시점에 조립되므로, 같은 이미지에 다른 값을 넣으면 다른 명령이 만들어집니다.
env_file로 환경 변수를 별도 파일로 뺀다
Compose 파일에서 환경 변수를 직접 나열하던 방식은 이렇습니다.
# Before
name: spring-db-test
services:
postgres-db:
image: postgres:12
expose:
- "5432"
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=springtest
- POSTGRES_PASSWORD=springtest
spring-crud:
image: test_crud_app:latest
depends_on:
- postgres-db
ports:
- 8080:8080
volumes:
postgres_data:
driver: local
name : postgres_data
값을 파일로 분리하면 이렇게 됩니다.
# After
name: spring-db-test
services:
postgres-db:
image: postgres-iochord
expose:
- "5432"
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- ./common.env
spring-crud:
image: test-crud-app:latest
depends_on:
- postgres-db
ports:
- 8080:8080
env_file:
- ./common.env
volumes:
postgres_data:
driver: local
name : postgres_test
환경 변수는 environment 또는 env_file을 이용해 지정할 수 있습니다. 환경 변수를 별도로 관리하기 위해 common.env 파일을 만들어 사용합니다.
POSTGRES_USER=springtest
POSTGRES_PASSWORD=springtest
POSTGRES_DB=postgres
DB_CONNECTION_ENV=--spring.datasource.url=jdbc:postgresql://postgres-db:5432/postgres --spring.datasource.username=springtest --spring.datasource.password=springtest
JAR_FILE=app.jar
Docker Compose를 통해 실행될 때 이 환경 변수 파일을 읽어서 컨테이너를 생성하고, 컨테이너 내부에서는 DB_CONNECTION_ENV와 JAR_FILE 등을 읽어서 jar 파일을 실행합니다. 결과적으로 common.env 파일이나 docker-compose.yml 파일을 수정하는 것만으로 이미지 변경 없이 설정이 다른 컨테이너를 만들 수 있습니다.
스프링 프로필도 같은 방식으로 밖에서 고른다
application.properties는 스프링 작동과 관련한 설정을 작성하는 파일입니다. 스프링 부트는 여러 개의 application.properties를 사용하는 방법을 제공하므로, src/main/resources 아래에 기본 application.properties와 함께 application-dev.properties, application-prod.properties를 두고 상황에 따라 고를 수 있습니다.
고르는 스위치가 SPRING_PROFILES_ACTIVE 환경 변수입니다. 개발용 Compose 파일은 다음과 같습니다.
# docker-compose.dev.yml
name: spring-db-dev
services:
postgres-db:
image: postgres-iochord
expose:
- "5432"
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- ./common.env
spring-crud:
image: test-crud-app:latest
depends_on:
- postgres-db
ports:
- 8081:8081
env_file:
- ./common.env
environment:
- SPRING_PROFILES_ACTIVE=dev
volumes:
postgres_data:
driver: local
name : postgres_dev
운영용은 프로필과 포트, 볼륨 이름만 다릅니다.
# docker-compose.prod.yml
name: spring-db-prod
services:
postgres-db:
image: postgres-iochord
expose:
- "5432"
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- ./common.env
spring-crud:
image: test-crud-app:latest
depends_on:
- postgres-db
ports:
- 8082:8082
env_file:
- ./common.env
environment:
- SPRING_PROFILES_ACTIVE=prod
volumes:
postgres_data:
driver: local
name : postgres_prod
Spring App 컨테이너에 SPRING_PROFILES_ACTIVE 환경 변수 값을 전달하면, 스프링이 동작할 때 어떤 .properties 파일을 읽을 것인지 지정할 수 있습니다. 즉 환경에 따른 다양한 설정을 application-*.properties 파일로 작성해 빌드해 둔 뒤, Compose 작동 시점에 docker-compose 파일 내용에 따라 외부에서 설정을 선택하는 구조가 됩니다.
어떤 Compose 파일을 읽을지는 -f로 지정한다
파일이 여러 개가 되었으니 어느 것을 쓸지 골라야 합니다.
$ docker compose -f docker-compose.dev.yml up -d

전체 그림은 이렇게 정리됩니다. 하나의 common.env가 두 Compose 파일에 공통 환경 변수를 공급하고, docker-compose.yml과 docker-compose.dev.yml이 각각 8080·8081 포트로 서로 다른 스택을 띄우며, 각 스택 안의 Spring Boot App은 전달받은 프로필에 따라 자기가 읽을 application*.properties를 고릅니다. 이미지는 하나 그대로입니다.
'IT·테크 > 인프라' 카테고리의 다른 글
| Docker Compose scale과 nginx 로드 밸런싱으로 부하 나누기 (0) | 2026.07.28 |
|---|---|
| Docker Compose에서 .env 파일 하나만 바꿔 끼우기 (0) | 2026.07.28 |
| Docker Compose — 여러 컨테이너를 한 덩어리로 묶어 관리하기 (0) | 2026.07.26 |
| Docker 이미지와 컨테이너 — Spring Boot 앱으로 직접 만들어 보기 (2) | 2026.07.25 |
| Docker Desktop 설치 — 윈도우에서 WSL2와 Hyper-V가 하는 일 (0) | 2026.07.24 |