도커 이미지 용량을 줄이려고 docker image prune 을 돌렸는데 Total reclaimed space: 0B 만 돌아온다면, 기본 image prune 이 이름 없는(dangling) 이미지만 지우기 때문이고 종료된 컨테이너, 이미지, 빌드 캐시, 볼륨 순서로 풀어야 실제로 줄어듭니다.
안녕하세요? 정리하는 개발자 워니즈입니다. 이번 시간에는 비어 있는 Docker 에 흔한 개발 상태를 일부러 만들어두고 정리 명령을 하나씩 돌려서 각 명령이 실제로 무엇을 지우고 무엇을 남기는지 숫자로 재본 결과를 정리해보려고 합니다.
한 줄 요약 도커 이미지 용량은 어떤 prune 명령을 고르느냐보다 어떤 순서로 돌리느냐에 따라 명령 한 번에 되찾는 양이 달라졌습니다. 종료된 컨테이너, 이미지, 빌드 캐시, 볼륨 순서로 풀어야 앞 단계가 붙잡고 있던 몫이 뒤 단계에서 풀려납니다.
- 무엇을 쟀나 macOS Docker Desktop(Engine 29.8.0)에서 이미지 5종을 받고 같은 태그로 3회 재빌드하고 컨테이너 4개와 볼륨 2개를 만든 뒤 prune 명령 5개가 각각 회수한 도커 이미지 용량을 쟀습니다
- 예상과 달랐던 것 같은 태그로 세 번 빌드했는데 dangling 이미지가 0개였고 그래서 기본
image prune은 0B 를 회수했습니다 - 그래서 바꾼 순서 이미지를 먼저 지우자 빌드 캐시 회수 가능량이 36.38MB 에서 98.08MB 로 늘었고, 볼륨은 컨테이너가 남아 있는 동안
-a를 붙여도 0B 였습니다. 반대 순서로 돌리면 합계는 같고builder prune을 두 번 돌려야 했습니다(2026-09-29 재측정)
지금 내 PC 의 도커 이미지 용량이 어느 칸에 얼마나 쌓였는지는 아래 명령 한 줄로 먼저 확인할 수 있습니다.
docker system df
이번 재현 환경에서 컨테이너까지 만든 직후 찍은 출력은 이랬는데요, RECLAIMABLE 열이 지금 지워도 되는 몫이라서 이 열부터 보시면 됩니다.
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 3 687.1MB 335.3MB (48%)
Containers 4 2 98.3kB 12.29kB (12%)
Local Volumes 2 2 0B 0B
Build Cache 13 0 98.08MB 36.38MB
지금 상황에 맞춰 고르면 이렇습니다.
docker image prune이 0B 를 돌려준다면 이름 있는 안 쓰는 이미지까지 지우는docker image prune -a로 넘어갑니다(4장)- 빌드 캐시가 크게 남았다면 이미지를 먼저 지운 뒤
docker builder prune을 돌립니다(6장) - 볼륨이
-a를 붙여도 안 지워진다면 그 볼륨을 쓰는 컨테이너가 남아 있는지부터 봅니다(7장) - CI 러너처럼 작업이 끝나면 머신째 사라진다면 정리 순서를 고민하지 않아도 됩니다(10장)
목차
- 도커 이미지 용량은 어디에 쌓이는가
- 재현 실험은 빈 Docker 에서 이렇게 만들었습니다
- 1단계 지우기 전에 system df 로 센다
- 기본 image prune 은 왜 0B 를 돌려줬을까요?
- 2단계 종료된 컨테이너부터 풀고 이미지를 지운다
- 3단계 빌드 캐시를 비우고 볼륨은 마지막에 본다
- 볼륨은 왜 -a 를 붙여도 하나도 안 지워졌을까요?
- system prune 한 줄로 끝내면 안 되나요?
- 이번 재현으로 말할 수 없는 것
- 정리와 필자의 결론
1. 도커 이미지 용량은 어디에 쌓이는가
흔히 도커 이미지 용량이라고 뭉뚱그려 부르지만 Docker 가 디스크를 쓰는 곳은 네 칸으로 나뉘어 있고, docker system df 가 이 네 칸을 Images, Containers, Local Volumes, Build Cache 로 따로 보여줍니다(Docker 공식 문서 docker system df).
| 칸 | 무엇이 들어가나 | 지우는 명령 |
|---|---|---|
| Images | pull 로 받거나 직접 빌드한 이미지 | docker image prune |
| Containers | 컨테이너마다 이미지 위에 얹힌 쓰기 계층 | docker container prune |
| Local Volumes | 볼륨에 쌓인 데이터 | docker volume prune |
| Build Cache | BuildKit 이 빌드 중에 남긴 중간 산물 | docker builder prune |
이 글의 출발점이 된 실패부터 보여드리면, 빈 Docker 에 이미지 5종을 받고 같은 태그로 세 번 빌드하고 컨테이너 4개를 만든 뒤 기본 정리 명령을 돌린 결과가 아래입니다(2026-09-29 재측정, 9월 25일 첫 측정과 숫자가 한 자리도 다르지 않았습니다).
$ docker image prune -f
Total reclaimed space: 0B
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 3 687.1MB 335.3MB (48%)
Containers 4 2 98.3kB 12.29kB (12%)
Local Volumes 2 2 0B 0B
Build Cache 13 0 98.08MB 36.38MB
이미지 칸의 RECLAIMABLE 이 335.3MB 인데 기본 prune 은 0B 였고, 같은 상태에서 docker image prune -a -f 는 Total reclaimed space: 328.7MB 를 돌려줬습니다. SIZE 열은 그 칸이 지금 차지하는 총량이고 RECLAIMABLE 열이 지금 지워도 되는 몫이라, 명령을 고르기 전에 뒤쪽 열과 명령이 지우는 범위를 먼저 맞춰 봐야 합니다. 재현 절차는 2장에 그대로 있고 스크립트 한 번에 1분 남짓 걸렸습니다.

