ビルドが始まる前にもう遅くなっている
한국어 원문으로 표시합니다.
한 줄 요약
docker build . 의 그 점 하나가 현재 디렉터리 전체를 빌더로 전송합니다.
캐시를 아무리 잘 짜도, 전송해야 할 게 800MB 면 빌드는 그 전에 이미 느립니다.
왜 이게 필요했나
Dockerfile 은 두 줄뿐인데 빌드가 40초 걸립니다. 로그 첫 줄을 보면 답이 있습니다.
Sending build context to Docker daemon 812.4MB
빌드가 시작되기도 전에, 현재 디렉터리를 통째로 압축해 빌더에게 보내는
단계입니다. node_modules, .git, dist, 어제 받아 둔 덤프 파일까지
전부 갑니다. Dockerfile 에서 안 쓰더라도 전송은 됩니다.
여기서 두 가지가 동시에 망가집니다.
- 속도 — 매 빌드마다 수백 MB 를 옮깁니다.
- 캐시 —
COPY . .는 컨텍스트 안 파일이 하나라도 바뀌면 깨집니다..git/index는git status만 쳐도 바뀝니다. 그래서 소스를 안 고쳤는데도 캐시가 깨지는 일이 생깁니다.
어떻게 동작하나
.dockerignore 는 .gitignore 와 문법이 비슷하지만 목적이 다릅니다.
.gitignore 는 "버전 관리하지 않을 것", .dockerignore 는 "빌더에게 보내지
않을 것"입니다. 겹치는 부분이 많지만 같지 않습니다 — 예를 들어 .git 은
.gitignore 에 넣을 수 없지만 .dockerignore 에는 반드시 넣어야 합니다.
.git
node_modules
**/__pycache__
*.log
dist/
.env
마지막 줄이 중요합니다. .env 를 컨텍스트에 두면 COPY . . 로 이미지에
그대로 박힙니다. 나중에 지우는 레이어를 추가해도 앞 레이어에는 남습니다.
재현성 — 같은 Dockerfile, 다른 결과
.dockerignore 로 컨텍스트를 줄여도 빌드가 재현되지 않는 흔한 이유가 둘 더
있습니다.
떠다니는 태그. FROM python:3.12 는 오늘과 다음 달이 다른 이미지입니다.
FROM python:3.12.7-slim 처럼 고정하거나, 더 엄격하게는 다이제스트로
FROM python@sha256:... 를 씁니다.
패키지 인덱스. apt-get install curl 은 그날의 최신 버전을 가져옵니다.
어제 통과한 빌드가 오늘 깨지는 고전적인 원인이고, 정말 필요한 곳에서는
버전을 명시합니다.
| 문제 | 증상 | 대응 |
|---|---|---|
| 큰 컨텍스트 | "Sending build context" 가 수백 MB | .dockerignore |
.git 포함 |
소스 안 고쳤는데 캐시가 깨짐 | .dockerignore 에 .git |
| 떠다니는 태그 | 지난주 빌드와 결과가 다름 | 패치 버전·다이제스트 고정 |
| 시크릿 유입 | 이미지에 .env 가 들어감 |
.dockerignore + 빌드 시크릿 |
ARG 는 이미지에 남는다
ARG API_TOKEN
RUN curl -H "Authorization: $API_TOKEN" ...
이렇게 쓰면 docker history 에 그 값이 남습니다. 빌드 타임 비밀은 ARG 가
아니라 BuildKit 의 시크릿 마운트로 넘깁니다. ARG 는 "버전 번호" 같은
공개해도 되는 값에만 씁니다.
현장에서 만나는 모습
- 신규 입사자가
git clone후 첫 빌드에 5분 —.dockerignore가 없다. - CI 는 빠른데 로컬만 느리다 — 로컬에는
node_modules와 빌드 산출물이 있다. - 이미지에서 고객 덤프 CSV 가 발견됐다 — 컨텍스트에 있었고
COPY . .였다.
컨텍스트를 줄이는 것 말고 안 보내는 방법
.dockerignore 는 보낼 것을 줄이지만, 아예 다른 길로 가져오는 방법도 있다.
어느 쪽이 맞는지는 그 파일이 빌드에 필요한 이유로 갈린다.
빌드에만 필요하고 최종 이미지에는 없어야 하는 것 — 앞 코스에서 본 다단계 빌드와 비밀 마운트가 이 자리다. 자격 증명은 컨텍스트에 아예 넣지 않고 마운트로 건네고, 컴파일 도구와 중간 산출물은 앞 단계에 두고 결과만 옮긴다.
빌드 중에 받아 오는 것 — 캐시 마운트를 쓰면 의존성 디렉터리를 컨텍스트에
넣지 않고도 빌드 사이에 재사용할 수 있다. node_modules 를 통째로 보내지
않아도 되는 이유가 이것이고, 컨텍스트가 작아지는 동시에 캐시도 좋아진다.
원격에서 가져오는 것 — 빌더는 컨텍스트 대신 git 저장소 주소나 tarball 주소를 받을 수도 있다. CI 처럼 이미 그 자리에 소스가 있는 환경에서는 큰 차이가 없지만, 컨텍스트를 만들 수 없는 자리에서는 이 길이 유일하다.
그리고 무엇이 실제로 갔는지 확인하는 방법을 알아 두면 좋다. 컨텍스트에
무엇이 담기는지는 .dockerignore 규칙의 순서와 부정 패턴에 따라 헷갈리기
쉬운데, 이미지를 만든 뒤 그 안의 파일 목록을 훑어 보면 의도하지 않은 것이
들어갔는지 바로 드러난다. 비밀이 들어갔는지 확인하는 가장 확실한 방법도
이것이고, 앞 코스에서 본 대로 레지스트리에 올라간 뒤에는 되돌릴 수 없으므로
올리기 전에 한 번 보는 값이 크다.
다음 확인에서 볼 것
이어지는 퀴즈에서는 빌드 컨텍스트의 경계, .dockerignore, 캐시 키와 비밀 전달
방식을 판단합니다. 앞 실습에서 측정한 전송 크기와 캐시 무효화 결과를 근거로
소스 변경과 무관한 파일이 빌드에 미치는 영향을 구분해 보세요.