Hình dung bạn muốn biết một chung cư "nặng" bao nhiêu chỗ. Hỏi từng hộ "nhà anh rộng bao nhiêu", ai cũng kể cả cầu thang, móng và mái chung — cộng lại thành con số khổng lồ, đếm trùng phần dùng chung. Hỏi sổ sách của ban quản lý thì gọn hơn, nhưng họ quên mất cái tầng hầm mà cả toà đang chất đồ (nhật ký). Chỉ có đo thẳng cả khu đất mới ra con số thật. Hỏi Docker chiếm bao nhiêu đĩa cũng đúng ba cách đó — và chúng cho ba câu trả lời khác nhau đủ để dẫn bạn đi sai hướng.

Cách hỏi Trả lời
Cộng dồn cột SIZE của docker images 420 MB
docker system df (cộng cả bốn dòng) 217 MB
du -sm /var/lib/docker 294 MB

Con số thứ ba là con số thật. Hai con số kia sai theo hai hướng ngược nhau.

Vì sao 420 MB là quá cao

Cột SIZE của docker images tính toàn bộ dung lượng của image, kể cả những lớp nó dùng chung với image khác. Bốn image dựng từ cùng một nền:

REPOSITORY   TAG   SIZE     SHARED SIZE   UNIQUE SIZE
bien-the     a     64.4MB   64.38MB       11B
bien-the     b     64.4MB   64.38MB       11B
bien-the     c     64.4MB   64.38MB       11B
co-so        1     64.4MB   64.38MB       0B

Bốn dòng, mỗi dòng 64,4 MB, cộng lại 257 MB. Trên đĩa chúng tốn 64,38 MB cộng thêm 33 byte.

Cột UNIQUE SIZE mới là thứ bạn thu hồi được nếu xoá image đó. Xoá bien-the:a giải phóng 11 byte. Đây là lý do "dọn image cho nhẹ máy" thường không có tác dụng gì: bạn xoá mười image cùng nền và giải phóng vài trăm byte.

Xem cột đó bằng:

docker system df -v

Muốn thật sự lấy lại chỗ thì phải xoá cái nền — nghĩa là mọi image dựa trên nó cũng phải đi. Đó cũng là lập luận ngược lại của phần 10: dùng chung một base image càng nhiều thì tổng dung lượng càng nhỏ, dù bảng docker images trông có vẻ khổng lồ.

Vì sao 217 MB là quá thấp

docker system df cộng bốn dòng của chính nó:

Images          164.9MB
Containers          0B
Local Volumes   52.43MB
Build Cache         38B

Nhưng thư mục thật là 294 MB. Thiếu 77 MB. Chúng ở đây:

Thư mục Dung lượng
/var/lib/docker/overlay2 190 MB
/var/lib/docker/containers 52 MB
/var/lib/docker/volumes 51 MB
buildkit + linh tinh 1 MB

Dòng giữa là thủ phạm chính. Bên trong nó:

53.469.925 byte   .../0c0e4914...-json.log

Năm mươi ba megabyte nhật ký container, trong khi docker system df ghi cột Containers là 0 B. Đây đúng là chuyện phần 29 đã đo: log nằm ngoài mọi con số kế toán của Docker, và mặc định json-file không xoay vòng nên nó lớn mãi.

Phần chênh còn lại nằm giữa Images 164,9 MB và overlay2 190 MB — đó là lớp ghi của các container đang chạy cùng phần siêu dữ liệu của image, những thứ system df gộp vào chỗ khác hoặc bỏ qua.

Cách đếm đáng tin

Trên máy chủ Linux, đừng hỏi Docker — hỏi hệ thống tệp:

