빠른 비교
ARG NODE_VERSION=22
FROM node:${NODE_VERSION}-alpine
ENV NODE_ENV=production
ENV PORT=3000# ARG는 --build-arg로 주입
docker build --build-arg NODE_VERSION=20 -t my-app .
# ENV는 -e로 런타임에 재정의 가능
docker run -e PORT=4000 my-app갈리는 기준
어떤 변수 전달 방식을 먼저 떠올리면 되나
| 상황 | 먼저 떠올릴 선택 |
|---|---|
| 베이스 이미지 버전처럼 빌드 시점 값 | ARG |
| 앱 포트나 모드처럼 런타임 값 | ENV |
| 컨테이너 실행 때 값 덮어쓰기 | docker run -e |
| 민감 정보 전달 | BuildKit secret 또는 외부 시크릿 |
ARG — 빌드 시점에만 존재하고 이미지 레이어에 값이 남지 않는다
ARG로 선언한 변수는 docker build 실행 중에만 유효합니다. 빌드가 끝나면 컨테이너 런타임에는 전달되지 않습니다. 베이스 이미지 버전, 빌드 툴 경로, 패키지 버전처럼 "이미지를 어떻게 만들 것인가"를 파라미터로 받을 때 적합합니다.
ARG ALPINE_VERSION=3.19
FROM alpine:${ALPINE_VERSION}
ARG BUILD_DATE
LABEL build-date=${BUILD_DATE}
# BUILD_DATE는 빌드 후 컨테이너 환경에 남지 않음ENV — 이미지와 컨테이너 런타임 모두에서 유지된다
ENV로 설정한 값은 이미지 레이어에 기록되어, 컨테이너가 실행될 때도 환경 변수로 남습니다. 애플리케이션 설정 기본값, 포트, 런타임 모드처럼 "컨테이너가 어떤 설정으로 동작할 것인가"를 정의할 때 씁니다. docker run -e로 런타임에 재정의할 수 있습니다.
ENV NODE_ENV=production
ENV PORT=3000
ENV LOG_LEVEL=info
# 컨테이너 실행 시 process.env.PORT === '3000'ARG와 ENV는 보이는 시점이 다르다
ARG는 빌드 도중 Dockerfile 계산에만 보이고, ENV는 최종 컨테이너 프로세스에도 보입니다. 그래서 Node 버전이나 베이스 이미지 태그는 ARG가 맞고, NODE_ENV나 PORT처럼 앱이 실행 중 읽는 값은 ENV가 맞습니다. "앱 코드가 이 값을 읽어야 하나"를 기준으로 고르면 실수가 줄어듭니다.
ARG NODE_VERSION=22
FROM node:${NODE_VERSION}-alpine
ENV NODE_ENV=production
ENV PORT=3000ARG로 시크릿을 넘기면 docker history에 노출된다
ARG가 이미지 레이어에 "값"을 남기지 않는다고 해도, docker history --no-trunc 명령으로 빌드 레이어 메타데이터를 보면 --build-arg로 전달된 값이 보일 수 있습니다. 비밀번호나 API 키 같은 민감 정보는 ARG로 넘기지 않아야 합니다.
# 위험한 패턴
docker build --build-arg DB_PASSWORD=secret .
docker history my-app # DB_PASSWORD가 노출될 수 있음
# 안전한 대안: BuildKit secret 마운트 사용
docker build --secret id=db_password,src=./.secrets/db_password .선택 기준
| 상황 | 적합한 선택 |
|---|---|
| 베이스 이미지 버전, 빌드 파라미터 | ARG |
| 앱 설정, 포트, 런타임 모드 | ENV |
| 민감 정보 (비밀번호, API 키) | BuildKit secret (ARG/ENV 모두 피함) |
| 빌드 후에도 컨테이너에서 읽어야 하는 값 | ENV |
| 이미지마다 다르게 빌드해야 하는 파라미터 | ARG |
주의할 점
시크릿을 ARG로 넘기면 docker history에 값이 노출된다. ARG가 런타임에 남지 않는다고 해도 빌드 캐시와 히스토리에 기록될 수 있으므로, 비밀번호나 토큰은 BuildKit의 --secret 플래그나 런타임 시크릿 관리 도구를 써야 한다.
ARG APP_PORT=3000docker build --build-arg APP_PORT=4000 -t my-app .
docker run my-app env | grep PORT
# APP_PORT는 런타임 환경변수가 아니라서 앱이 읽지 못함참고 링크
2 sources