도커를 배우면서 “Dockerfile을 작성한다”는 말을 많이 들었지만, 막상 손에 잡히지 않았던 적이 있습니다.
FROM, RUN, COPY, CMD 같은 명령어들이 도대체 어떤 순서로 실행되고, 왜 이렇게 작성해야 하는지 감이 안 왔죠.
한 줄 한 줄의 의미보다도, 이게 어떤 구조로 동작하는지를 이해하는 게 더 중요했습니다.
처음 Dockerfile을 마주했을 때

처음 Dockerfile을 봤을 때, “이게 뭔가 빌드 스크립트인가?” 싶은 생각이 들었습니다.
대충 보면 리눅스 명령어랑 비슷하긴 한데, 순서가 조금 특이하죠.
예를 들어 이런 식입니다.
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "start"]
이걸 그대로 실행하면 “이미지가 생성된다”고들 말하지만, 사실 이 파일 안의 명령들은 이미지를 구성하는 레이어(layer) 들을 만드는 단계들입니다.
즉, 한 줄 한 줄이 각각의 파일 시스템 상태로 쌓여서 완성된 이미지가 만들어지는 겁니다.
FROM — 기반 환경을 지정한다

FROM은 말 그대로 “어떤 환경을 기반으로 할지”를 정하는 명령입니다.
처음 배울 땐 무심코 넘어가지만, 이 한 줄이 굉장히 중요합니다.
예를 들어 FROM node:18-alpine은 “리눅스 알파인 기반의 Node.js 18 버전이 설치된 환경을 가져오겠다”는 뜻입니다.
이 한 줄만으로도 OS, Node 버전, 패키지 매니저가 한꺼번에 준비됩니다.
예전에 이걸 모르고 FROM ubuntu:20.04부터 시작해 Node를 직접 설치했는데,
빌드 속도도 느리고 이미지 용량이 두 배가 되더군요.
그래서 가능하면 공식 이미지를 기반으로 시작하는 게 좋습니다.
WORKDIR — 작업 디렉토리를 지정한다
WORKDIR은 명령어들이 실행될 기본 경로를 정합니다.
이게 없으면 기본적으로 / 루트 경로에서 모든 명령이 실행되는데,
그 상태에서 COPY를 하면 루트 밑에 코드가 복사돼 버려서 나중에 파일 구조가 엉망이 됩니다.
즉, WORKDIR /app은 “이 아래에서 작업하겠다”는 의미이고,
그 뒤의 모든 RUN, COPY, CMD는 /app 내부 기준으로 실행됩니다.
COPY & RUN — 이미지 안으로 코드와 의존성을 집어넣는다
COPY는 로컬 파일을 이미지 안으로 복사하는 명령입니다.
예를 들어 COPY package*.json ./ 은 현재 디렉토리의 package.json과 package-lock.json을 이미지 내부로 옮깁니다.
그다음 RUN npm install은 이미지 안에서 패키지를 설치하는 단계입니다.
여기서 중요한 점은, 이 과정도 “하나의 레이어로 저장된다”는 것입니다.
즉, npm install이 완료된 상태가 캐시로 남고, 이후 빌드할 때 같은 package.json이면 이 단계는 건너뛰게 됩니다.
처음엔 왜 이렇게 단계별로 나뉘어 있는지 의아했는데,
빌드를 여러 번 반복해보면 이 구조가 얼마나 효율적인지 깨닫게 됩니다.
패키지가 바뀌지 않았는데 매번 다시 설치하지 않아도 되니까요.
CMD — 컨테이너 실행 시 실제로 돌아갈 명령
CMD는 이미지가 컨테이너로 실행될 때 기본으로 실행되는 명령을 정의합니다.
예를 들어 CMD ["npm", "start"]는 docker run으로 컨테이너를 띄웠을 때 자동으로 npm start가 실행되도록 만듭니다.
이 부분은 자주 오해받는 명령 중 하나입니다.
RUN은 “이미지 빌드 중 실행”이고, CMD는 “컨테이너 실행 시 실행”이라는 차이점이 있습니다.
실무에서도 이걸 헷갈리면,
컨테이너가 시작하자마자 종료되는 황당한 경험을 하게 되죠.
빌드 과정을 실제로 보면 확실히 이해된다

Dockerfile을 다 작성한 뒤, 터미널에서 이렇게 입력합니다.
docker build -t myapp:latest .
그러면 도커는 각 명령어를 순차적으로 읽어들이면서 이미지를 단계별로 쌓습니다.
각 단계가 끝날 때마다 “레이어”로 저장되고,
다음 빌드 때 변경되지 않은 단계는 캐시를 그대로 재사용합니다.
이 과정을 보면, Dockerfile은 단순한 스크립트가 아니라
**“환경을 조립하는 설계도”**라는 걸 실감하게 됩니다.
실무에서 느낀 Dockerfile 팁
처음 프로젝트에 도커를 도입했을 때,
Dockerfile이 길어질수록 빌드 속도가 너무 느려서 스트레스가 컸습니다.
그때 알게 된 몇 가지 팁이 있습니다.
- COPY 순서가 중요하다. 변경이 적은 파일부터 위에 배치해야 캐시가 더 잘 활용된다.
- RUN apt-get update && apt-get install처럼 여러 명령을 한 줄로 묶으면 이미지 레이어를 줄일 수 있다.
- .dockerignore 파일을 꼭 만들어서 빌드에 불필요한 파일을 제외해야 한다.
이 세 가지를 지키는 것만으로도 빌드 시간이 절반으로 줄었습니다.
지금 돌이켜보면
처음에는 그저 docker build 한 줄로 끝나는 줄 알았는데,
알고 보면 Dockerfile의 구조를 제대로 이해하는 게
이미지를 효율적으로 관리하고 디버깅하는 데 핵심이었습니다.
빌드 캐시 구조, 레이어 개념, RUN과 CMD의 차이 —
이걸 이해하고 나니까 도커를 단순히 “도구”로 쓰는 게 아니라
하나의 개발 환경 관리 시스템처럼 다루게 되더군요.
'docker' 카테고리의 다른 글
| Docker Compose로 여러 컨테이너 한 번에 다루기 (0) | 2025.11.12 |
|---|---|
| 도커 이미지와 컨테이너, 뭐가 다른 걸까 (0) | 2025.11.12 |
| 도커로 무중단 배포(Blue-Green Deployment) 구현하기 (0) | 2025.11.12 |
| 도커와 CI/CD — 자동으로 빌드하고 배포하기 (0) | 2025.11.12 |
| 도커 이미지 배포 — Docker Hub부터 사설 레지스트리까지 (0) | 2025.11.12 |