콘텐츠로 건너뛰기

[DevOps] 도커 이미지 용량 정리 3단계

도커 이미지 용량을 줄이려고 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장)

목차

  1. 도커 이미지 용량은 어디에 쌓이는가
  2. 재현 실험은 빈 Docker 에서 이렇게 만들었습니다
  3. 1단계 지우기 전에 system df 로 센다
  4. 기본 image prune 은 왜 0B 를 돌려줬을까요?
  5. 2단계 종료된 컨테이너부터 풀고 이미지를 지운다
  6. 3단계 빌드 캐시를 비우고 볼륨은 마지막에 본다
  7. 볼륨은 왜 -a 를 붙여도 하나도 안 지워졌을까요?
  8. system prune 한 줄로 끝내면 안 되나요?
  9. 이번 재현으로 말할 수 없는 것
  10. 정리와 필자의 결론

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 를 찍어서 네 칸이 어떻게 바뀌는지 남겼습니다.

  1. 흔히 쓰는 이미지 5종을 받았습니다. alpine:3.20, nginx:1.27-alpine, node:20-slim, python:3.12-slim, redis:7-alpine 입니다
  2. python:3.12-slim 위에 requests 를 설치하는 작은 이미지를 demo-app:latest 라는 같은 태그로 세 번 빌드했고, 빌드마다 --build-arg V 값만 1, 2, 3 으로 바꿨습니다
  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 에 가까웠으니, 종료된 컨테이너는 그 자체로는 거의 공간을 차지하지 않으면서 이미지를 붙잡는 방식으로 도커 이미지 용량을 늘리고 있었던 셈입니다.
컨테이너까지 만든 재현 환경에서 docker system df 를 실행한 터미널 출력, RECLAIMABLE 열에 이미지 335.3MB 회수 가능이 찍힌 화면

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 구성하기 처럼 빌드가 도는 자리에 이 명령을 같이 두는 방식을 생각해볼 수 있습니다.
이미지 정리 전 36.38MB였던 빌드 캐시 회수 가능량이 image prune -a 이후 98.08MB로 늘어난 것을 보여주는 막대 차트

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 의 관리 에 더 자세히 있습니다.
docker volume prune 과 volume prune -a 를 실행한 뒤에도 docker volume ls 에 볼륨 두 개가 그대로 남아 있는 터미널 출력

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장의 표 같은 기록이 쌓이면 자기 환경에서 어느 칸이 주로 불어나는지가 보이기 시작합니다.
image prune, image prune -a, builder prune, volume prune, volume prune -a 다섯 명령이 이번 재현에서 각각 회수한 도커 이미지 용량을 나란히 비교한 막대 차트

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 열이 가장 큰 칸이 어디인지부터 확인해 보세요.

함께 보면 좋은 글

도커 디스크가 찼을 때 여러분은 어떤 명령부터 돌리시나요? 정리 순서를 정해 두셨는지, 그때그때 system prune 한 줄로 끝내시는지 댓글로 알려 주세요.

새 글이 올라오면 메일로 받아 보실 수 있습니다.

이 글을 쓴 사람

인프라와 DevOps를 실무로 다루면서 겪은 것을 기록합니다. Docker, Kubernetes, AWS, 그리고 AI 도구를 실제로 써 보고 남기는 로그입니다.

Threads·X

새 글이 올라오면 Threads @wonizz.ai 에도 올립니다. 팔로우해 두면 피드에서 바로 볼 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다