2. 재현 실험은 빈 Docker 에서 이렇게 만들었습니다
도커 정리 글에 실린 숫자는 보통 글쓴이 PC 한 대의 상태라서 독자가 자기 환경과 맞춰볼 방법이 없습니다. 그래서 이번에는 네 칸이 전부 0B 인 빈 Docker 에서 출발해 누구나 같은 상태를 다시 만들 수 있는 재현 실험으로 도커 이미지 용량의 변화를 쟀습니다.
| 항목 | 값 |
|---|---|
| 실행일 | 2026-09-25 첫 측정, 2026-09-29 같은 절차로 재측정(숫자 동일) |
| Docker Engine(Server) | 29.8.0 |
| 스토리지 드라이버 | overlayfs |
| 이미지 저장소 | containerd(driver-type io.containerd.snapshotter.v1) |
| 호스트 | macOS, Docker Desktop |
| 시작 상태 | 이미지, 컨테이너, 볼륨, 빌드 캐시 전부 0B |
재현은 아래 세 단계로 진행했고 각 단계가 끝날 때마다 docker system df 를 찍어서 네 칸이 어떻게 바뀌는지 남겼습니다.
- 흔히 쓰는 이미지 5종을 받았습니다. alpine:3.20, nginx:1.27-alpine, node:20-slim, python:3.12-slim, redis:7-alpine 입니다
- python:3.12-slim 위에 requests 를 설치하는 작은 이미지를
demo-app:latest라는 같은 태그로 세 번 빌드했고, 빌드마다--build-arg V값만 1, 2, 3 으로 바꿨습니다 - 컨테이너 4개를 만들었습니다. nginx 와 redis 는 실행 상태로 두고 redis 에는
cachedata라는 이름 붙은 볼륨을 달았고, alpine 은 한 번 실행하고 끝나는 컨테이너를 두 개 만들면서 그중 하나에-v /scratch로 익명 볼륨을 붙였습니다
빌드에 쓴 Dockerfile 은 아래 다섯 줄이고, Dockerfile 문법이 낯설다면 Dockerfile 의 이해 를 먼저 보시면 읽기 편합니다.
FROM python:3.12-slim
ARG V=1
RUN pip install --no-cache-dir requests==2.31.0 && echo "build $V" > /build.txt
COPY app.py /app/app.py
CMD ["python", "/app/app.py"]
같은 태그로 세 번 빌드하고 dangling 이미지를 세는 부분은 아래와 같은데, ctx 는 위 Dockerfile 과 한 줄짜리 app.py 가 들어 있는 빌드 디렉터리입니다.
for v in 1 2 3; do
docker build -q -t demo-app:latest --build-arg V=$v ctx
done
docker images -f dangling=true
3. 1단계 지우기 전에 system df 로 센다
첫 단계는 아무것도 지우지 않고 도커 이미지 용량이 어느 칸에 얼마나 있는지 세는 것인데요, 컨테이너까지 만든 직후 docker system df 를 돌리자 아래 출력이 나왔습니다(macOS Docker Desktop, Engine 29.8.0, 2026-09-25 실행).
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 3 687.1MB 335.3MB (48%)
Containers 4 2 98.3kB 12.29kB (12%)
Local Volumes 2 2 0B 0B
Build Cache 13 0 98.08MB 36.38MB
재현 단계마다 같은 명령을 찍어서 네 칸 중 크게 움직인 이미지와 빌드 캐시만 모아보면 아래 표처럼 됩니다.
| 시점 | 이미지 | 이미지 회수 가능 | 빌드 캐시 | 캐시 회수 가능 |
|---|---|---|---|---|
| 빈 상태 | 0개, 0B | 0B | 0개, 0B | 0B |
| 이미지 5종 pull | 5개, 669.2MB | 669.2MB | 0개, 0B | 0B |
| 같은 태그 3회 재빌드 | 6개, 687.1MB | 484.4MB | 13개, 98.08MB | 36.38MB |
| 컨테이너 4개 생성 | 6개, 687.1MB | 335.3MB | 13개, 98.08MB | 36.38MB |
직접 확인 1. 실행 중인 컨테이너는 nginx 와 redis 두 개뿐인데 Images 의 ACTIVE 는 3 으로 찍혔고, 남은 하나는 이미 종료된 컨테이너 두 개가 쓰고 있던 alpine 이었습니다. 종료된 컨테이너도 자기가 만들어진 이미지를 사용 중으로 붙잡고 있다는 뜻입니다. 컨테이너를 만든 뒤 이미지 회수 가능량이 484.4MB 에서 335.3MB 로 줄어든 것도 같은 이유로 읽힙니다.
반대로 컨테이너 칸 자체의 회수 가능량은 12.29kB 로 사실상 0 에 가까웠으니, 종료된 컨테이너는 그 자체로는 거의 공간을 차지하지 않으면서 이미지를 붙잡는 방식으로 도커 이미지 용량을 늘리고 있었던 셈입니다.

