docker build를 실행하면 Docker는 지정된 디렉터리 전체를 Build Context로 묶어 데몬에 전송한다. node_modules나 .git 같은 대용량 디렉터리가 포함되면 전송 시간이 수십 초씩 늘어날 수 있다. .dockerignore는 이 컨텍스트에서 제외할 경로를 명시하는 파일로, .gitignore와 동일한 위치(프로젝트 루트)에 둔다.
$ docker build -t my-app .
^^^^^^^^^^^^^^^^
'.' = Build Context 루트
클라이언트 (로컬 파일시스템)
|
| tar로 압축 후 전송
v
Docker 데몬
|
| Dockerfile 명령 순서대로 레이어 생성
v
이미지
docker build 명령의 마지막 인자(.)가 Build Context다. Docker 클라이언트는 이 디렉터리를 tar로 묶어 데몬에 보내고, 데몬이 Dockerfile을 해석하며 레이어를 쌓는다. 컨텍스트 크기가 곧 전송 비용이다.
Build Context — Docker 데몬이 이미지를 빌드할 때 참조하는 파일 집합. COPY · ADD 명령은 이 컨텍스트 안의 경로만 접근할 수 있다.
.dockerignore에 등록된 경로는 tar 압축 단계에서 아예 제외된다. Dockerfile의 COPY . . 명령이 실행될 때도 해당 파일은 존재하지 않으므로 이미지 레이어에 포함되지 않는다.
| 제외 대상 | 이유 |
|---|---|
node_modules | 컨테이너 안에서 npm install로 재설치 |
.git | 버전 이력은 런타임에 불필요, 용량이 큼 |
.env | 시크릿 노출 방지 |
*.log | 런타임 로그는 컨테이너 외부에서 관리 |
dist / build | 이미지 안에서 직접 빌드하는 경우 불필요 |
.gitignore와 거의 동일한 glob 문법을 사용한다.
# 주석
node_modules
.git
.env* # .env, .env.local, .env.production 모두 제외
**/*.log # 모든 하위 디렉터리의 .log 파일
dist/
!dist/static # dist 제외하되 dist/static은 포함 (예외)
! 접두사는 이전 규칙을 무효화하는 예외 패턴이다. 순서가 중요하며, 나중에 오는 규칙이 앞 규칙을 덮어쓴다.
glob 패턴 — *는 단일 경로 세그먼트 내 임의 문자열, **는 디렉터리 경계를 넘는 임의 경로를 의미한다.
Node.js 프로젝트의 전형적인 .dockerignore는 다음과 같다.
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
dist
coverage
*.test.ts
빌드 로그에서 Sending build context to Docker daemon 줄의 크기가 줄어든 것으로 효과를 바로 확인할 수 있다.
# 적용 전
Sending build context to Docker daemon 312.4MB
# 적용 후
Sending build context to Docker daemon 1.234MB
.dockerignore는 COPY 명령보다 먼저 평가된다. COPY . .처럼 와일드카드를 사용하더라도 제외된 경로는 복사되지 않는다. 반대로 .dockerignore에 등록하지 않은 파일은 COPY에서 명시적으로 지정하지 않는 한 이미지에 들어가지 않으므로, 컨텍스트 크기 제어와 복사 범위 제어는 별개임을 구분해야 한다.
레이어 캐시(Layer Cache) — Docker는 명령과 컨텍스트 해시를 기반으로 캐시를 재사용한다. 불필요한 파일이 변경될 때마다 캐시가 무효화되는 문제도 .dockerignore로 방지할 수 있다.