docker compose up을 실행할 때 이미지를 직접 빌드하게 만들 수 있다. image 키 대신 build 키를 사용하면 Compose가 지정된 Dockerfile을 읽어 이미지를 생성한다. 빌드 컨텍스트, Dockerfile 경로, 빌드 인수를 조합하면 개발과 프로덕션 환경을 하나의 compose.yml로 관리할 수 있다.
compose.yml
├── services
│ └── app
│ └── build
│ ├── context ← 빌드 컨텍스트 디렉토리
│ ├── dockerfile ← Dockerfile 경로 (상대 경로)
│ └── args ← ARG 값 주입
가장 단순한 형태는 build: .처럼 컨텍스트만 지정하는 것이다. Compose는 해당 디렉토리에서 Dockerfile을 자동으로 찾는다.
services:
app:
build: .
ports:
- "3000:3000"
context는 Docker 데몬에 전송되는 파일 트리의 루트다. Dockerfile 안의 COPY, ADD 명령은 이 경로를 기준으로 파일을 찾는다.
dockerfile은 context 안에서 사용할 Dockerfile의 상대 경로를 명시한다. 파일명이 Dockerfile이 아닐 때 반드시 지정해야 한다.
services:
app:
build:
context: ./app
dockerfile: docker/Dockerfile.prod
context — 빌드 시 Docker 데몬에 전달되는 파일 집합의 루트 디렉토리. .dockerignore로 제외 파일을 설정한다.
Dockerfile의 ARG 지시어에 값을 전달할 때 args를 사용한다. 런타임 환경변수(ENV)와 달리 빌드 시점에만 존재한다.
services:
app:
build:
context: .
args:
NODE_ENV: production
APP_VERSION: "2.1.0"
FROM node:20-alpine
ARG NODE_ENV
ARG APP_VERSION
ENV NODE_ENV=${NODE_ENV}
LABEL version=${APP_VERSION}
ARG — 빌드 단계에서만 유효한 변수. 이미지 레이어에 남지 않아 비밀값 전달에는 부적합하다. 비밀값은 --secret 플래그를 사용한다.
멀티스테이지 Dockerfile과 target 키를 조합하면 하나의 Dockerfile로 두 환경을 분리할 수 있다.
services:
app-dev:
build:
context: .
target: development
app-prod:
build:
context: .
target: production
args:
NODE_ENV: production
| 항목 | 개발 | 프로덕션 |
|---|---|---|
| target | development | production |
| devDependencies | 포함 | 제외 |
| 소스 마운트 | 볼륨 마운트 | COPY로 번들 |
| 이미지 크기 | 크다 | 작다 |
docker compose build 명령은 compose.yml에 정의된 모든 서비스의 이미지를 빌드한다. --no-cache 옵션으로 캐시를 무시하거나, --pull로 베이스 이미지를 항상 최신으로 유지할 수 있다.
# 캐시 없이 전체 빌드
docker compose build --no-cache
# 특정 서비스만 빌드
docker compose build app
# 베이스 이미지 갱신 후 빌드
docker compose build --pull
빌드 캐시는 레이어 단위로 동작한다. COPY package.json . → RUN npm install 순서로 작성하면 소스 변경 시에도 의존성 설치 레이어를 재사용할 수 있다.