Docker image가 너무 커지면 단순히 저장 공간만 아까운 게 아닙니다. build가 느려지고, push와 pull이 무거워지고, CI 시간이 늘어나고, 배포도 늦어지며, cold start나 node pull 지연도 더 눈에 띄게 됩니다.
짧게 말하면, 무작정 base image만 바꾸기보다 먼저 어떤 layer가 큰지, build 전용 도구가 runtime까지 남았는지, build context에 들어오면 안 되는 파일이 섞였는지를 확인하는 게 더 중요합니다.
먼저 image size와 build 속도 문제를 분리해서 보세요
팀에서 자주 섞어 말하는 문제는 사실 세 가지입니다.
- 최종 runtime image 자체가 너무 큰 경우
- layer 재사용이 나빠서 build가 느린 경우
- build context가 커서 전송과 복사가 느린 경우
세 가지가 동시에 있을 수는 있지만, 어디가 핵심인지에 따라 대응이 달라집니다. image가 커도 caching이 좋으면 build는 빨리 끝날 수 있고, image가 작아도 Dockerfile 순서가 나쁘면 build는 계속 느릴 수 있습니다. 또 최종 image는 적당해도 build context에 불필요한 파일이 많으면 체감은 여전히 나쁩니다.
Docker image가 커지는 흔한 이유
1. base image가 필요 이상으로 무거움
일부 image는 애플리케이션 코드가 들어가기 전부터 이미 수백 메가바이트를 차지합니다. 풀 배포판 기반 이미지나 build toolchain이 모두 들어 있는 language image가 대표적입니다.
그렇다고 무조건 가장 작은 image가 정답은 아닙니다. 호환성, 패치 관리, 운영 편의성도 중요합니다. 다만 runtime만 필요한 서비스에 build 환경 전체를 싣고 가는 것은 대개 낭비입니다.
2. build dependency가 최종 image에 남아 있음
compiler, package manager, test tool, header, cache가 multi-stage build 없이 그대로 최종 image에 남는 경우가 많습니다.
실무에서 production image가 예상보다 훨씬 큰 가장 흔한 원인 중 하나입니다.
3. build context에 너무 많은 파일이 들어옴
.dockerignore가 약하면 로컬 artifact, virtual environment, node_modules, 테스트 결과물, 임시 파일, 심지어 Git 이력까지 build context에 포함될 수 있습니다.
이 파일들이 runtime image까지 들어가면 더 큰 문제고, 들어가지 않더라도 build 자체는 무거워집니다.
4. Dockerfile이 불필요한 layer를 만들고 있음
반복되는 package install, 너무 넓은 COPY . ., 순서가 좋지 않은 layer 구성은 size와 cache 재사용성 모두에 악영향을 줍니다.
하나하나는 작아 보여도 합치면 빠르게 커집니다.
5. 하나의 image가 너무 많은 역할을 담고 있음
runtime, 관리 도구, migration script, debugging utility, 대용량 asset을 하나의 image에 모두 묶어두면 구조적으로 커질 수밖에 없습니다.
이 경우는 Dockerfile만의 문제가 아니라 패키징 전략 자체를 봐야 합니다.
실전 점검 순서
1. image size를 보고 layer history를 확인하세요
먼저 아래 명령으로 큰 층이 어디서 나오는지 봅니다.
docker images
docker history <image>
docker image inspect <image>
처음부터 완벽한 분석이 필요하진 않습니다. 일단 “base image가 큰지, dependency install layer가 큰지, build artifact가 남는지, 애플리케이션 파일 복사가 큰지”만 구분해도 충분합니다.
2. build 전용 도구가 runtime에 남았는지 확인하세요
package manager, compiler, test dependency가 최종 image에 있다면 multi-stage build를 더 깔끔하게 쓰는 쪽이 보통 가장 빠른 개선입니다.
애플리케이션 동작을 바꾸지 않고도 크게 줄일 수 있는 경우가 많습니다.
3. .dockerignore와 넓은 COPY를 점검하세요
Dockerfile이 COPY . .를 쓴다면, build context가 정말 깨끗한지 먼저 확인해야 합니다.
특히 아래 항목이 자주 문제를 만듭니다.
- 로컬 cache
- 이미지 밖에서 생성된 dependency 디렉터리
- build output
- 로그, coverage, 임시 파일
- 들어가면 안 되는 secret이나 config
4. 최근 변경 이후 dependency 무게가 어떻게 달라졌는지 비교하세요
image가 갑자기 커졌다면 최근 변경을 보는 편이 가장 빠릅니다.
- 새 language package 추가
- base image 변경
- build step 추가
- asset 또는 generated file 증가
- 여러 앱을 하나의 image에 묶는 변경
큰 리팩터링보다 최근 증가분 하나를 되돌리거나 줄이는 게 더 효과적인 경우가 많습니다.
5. Dockerfile 문제인지, 앱 패키징 문제인지 구분하세요
어떤 경우는 Dockerfile 구조만 정리하면 되고, 어떤 경우는 앱 자체가 너무 큰 bundle을 만들고 있는 것이 핵심입니다.
예를 들어 큰 모델 파일, static asset, 사용하지 않는 dependency를 계속 싣고 있다면 그건 Docker가 아니라 패키징 전략 문제에 가깝습니다.
패턴을 찾은 뒤 어떻게 바꿀지
base image가 주된 원인인 경우
호환성이 허용하는 범위에서 더 lean한 runtime 중심 base image로 옮기세요. 목표는 “무조건 최소”가 아니라 “충분히 작고 운영하기 쉬운 상태”입니다.
build tooling이 runtime에 남은 경우
multi-stage build를 적용해서 build와 runtime을 분리하고, 최종 image에는 실행에 필요한 산출물만 남기세요.
build context가 부풀어 있는 경우
.dockerignore를 강화하고, COPY 범위를 좁히고, 저장소 전체를 통째로 복사하지 않도록 정리하세요.
dependency 증가가 원인인 경우
사용하지 않는 라이브러리를 제거하고, 선택 기능을 분리하고, 하나의 image가 단일 runtime 책임만 갖도록 정리하는 편이 좋습니다.
큰 image 때문에 배포 체감도 나빠진 경우
Cloud Run 첫 요청 지연과 함께 보인다면 GCP Cloud Run cold start를, Docker host 디스크 압박도 같이 있다면 Docker no space left on device를 함께 보세요.
빠른 체크리스트
image가 너무 크다고 느껴질 때는 아래 순서가 가장 실용적입니다.
- layer history를 본다
- base image와 dependency install 중 무엇이 더 큰지 구분한다
- build 전용 도구가 최종 image에 남는지 확인한다
.dockerignore와COPY범위를 점검한다- 최근 dependency와 asset 증가를 비교한다
- Docker tweak보다 packaging 단순화를 먼저 한다
FAQ
Q. Alpine이 항상 정답인가요?
아닙니다. size는 줄일 수 있지만 호환성, 디버깅, 패키지 생태계 특성도 같이 봐야 합니다.
Q. image size는 배포에만 영향이 있나요?
아닙니다. CI 시간, 로컬 개발 속도, node 디스크 사용량, registry 전송, cold start 체감에도 영향을 줍니다.
Q. 가장 빠른 첫 단계는 무엇인가요?
docker history로 가장 큰 layer를 확인하는 것입니다.
Q. multi-stage build는 언제 써야 하나요?
runtime image가 build toolchain 전체를 필요로 하지 않을 때 거의 항상 도움이 됩니다.
Read Next
- image 증가가 Docker host 저장 공간 문제로 이어진다면 Docker no space left on device를 보세요.
- stale layer 때문에 build 결과가 헷갈린다면 Docker build cache not updating를 확인하세요.
- image 변경 뒤 startup failure가 보인다면 Docker container keeps restarting로 이어가세요.
- 더 넓은 인프라 글은 Infra 카테고리에서 볼 수 있습니다.
Related Posts
- Docker no space left on device
- Docker build cache not updating
- Docker container keeps restarting
- GCP Cloud Run cold start
Sources:
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.