Docker
.dockerignore 없이 빌드하면 이미지가 왜 커지는가
.dockerignore를 설정하지 않으면 node_modules나 .git 같은 폴더가 통째로 이미지에 포함된다. 이미지 크기와 빌드 시간, 보안 모두 영향을 받는다.
Dockerfile을 처음 만들 때 .dockerignore를 빠뜨리는 경우가 많다. COPY . . 한 줄이면 소스 코드가 다 들어간다고 생각하기 쉬운데, 실제로는 프로젝트 루트에 있는 모든 것이 빌드 컨텍스트로 넘어간다.
무엇이 들어가는지 확인한다
빌드 컨텍스트에 무엇이 포함되는지 보려면 빌드 시 출력 첫 줄을 확인하면 된다.
Sending build context to Docker daemon 512.4MB
이 숫자가 크다면 불필요한 파일이 들어가고 있는 것이다. node_modules(수백 MB), .git 디렉토리(커밋 히스토리 전체), .env 파일, 빌드 결과물인 .next 폴더까지 전부 데몬으로 전송된 다음 이미지 레이어에 쌓인다.
.dockerignore 기본 작성법
Node.js 프로젝트를 기준으로 최소한 이것은 제외해야 한다.
# 의존성 (컨테이너 안에서 npm ci로 설치)
node_modules
npm-debug.log
# 버전 관리
.git
.gitignore
# 빌드 캐시/결과물
.next
dist
build
# 환경 변수 (절대 이미지에 포함시키지 않는다)
.env
.env.local
.env.*.local
# 에디터/OS
.DS_Store
.idea
.vscode
.env가 이미지에 포함되면 docker history 명령이나 레이어 추출으로 내용을 확인할 수 있다. 이미지를 레지스트리에 올리는 순간 보안 사고로 이어질 수 있다.
node_modules 제외가 핵심
node_modules를 제외하지 않으면 두 가지 문제가 생긴다. 첫째, 수백 MB를 매 빌드마다 전송한다. 둘째, 컨테이너 안 OS(보통 Alpine이나 Debian)와 다른 플랫폼용 바이너리가 섞일 수 있다. 예를 들어 macOS에서 npm install한 node_modules를 Linux 컨테이너에 복사하면 네이티브 모듈이 동작하지 않는다.
Dockerfile에서 npm ci를 실행하는 이유가 여기 있다.
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
이미지 크기 비교
.dockerignore 없이 빌드한 이미지와 있을 때를 비교하면 차이가 바로 보인다.
docker image ls | grep my-app
# my-app without-ignore 1.2GB
# my-app with-ignore 180MB
크기가 줄면 레지스트리 푸시·풀 시간이 줄고, 컨테이너 시작 속도도 조금 빨라진다. .dockerignore는 Dockerfile과 같은 디렉토리에 두면 자동으로 적용된다.