4. 기본 image prune 은 왜 0B 를 돌려줬을까요?
이 환경에는 지울 dangling 이미지가 처음부터 하나도 없었기 때문입니다. 공식 문서에 따르면 docker image prune 은 기본으로 dangling 이미지만 지우고 -a 를 붙여야 컨테이너가 참조하지 않는 이미지까지 지우는데, 기본 명령의 대상이 비어 있으니 회수량도 0B 일 수밖에 없었습니다(Docker 공식 문서 docker image prune).
직접 확인 2. 같은 태그로 세 번 빌드한 직후 docker images -f dangling=true 는 머리글 한 줄만 찍고 목록이 비어 있었고, 이미지 개수도 받은 5종에 demo-app:latest 하나를 더한 6개라서 앞선 두 번의 빌드 결과는 목록에 별도 이미지로 남지 않았습니다. 이 상태에서 docker image prune -f 를 돌리자 결과는 Total reclaimed space: 0B 였고 네 칸의 숫자도 한 자리도 바뀌지 않았습니다.
같은 태그로 다시 빌드하면 이전 이미지가 태그를 잃고 dangling 으로 남는다는 설명이 흔한데 이번 환경에서는 그 현상이 나타나지 않았습니다. 이 환경은 containerd 이미지 저장소를 쓰고 있었고, dangling 목록의 머리글도 IMAGE ID DISK USAGE CONTENT SIZE EXTRA 로 기존에 익숙한 형식과 달랐습니다(Docker Desktop containerd image store 문서).
기본
image prune이 0B 를 돌려주는 것은 명령이 고장 난 것이 아니라 지울 dangling 이미지가 없다는 뜻입니다. 돌리기 전에docker images -f dangling=true로 대상이 있는지부터 보면 헛걸음을 줄일 수 있습니다.
다만 이 관찰을 Docker 29 부터 항상 그렇다는 규칙으로 읽으면 곤란한데요, 필자가 확인한 것은 containerd 저장소를 쓰는 이 한 환경이고 기존 방식 저장소를 쓰는 서버에서는 같은 태그 재빌드가 dangling 을 남길 수 있어서 비교 실험 없이는 말할 수 없습니다. 앞선 두 번의 빌드 결과가 어디로 갔는지도 df 숫자만으로는 가를 수 없어서 미확인으로 남겨둡니다.
5. 2단계 종료된 컨테이너부터 풀고 이미지를 지운다
이번 재현에서 도커 이미지 용량이 실제로 크게 빠진 명령은 docker image prune -a 였고, 같은 상태에서 이 명령을 돌리자 Total reclaimed space: 328.7MB 가 찍혔습니다.
| 항목 | 정리 전 | image prune -a 후 |
|---|---|---|
| 이미지 개수 | 6개 | 3개 |
| 이미지 SIZE | 687.1MB | 149.2MB |
| 이미지 회수 가능 | 335.3MB | 0B |
| 빌드 캐시 회수 가능 | 36.38MB | 98.08MB |
직접 확인 3. 지워진 이미지는 어떤 컨테이너도 쓰지 않던 node:20-slim, python:3.12-slim, demo-app 세 개였고 남은 세 개는 nginx 와 redis 와 alpine 이었습니다. alpine 은 실행 중인 컨테이너가 하나도 없는데도 종료된 컨테이너 두 개가 붙잡고 있어서 -a 로도 지워지지 않았습니다.
그래서 2단계는 종료된 컨테이너를 먼저 정리하고 이미지를 지우는 순서입니다. 공식 문서 설명대로라면 종료된 컨테이너가 사라진 뒤에는 alpine 도 참조가 끊겨 -a 의 대상이 되지만 이 순서로 한 번 더 돌려서 alpine 이 빠지는지는 이번에 따로 재지 않았습니다.
docker ps -a --filter status=exited
docker container prune -f
docker image prune -a -f
docker system df
docker container prune 은 종료된 컨테이너를 전부 지우므로 다시 켜서 쓸 컨테이너가 섞여 있는지 첫 줄로 먼저 확인하고, -a 로 지운 이미지는 다음에 필요할 때 다시 받아야 하니 받기 어려운 이미지가 섞여 있다면 그것부터 빼두는 편이 안전합니다.
직접 확인 4. 숫자 하나가 맞지 않았는데, prune 이 보고한 회수량은 328.7MB 였지만 df 의 이미지 SIZE 는 687.1MB 에서 149.2MB 로 537.9MB 가 줄었습니다. 9월 29일 재측정 때 정리 직전에 docker system df -v 를 찍어 보니 이유가 보였습니다. RECLAIMABLE 335.3MB 는 지워질 세 이미지의 UNIQUE SIZE(demo-app 17.9MB, node:20-slim 315.2MB, python:3.12-slim 2.185MB)를 더한 값이고, demo-app 과 python:3.12-slim 이 같이 쓰던 SHARED SIZE 202.7MB 는 어느 이미지의 회수 가능 몫으로도 잡히지 않았습니다. 두 이미지가 함께 지워지면서 공유 계층도 풀렸으니 df 감소는 335.3MB 에 202.7MB 를 더한 538MB 쪽과 맞습니다. prune 보고값 328.7MB 가 UNIQUE 합계보다 6.6MB 작은 이유는 이번에도 확인하지 못했으니, 정리 계획을 세울 때는 prune 보고값과 df 전후 차이를 둘 다 적어두는 쪽이 나중에 헷갈리지 않습니다.
이미지를 처음부터 작게 만드는 방법은 Dockerfile 최적화 에서 레이어 캐싱과 베이스 이미지 선택을 다뤘는데, 지우는 것보다 덜 쌓는 쪽이 도커 이미지 용량 관리에서는 오래가는 방법이라고 생각합니다.
6. 3단계 빌드 캐시를 비우고 볼륨은 마지막에 본다
마지막 단계는 앞 단계가 풀어준 몫을 지우는 것인데요, 이미지를 정리한 직후 docker builder prune -f 를 돌리자 Total: 98.08MB 가 찍혔고 빌드 캐시 칸은 13개, 98.08MB 에서 0개, 0B 가 됐습니다(Docker 공식 문서 docker builder prune).
직접 확인 5. 이 글에서 순서를 강조하는 이유가 여기 있는데, 이미지를 지우기 전 빌드 캐시의 회수 가능량은 36.38MB 였지만 image prune -a 뒤에는 98.08MB 로 약 2.7배가 됐습니다. 이미지가 남아 있는 동안에는 빌드 캐시 일부가 회수 대상에서 빠져 있었다는 뜻입니다.
| 시점 | 빌드 캐시 전체 | 회수 가능 |
|---|---|---|
| 이미지 정리 전 | 13개, 98.08MB | 36.38MB |
| image prune -a 직후 | 13개, 98.08MB | 98.08MB |
| builder prune 직후 | 0개, 0B | 0B |
직접 확인 5-1(2026-09-29 반대 순서 실측). 같은 스크립트에서 순서만 바꿔 빌드 캐시를 먼저 비웠더니 docker builder prune -f 는 Total: 36.38MB 를 돌려줬고, 빌드 캐시 칸에는 6개, 61.7MB 가 회수 불가로 남았습니다. 그다음 docker image prune -a -f(보고값 330.8MB)를 돌리자 남은 61.7MB 가 회수 가능으로 바뀌었고, builder prune 을 한 번 더 돌려야 비워졌습니다.
| 순서 | 1차 builder prune | image prune -a | 2차 builder prune | 빌드 캐시 합계 |
|---|---|---|---|---|
| 이미지 먼저(이 글의 순서) | 돌리지 않음 | 328.7MB | 98.08MB | 98.08MB |
| 빌드 캐시 먼저 | 36.38MB | 330.8MB | 61.7MB | 98.08MB |
그래서 9월 25일 판에 적었던 “순서가 뒤 칸의 회수량까지 바꾼다”는 문장은 고칩니다. 두 순서의 빌드 캐시 합계는 98.08MB 로 같았고, 순서가 바꾼 것은 명령 한 번에 빠지는 양이었습니다. 빌드 캐시를 먼저 비우면 이미지를 지운 뒤 builder prune 을 한 번 더 돌려야 같은 양이 빠집니다. 이미지가 캐시를 붙잡는 내부 구조는 문서에서 확인하지 못해 미확인으로 둡니다.
공식 문서는 builder prune 이 기본으로 dangling 캐시만 지우고 -a 를 붙이면 사용하지 않는 캐시 전부를 지운다고 설명합니다. 이번 재현에서는 -a 없이 돌렸는데도 이미지를 먼저 지운 뒤라서 98.08MB 전부가 빠졌고, -a 를 붙였을 때 결과가 어떻게 달라지는지는 재지 않았습니다.
빌드 캐시는 도커 이미지 용량을 이루는 칸 가운데 잃는 것이 다음 빌드 시간뿐인 칸이라 주기적으로 돌려도 고민할 거리가 적고, CI 에서 빌드를 자주 태우는 환경이라면 예전에 정리한 Docker Build Pipeline 구성하기 처럼 빌드가 도는 자리에 이 명령을 같이 두는 방식을 생각해볼 수 있습니다.

