이미지를 만드는 명령서. 명령어는 18개뿐인데, 그중 절반이 비슷해 보이는 것끼리 짝을 이룬다.
FROM · RUN · CMD · LABEL · EXPOSE · ENV · ADD · COPY · ENTRYPOINT VOLUME · USER · WORKDIR · ARG · ONBUILD · STOPSIGNAL · HEALTHCHECK · SHELL MAINTAINER (폐기 — LABEL maintainer 를 쓴다)
- 레이어를 만드는 것 — RUN · COPY · ADD
- 메타데이터만 바꾸는 것 — 나머지 전부
문법 버전을 고정한다
# syntax=docker/dockerfile:1
파서 지시자다 — BuildKit 이 어떤 Dockerfile 문법을 쓸지 정한다
기능마다 요구 버전이 다르다
1.2 RUN --mount=type=cache
1.4 COPY --link · 히어독
1.8 # check= 지시자 (빌드 검사)
없으면 데몬에 내장된 낡은 문법으로 파싱돼 "문법 오류" 가 난다
COPY vs ADD
COPY app.jar /app/ # 기본. 파일·디렉터리 복사
ADD https://x/y.tar.gz / # 원격 URL 다운로드
ADD archive.tar.gz /app/ # tar 자동 압축 해제
공식 권장 — 기본은 COPY 를 쓴다
ADD 가 위험한 이유
- tar 를 '자동으로 푼다' — 의도치 않게 파일이 흩어진다
- 원격 URL 은 캐시 판정이 애매하고 검증이 없다
- 무엇을 할지 파일 확장자에 따라 달라진다 (예측 불가)
원격 파일이 필요하면 RUN 안에서 받고 체크섬을 검증한다
ENV vs ARG
ARG NODE_VERSION=22 # 빌드 시점에만 존재
ENV NODE_ENV=production # 이미지에 남아 런타임에도 보인다
둘 다 비밀을 담으면 안 된다 ARG 로 넘긴 값도 docker history 에 남는다 ENV 는 docker inspect 로 그대로 보인다
빌드 비밀은 시크릿 마운트로
- RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
- 빌드 중에만 파일로 존재하고 레이어에 남지 않는다
.dockerignore
docker build . 의 '.' 이 빌드 컨텍스트다 — 이 디렉터리 전체가 전송된다
.git · node_modules · 빌드 산출물이 통째로 넘어가면
- 전송이 느려진다
- COPY . . 로 이미지에 딸려 들어간다 (비밀 유출)
이미지에 .git 이 통째로 들어가 있는 경우가 의외로 흔하다 커밋 히스토리에 남은 비밀까지 함께 나간다
자주 틀리는 것
- EXPOSE — 문서일 뿐이다. 실제 공개는 docker run -p 가 한다
- WORKDIR — RUN cd 는 다음 RUN 에서 원위치로 돌아간다. WORKDIR 을 쓴다
- VOLUME — 이미지에 넣으면 익명 볼륨이 자동 생성돼 통제가 어렵다
- 실행 시 -v 로 지정하는 편이 낫다
빌드 검사
# syntax=docker/dockerfile:1
# check=error=true
BuildKit 이 흔한 실수를 잡아 준다
- 정의하지 않은 ARG 사용
- JSON 이 아닌 CMD/ENTRYPOINT (shell form 경고)
- 대소문자 불일치 (from → FROM)
- 중복 스테이지 이름
Dockerfile v1.8.0+ 에서 쓸 수 있다 CI 에 넣으면 리뷰에서 반복 지적하던 것들이 자동으로 걸린다 hadolint 같은 외부 린터를 함께 쓰기도 한다
자주 쓰는 골격
# syntax=docker/dockerfile:1
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
USER 101:101
면접 함정
- ❌ "ADD가 COPY의 상위 호환" → 자동 압축 해제 때문에 예측이 어렵다. 기본은 COPY다.
- ❌ "EXPOSE하면 포트가 열린다" → 문서일 뿐이다.