sudo du -sh /var/lib/docker
sudo du -sm /var/lib/docker/* | sort -rn | head

Hai lệnh này trả lời đúng câu hỏi bạn đang hỏi: ổ đĩa mất bao nhiêu chỗ. Rồi mới dùng docker system df -v để biết trong đó cái gì xoá được.

Trên Docker Desktop macOS hoặc Windows thì /var/lib/docker nằm trong máy ảo, bạn không du thẳng được. Cách vào:

docker run --rm --privileged --pid=host alpine \
  nsenter -t 1 -m -u -i -n -- du -sm /var/lib/docker

Và nhớ rằng trên Desktop còn một lớp nữa: tệp ảnh đĩa của máy ảo. Nó không tự co lại khi bạn xoá dữ liệu bên trong — Docker Desktop có nút thu gọn riêng trong phần cài đặt.

Bốn vùng, bốn cách xử lý khác nhau

Vùng Đo bằng Dọn bằng
overlay2 (lớp image) docker system df -v, cột UNIQUE SIZE docker image prune -a
overlay2 (lớp ghi) docker ps -s docker container prune
volumes docker system df -v docker volume prune -a (nhớ -a)
containers (log) du trên LogPath không dọn được — phải cấu hình lại

Dòng cuối là dòng hay bị bỏ sót nhất, và như phần 45 đã đo, không lệnh prune nào chạm tới nó.

Ba con số nên theo dõi

Nếu bạn giám sát máy chủ chạy Docker, ba thứ này đáng đưa vào cảnh báo:

  1. du -sm /var/lib/docker — con số thật, và là con số làm ổ đầy.
  2. Tệp log lớn nhất — nó lớn tuyến tính theo thời gian nếu chưa xoay vòng.
  3. Build cache — trên máy CI đây thường là vùng phình nhanh nhất.

Đừng cảnh báo dựa trên docker images: nó gần như luôn báo cao hơn thực tế vài lần, và bạn sẽ quen với việc bỏ qua cảnh báo.

Muốn tự so ba con số trên máy mình, hỏi cả ba nguồn rồi nhìn du chia theo thư mục:

# so ba con so tren chinh may ban
echo "docker images cong don:"
docker images --format '{{.Size}}' | numfmt --from=iec --suffix=B 2>/dev/null | head -1 >/dev/null
docker system df
sudo du -sm /var/lib/docker/* 2>/dev/null | sort -rn | head -5

Nếu containers xuất hiện trong năm dòng đầu, bạn đang mất đĩa cho nhật ký. Nếu overlay2 lớn gấp nhiều lần con số Images mà system df báo, phần thừa là lớp ghi của container — dấu hiệu ứng dụng đang ghi vào chính container thay vì vào volume.

Mẫu số chung

Bài học đầu tiên, đọc thẳng từ 420 / 217 / 294 MB: cùng một đại lượng đo ba cách cho ba con số, vì mỗi công cụ đếm cái tiện cho mục đích của nó chứ không đếm "sự thật" — nên phải biết mỗi cái gồm và bỏ những gì, và khi chúng bất đồng thì đi tới nền đất thật. docker images đếm trùng lớp dùng chung (góc nhìn từng-image), docker system df bỏ sót nhật ký (kế toán riêng của Docker), du mới đo đúng cái ổ đĩa mất chỗ. Cùng chuyện "một số vô nghĩa nếu không kèm định nghĩa" ở khắp nơi: du khác df, RSS khác VSZ khác PSS khi đo bộ nhớ, kích thước logic khác vật lý của một CSDL, .git phình khác cây làm việc. Nguyên tắc: khi các công cụ cho số khác nhau, chúng đang trả lời những câu hỏi khác nhau — tìm cái trả lời đúng câu của bạn, và với "ổ đĩa còn bao nhiêu" thì nền đất (hệ thống tệp) là trọng tài cuối cùng.

Điều thứ hai, đọc từ "ba image 64 MB chỉ tốn thêm 33 byte": khi tài nguyên được dùng chung, chi phí thêm một cái rẻ bèo, nhưng chỗ thu hồi được khi xoá một cái cũng bé tí — bạn chỉ lấy lại được phần riêng. Thêm image thứ tư trên cùng nền tốn 11 byte; xoá nó cũng chỉ giải phóng 11 byte, vì phần móng vẫn được ba image kia giữ. Nên "dọn cho nhẹ máy" thất bại trừ khi gỡ cái nền — và mọi thứ đứng trên nó. Cùng luật ấy ở mọi thứ chia sẻ có đếm-tham-chiếu: thư viện dùng chung, khối copy-on-write đã dedup, một dependency nhiều nơi cùng cần, một cache CDN — thêm thì rẻ, xoá một người dùng chẳng trả lại gì, chỉ khi người tham chiếu cuối cùng biến mất mới thật sự thu hồi (đúng cơ chế refcount/GC). Nguyên tắc: với tài nguyên dùng chung, chi phí biên khác hẳn lượng thu hồi được — xoá chỉ giải phóng thứ không còn ai giữ.

Phần sau chuyển sang Docker Compose: gõ up thì thật ra chuyện gì xảy ra.