7. 볼륨은 왜 -a 를 붙여도 하나도 안 지워졌을까요?
볼륨 두 개가 모두 컨테이너에 참조되고 있었기 때문입니다. 공식 문서는 docker volume prune 이 어떤 컨테이너도 참조하지 않는 볼륨만 지우고 기본으로는 익명 볼륨만 대상으로 삼으며, -a 를 붙이면 이름 붙은 볼륨까지 대상을 넓힌다고 설명합니다(Docker 공식 문서 docker volume prune).
직접 확인 6. 이미지와 빌드 캐시를 정리한 뒤 docker volume prune -f 와 docker volume prune -a -f 를 차례로 돌렸는데 둘 다 Total reclaimed space: 0B 였고, docker volume ls 에는 두 볼륨이 이름 그대로 남아 있었습니다.
| 볼륨 | 종류 | 참조하는 컨테이너 | volume prune | volume prune -a |
|---|---|---|---|---|
| cachedata | 이름 붙음 | redis 컨테이너(실행 중) | 남음 | 남음 |
| 61b2e0f02c17 로 시작하는 해시 | 익명 | 이름 없는 alpine 컨테이너(종료) | 남음 | 남음 |
-a 는 대상 범위를 이름 붙은 볼륨까지 넓힐 뿐이고 사용 중인 볼륨을 지우는 옵션이 아닙니다. 익명 볼륨은 컨테이너가 이미 종료됐는데도 그 컨테이너가 남아 있다는 이유만으로 지워지지 않았고 이것이 볼륨 정리를 컨테이너 정리 뒤에 두는 이유입니다.
직접 확인 7. 실험을 원상 복구하면서 컨테이너를 전부 지우고 docker system prune -a -f --volumes 를 돌렸더니 볼륨은 2개에서 1개로 줄었습니다. 9월 29일 재측정에서는 이름까지 찍었는데, Deleted Volumes: 아래에는 해시 이름의 익명 볼륨 하나만 나왔고 뒤이은 docker volume ls 에는 이름 붙은 cachedata 가 남아 있었습니다. 공식 문서대로 --volumes 는 익명 볼륨만 지웠고, 이름 붙은 볼륨은 docker volume rm cachedata 로 따로 지워야 했습니다.
볼륨은 네 칸 중 유일하게 지우면 데이터가 사라지는 칸이라서 도커 이미지 용량을 되찾겠다고 한 번에 밀어버리기보다 목록을 눈으로 보고 하나씩 판단하는 편이 낫고, 볼륨의 종류와 마운트 방식은 예전에 정리한 Volume 의 관리 에 더 자세히 있습니다.

