개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Dockerfile — 이미지를 빌드하는 명세서

2025년 6월 24일
DockerDockerfileFROMRUNCMD

Docker 이미지는 그냥 만들어지지 않는다. Dockerfile이라는 명세서에 적힌 명령어를 한 줄씩 실행하며 레이어를 쌓아 올린다. 레이어 하나하나가 캐시되기 때문에 순서와 구성이 빌드 속도에 직접적인 영향을 준다.

Dockerfile의 레이어 구조

FROM ubuntu:22.04          ← 레이어 1 (베이스 이미지)
RUN apt-get update         ← 레이어 2
RUN apt-get install -y ... ← 레이어 3
COPY . /app                ← 레이어 4
CMD ["node", "index.js"]   ← 메타데이터 (레이어 아님)

위에서 아래로 순서대로 실행되며, 변경된 줄 이후의 캐시는 모두 무효화된다.

핵심 명령어 정리

명령어역할
FROM베이스 이미지 지정
RUN빌드 시점에 쉘 명령 실행
COPY로컬 파일을 이미지로 복사
ADDCOPY + URL 다운로드 + tar 자동 압축 해제
WORKDIR이후 명령의 작업 디렉터리 설정
ENV환경 변수 설정 (빌드 및 런타임 모두)
EXPOSE컨테이너가 사용할 포트 문서화
ARG빌드 시점에만 유효한 변수
CMD컨테이너 기본 실행 명령 (오버라이드 가능)
ENTRYPOINT컨테이너 진입점 (오버라이드 어려움)

실전 Node.js 예시

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

ENV NODE_ENV=production
EXPOSE 3000

CMD ["node", "server.js"]

package*.json을 먼저 복사하고 npm ci를 실행하는 이유가 있다. 소스 코드가 바뀌어도 의존성 레이어 캐시가 유지되어 재빌드가 빠르다.

alpine — 경량 Linux 배포판. 이미지 용량을 크게 줄여준다.

CMD vs ENTRYPOINT

ENTRYPOINT ["node"]    # 고정 진입점
CMD ["server.js"]      # 기본 인자 (docker run 시 덮어쓸 수 있음)

docker run myapp index.js처럼 실행하면 CMD의 server.js가 index.js로 교체된다. ENTRYPOINT는 유지된다. 두 가지를 함께 쓸 때는 모두 JSON 배열 형식으로 통일해야 한다.

exec form — ["node", "server.js"] 형태. 쉘을 거치지 않아 신호 처리가 정확하다.

ARG와 ENV의 차이

ARG BUILD_VERSION=1.0.0
ENV APP_VERSION=$BUILD_VERSION

ARG는 docker build --build-arg BUILD_VERSION=2.0.0으로 주입하며 빌드가 끝나면 사라진다. ENV는 런타임까지 컨테이너 내부에 남는다.

COPY vs ADD

일반적으로 COPY를 사용한다. ADD는 원격 URL 다운로드나 .tar.gz 자동 압축 해제가 필요할 때만 쓴다. 그 외 상황에서 ADD를 쓰면 의도치 않은 동작이 생길 수 있다.

# 권장
COPY ./dist /app/dist

# tar 자동 해제가 필요할 때만
ADD archive.tar.gz /app/

Dockerfile은 인프라를 코드로 관리하는 첫 번째 단계다. 명령어 순서를 캐시 효율 기준으로 정렬하고, 불필요한 레이어를 줄이는 것만으로도 빌드 파이프라인이 눈에 띄게 빨라진다.

← 이전 글Docker CLI — 자주 사용하는 명령어 정리
다음 글 →.dockerignore — 빌드 컨텍스트에서 제외할 파일 지정