같은 Dockerfile로 개발용·스테이징용·운영용 이미지를 조금씩 다르게 굽고 싶을 때가 있습니다. 베이스 이미지 버전을 바꾼다든지, 빌드 시 API 주소를 다르게 넣는다든지요. Dockerfile을 환경마다 복사하지 말고, 빌드 시점 변수인 ARG 로 한 파일에서 처리하는 게 정석입니다. ARG는 docker build 할 때 --build-arg로 값을 넘겨받는 변수입니다.
ARG 기본
Dockerfile
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-slim
ARG APP_ENV=production
RUN echo "building for ${APP_ENV}"
Docker
docker build --build-arg NODE_VERSION=18 --build-arg APP_ENV=staging -t myapp:staging .
--build-arg를 안 주면 Dockerfile에 적은 기본값(20, production)이 쓰입니다. 환경별로 같은 파일을 그대로 두고 값만 바꿔 끼우는 셈입니다.
ARG vs ENV — 가장 헷갈리는 부분
| 구분 | ARG | ENV |
|---|---|---|
| 사는 시점 | 빌드 중에만 | 빌드 + 컨테이너 실행 중 |
| 주입 방법 | --build-arg | Dockerfile ENV / docker run -e |
| 실행 중 접근 | 불가 (사라짐) | 가능 |
즉 ARG로 받은 값은 이미지가 다 구워지면 사라집니다. 컨테이너 실행 중에도 쓰려면 ARG를 ENV로 옮겨 담아야 합니다.
Dockerfile
ARG APP_ENV=production
ENV APP_ENV=${APP_ENV}
FROM 위의 ARG는 스코프가 다르다
FROM보다 위에 선언한 ARG는 빌드 스테이지 안에서 다시 선언해야 보입니다. 이게 멀티스테이지에서 자주 막히는 지점입니다.
Dockerfile
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-slim
ARG NODE_VERSION # 스테이지 안에서 다시 선언해야 사용 가능
RUN echo "node ${NODE_VERSION}"
시크릿을 ARG로 넣지 말 것
--build-arg로 넘긴 값은 docker history에 그대로 남습니다. 비밀번호나 토큰을 ARG로 주입하면 이미지를 받은 누구나 볼 수 있습니다. 시크릿은 BuildKit의 --secret을 써야 합니다.
로컬 터미널
docker history myapp:staging # ARG로 넣은 값이 평문으로 보인다
체크리스트
Docker
docker build --build-arg APP_ENV=staging -t myapp:staging .
docker history myapp:staging # 시크릿이 새어나가지 않았는지
docker inspect myapp:staging # ENV로 옮긴 값 확인
docker build --no-cache ... # ARG 변경이 캐시에 묻히면 강제 재빌드
ARG 값을 바꿨는데 결과가 그대로라면 레이어 캐시 때문입니다. 해당 단계부터 --no-cache로 다시 구우세요.
ARG와 멀티스테이지를 엮어 환경별 이미지를 직접 굽는 실습은 도커 트랙에서 무료로 할 수 있습니다.