8. system prune 한 줄로 끝내면 안 되나요?
끝낼 수는 있지만 이번 재현에서 드러난 차이를 보려면 나눠 돌리는 쪽이 맞다고 봅니다. docker system prune 은 종료된 컨테이너와 사용하지 않는 네트워크와 dangling 이미지와 빌드 캐시를 한 번에 지우고 -a 와 --volumes 로 범위를 넓히는 명령입니다(Docker 공식 문서 Prune unused Docker objects).
| 명령 | 지우는 대상(공식 문서) | 이번 재현 회수량 |
|---|---|---|
| docker image prune | dangling 이미지 | 0B |
| docker image prune -a | 컨테이너가 참조하지 않는 이미지 전부 | 328.7MB |
| docker builder prune | 빌드 캐시(기본은 dangling) | 98.08MB(이미지 정리 뒤) |
| docker volume prune | 참조 없는 익명 볼륨 | 0B |
| docker volume prune -a | 참조 없는 볼륨 전부 | 0B |
| docker system prune | 위 대상을 묶어서 | 개별 회수량으로는 재지 않음 |
한 줄로 돌리면 도커 이미지 용량이 어느 칸에서 얼마나 빠졌는지가 출력 하나로 뭉쳐서 다음에 같은 상황이 왔을 때 무엇이 원인이었는지 되짚기 어렵습니다. --volumes 를 붙여도 이름 붙은 볼륨은 남는다는 점도 7장에서 본 대로라서, 한 줄이면 다 지워진다는 기대 자체가 맞지 않습니다.
필자는 도커 이미지 용량을 정리할 때 단계마다 docker system df 를 한 번씩 찍어 네 칸의 변화를 남기는 쪽을 택했는데, 명령 하나가 늘어날 뿐이지만 3장의 표 같은 기록이 쌓이면 자기 환경에서 어느 칸이 주로 불어나는지가 보이기 시작합니다.

9. 이번 재현으로 말할 수 없는 것
재현 실험은 조건을 통제한 대신 범위가 좁아서, 확인하지 못한 것을 지우지 않고 아래에 그대로 적어둡니다.
| 항목 | 상태 | 이유 |
|---|---|---|
| 기존 방식 이미지 저장소에서도 dangling 이 0개인가 | 미확인 | containerd 저장소 한 환경만 돌렸습니다 |
| 빌드 캐시를 먼저 지우면 회수량이 얼마인가 | 확인(2026-09-29) | 1차 36.38MB, 이미지 정리 뒤 2차 61.7MB, 합계는 이 글의 순서와 같은 98.08MB |
| 종료된 컨테이너를 지운 뒤 alpine 이 -a 로 빠지는가 | 미확인 | 문서상 동작이고 따로 재지 않았습니다 |
| prune 보고값 328.7MB 와 df 감소 537.9MB 의 차이 | 일부 확인(2026-09-29) | 공유 계층 202.7MB 가 RECLAIMABLE 에 잡히지 않아서입니다. prune 보고값과 UNIQUE 합계의 6.6MB 차이는 미확인 |
| builder prune 에 -a 를 붙이면 달라지는가 | 미확인 | -a 없이만 돌렸습니다 |
| macOS 쪽 Docker Desktop 가상 디스크 파일이 같이 줄어드는가 | 미확인 | 호스트 파일 크기를 재지 않았습니다 |
규모도 작았습니다. 이미지 5종에 수백 MB 수준의 실험이라 이미지가 수십 개 쌓인 환경에서 칸별 비율이 같게 나온다고 말할 근거는 없고, 이 글이 도커 이미지 용량 정리에서 말할 수 있는 것은 칸 사이의 관계와 지우는 순서까지입니다.
10. 정리: 누구에게 맞고 누구에게는 굳이인가, 그리고 필자는 이렇게 봅니다
이 정리 순서가 잘 맞는 쪽은 Docker Desktop 으로 개발하면서 빌드를 자주 돌리고 한 번 띄우고 끝나는 컨테이너가 쌓이는 환경인데, 종료된 컨테이너가 이미지를 붙잡고 그 이미지가 빌드 캐시를 붙잡는 구조가 이번 재현과 같다면 순서만 바꿔도 명령 한 번에 되찾는 도커 이미지 용량이 달라집니다.
굳이인 쪽도 있어서, 작업이 끝나면 머신째 사라지는 CI 러너라면 정리 순서를 고민할 이유가 적고 기존 방식 저장소를 쓰는 서버라면 이 글의 0B 관찰을 그대로 옮기지 말고 dangling 목록부터 세어보는 것이 먼저일 것 같습니다.
필자의 결론
도커 이미지 용량 정리는 명령을 아는 문제가 아니라 붙잡힌 순서대로 푸는 문제라고 봅니다. 기본 image prune 의 0B 도, 빌드 캐시의 2.7배도, -a 를 붙여도 남은 볼륨도 전부 앞 칸이 뒤 칸을 붙잡고 있어서 생긴 숫자였습니다.
그래서 필자는 정리 순서를 종료된 컨테이너, 이미지, 빌드 캐시, 볼륨으로 고정하고 단계마다 docker system df 를 찍어 남기기로 했습니다. 9월 29일에 같은 스크립트로 반대 순서를 돌려 보니 빌드 캐시 합계는 같았고 builder prune 을 두 번 돌려야 했으니, 이 순서의 이득은 총량이 아니라 한 번에 끝나는 데 있습니다. 기존 방식 저장소와의 비교는 containerd 가 아닌 환경을 따로 준비해야 해서 아직 하지 않았고, 이번에는 한 환경의 숫자를 있는 그대로 남기는 데서 멈췄습니다.
오늘 해 볼 일 하나만 고르면, 정리 명령을 돌리기 전에 docker system df 를 한 번 찍어 RECLAIMABLE 열이 가장 큰 칸이 어디인지부터 확인해 보세요.
함께 보면 좋은 글
- Dockerfile 최적화: 이미지를 처음부터 작게 만드는 빌드 쪽 방법
- Volume 의 관리: 볼륨 종류와 마운트 방식, 지우기 전에 볼 것
- Dockerfile 의 이해: 이번 재현에 쓴 Dockerfile 문법의 기초
도커 디스크가 찼을 때 여러분은 어떤 명령부터 돌리시나요? 정리 순서를 정해 두셨는지, 그때그때 system prune 한 줄로 끝내시는지 댓글로 알려 주세요.
새 글이 올라오면 Threads @wonizz.ai 에도 올립니다. 팔로우해 두면 피드에서 바로 볼 수 있습니다.