Dùng Docker được vài tháng, nhiều người giật mình khi thấy ổ đĩa VPS vơi đi một cách khó hiểu: vài chục GB “bốc hơi” dù chẳng cài thêm gì. Thủ phạm thường là chính Docker — image cũ chất chồng, container đã dừng nằm lại, volume mồ côi và cache build tích tụ. Bài cuối của series sẽ hướng dẫn bạn dọn dẹp Docker một cách có hệ thống và an toàn, kèm các biện pháp tối ưu để hệ thống luôn gọn nhẹ.
Nguyên tắc xuyên suốt khi dọn dẹp Docker là: đo trước, dọn từng lớp một, kiểm tra lại sau. Tuyệt đối không gõ lệnh prune bừa trên server đang chạy hệ thống thật khi chưa biết nó sẽ xóa những gì. Toàn bộ quá trình dưới đây được thực hành thật trên máy lab — nơi tui đã cố tình “bày rác” (tải thừa vài image, tạo sẵn container và volume không dùng) để bạn thấy rõ hiệu quả từng lệnh.
Mục lục bài viết:
- 1. Vì sao cần dọn dẹp và tối ưu Docker trên VPS?
- 2. Đo trước khi dọn: docker system df
- 3. Lớp 1: xóa container đã dừng bằng container prune
- 4. Lớp 2: xóa image thừa bằng image prune
- 5. Lớp 3: dọn volume thừa — bước nguy hiểm nhất
- 6. Lớp 4: dọn bộ nhớ đệm build bằng builder prune
- 7. Dọn tất cả trong một lệnh: docker system prune
- 8. Tối ưu từ gốc: để Docker sinh ít rác hơn
- 9. Những sai lầm khi dọn dẹp cần tránh
- 10. Lời kết: khép lại series Docker cơ bản
1. Vì sao cần dọn dẹp và tối ưu Docker trên VPS?
Muốn dọn dẹp Docker hiệu quả, trước hết phải hiểu dung lượng bị chiếm bởi những gì. Có bốn nguồn phình dung lượng chính. Thứ nhất là image: mỗi lần pull một phiên bản mới hay build lại image, bản cũ vẫn nằm nguyên trên đĩa; vài image nền lớn (ubuntu, mysql bản đầy đủ) đã nặng hàng trăm MB mỗi bản. Thứ hai là container đã dừng: chúng giữ lại lớp ghi của mình và đặc biệt là file log, container nào “nói nhiều” thì log phình rất nhanh.
Thứ ba là volume mồ côi — các volume không còn container nào gắn vào sau nhiều lần tạo/xóa container thử nghiệm, trong đó có cả volume ẩn danh sinh ra tự động. Thứ tư là build cache: các layer trung gian khi build image bằng Dockerfile. Một khái niệm cần biết là dangling image: image không còn tag nào trỏ tới (thường là phiên bản cũ sau khi bạn build lại cùng một tag) — chúng là rác thuần túy và là đối tượng dọn đầu tiên.
2. Đo trước khi dọn: docker system df
Lệnh tổng quan nhất khi dọn dẹp Docker là docker system df — nó cho biết Docker đang chiếm bao nhiêu dung lượng, chia theo từng loại tài nguyên và bao nhiêu trong đó có thể thu hồi (RECLAIMABLE):

Kết hợp với danh sách chi tiết để biết chính xác “rác” gồm những gì trước khi ra tay:

Trên máy lab đang có sẵn vài image thừa (httpd, ubuntu tải về mà không dùng), ba container rác đã dừng và các image phục vụ những bài trước của series. Con số RECLAIMABLE ở lệnh df là kim chỉ nam: nó cho bạn kỳ vọng thực tế về lượng dung lượng sẽ lấy lại được, và là mốc để đối chiếu sau khi dọn xong.
Hai cột còn lại trong bảng df cũng đáng chú ý: TOTAL là tổng số lượng tài nguyên thuộc mỗi loại đang tồn tại trên máy, còn ACTIVE là số đang thực sự được ít nhất một container sử dụng. Chênh lệch lớn giữa TOTAL và ACTIVE chính là dấu hiệu của rác tích tụ — ví dụ 15 image mà chỉ 3 image đang ACTIVE nghĩa là 12 image còn lại hoặc là để dành, hoặc là rác chờ dọn.
3. Lớp 1: xóa container đã dừng bằng container prune
Quy trình dọn dẹp Docker bắt đầu từ lớp an toàn nhất: container đã dừng. Lệnh docker container prune xóa toàn bộ container đang ở trạng thái dừng/exited, giữ nguyên container đang chạy. Mặc định lệnh sẽ hỏi xác nhận (gõ y), thêm cờ -f khi bạn đã chắc chắn hoặc khi chạy trong script:

Ba container rác đã biến mất khỏi danh sách docker ps -a, kèm thông báo tổng dung lượng thu hồi được. Lưu ý đi kèm việc xóa container là lớp ghi và log của chúng cũng mất — nếu cần điều tra sự cố của một container đã chết, hãy xem log và sao lưu trước khi prune. Trên server production, một thói quen tốt là luôn chạy docker ps -a đọc kỹ danh sách trước khi xác nhận xóa.
Nếu muốn nhìn sâu hơn trước khi quyết định dọn gì, biến thể docker system df -v sẽ liệt kê chi tiết từng image, từng container và từng volume cùng dung lượng của chúng, thay vì chỉ cho con số tổng. Bảng chi tiết này đặc biệt hữu ích trên server nhiều dự án: bạn sẽ thấy ngay image nào đang chiếm vài GB, container nào giữ file log khổng lồ, và ra quyết định dọn có chọn lọc thay vì prune tất cả trong lo lắng.
4. Lớp 2: xóa image thừa bằng image prune
Sau container, quá trình dọn dẹp Docker chuyển sang lớp image với hai mức cần phân biệt thật rõ. Mức nhẹ: docker image prune chỉ xóa dangling image — những image không còn tag, chắc chắn không ai dùng để chạy container mới theo tên được nữa:

Mức mạnh: thêm cờ -a thành docker image prune -a sẽ xóa mọi image không còn container nào tham chiếu — kể cả image có tag tử tế như các bản nginx cũ bạn đang “để dành”. Mức này giải phóng rất nhiều dung lượng nhưng hãy cân nhắc: image đã xóa muốn dùng lại phải pull/build lại từ đầu, và nếu đó là phiên bản dùng để rollback khi bản mới lỗi, bạn vừa vứt mất phao cứu sinh. Kinh nghiệm thực tế: trên máy phát triển cứ mạnh tay; trên server production hãy giữ lại ít nhất một, hai phiên bản gần nhất của mỗi ứng dụng.
Để prune có chọn lọc hơn, hãy dùng bộ lọc thời gian --filter "until=720h": chỉ những image không dùng và đã tồn tại quá 720 giờ (30 ngày) mới bị xóa, các image mới xuất hiện gần đây được giữ lại nguyên vẹn. Tương tự, bộ lọc theo nhãn --filter "label=keep=true" cho phép bạn đánh dấu những image tuyệt đối không được động vào ngay từ khi build. Kết hợp hai bộ lọc này là cách các đội vận hành chuyên nghiệp đặt lịch dọn tự động mà vẫn ngủ ngon.
5. Lớp 3: dọn volume thừa — bước nguy hiểm nhất
docker volume prune xóa các volume không còn container nào gắn vào. Khác với image (tải lại được), volume chứa dữ liệu thật và duy nhất — xóa nhầm volume của database là mất dữ liệu vĩnh viễn, không có cách khôi phục. Đây là bước phải thận trọng nhất trong toàn bộ quy trình dọn dẹp Docker:

Volume rác của máy lab đã được dọn. Nhưng hãy khắc ghi quy tắc: trước khi prune volume trên bất kỳ hệ thống nào có dữ liệu quan trọng, liệt kê volume bằng docker volume ls, đối chiếu với các hệ thống đang chạy, và sao lưu dữ liệu quan trọng ra ngoài Docker trước. Nếu không chắc chắn 100% về một volume, hãy để nó yên — dung lượng của một volume trống thường rất nhỏ so với rủi ro mất dữ liệu.
6. Lớp 4: dọn bộ nhớ đệm build bằng builder prune
Nguồn rác thứ tư đã nhắc ở đầu bài — cache của quá trình build — không nằm trong các lệnh prune phía trên ở mức mặc định của chúng. Mỗi lần docker build, Docker lưu lại các layer trung gian và cả dữ liệu tải về để lần build sau nhanh hơn; sau nhiều tháng, phần cache này có thể phình lên hàng GB, đặc biệt trên máy chuyên build image cho nhiều dự án.
Dọn riêng phần này bằng lệnh docker builder prune. Lệnh sẽ hỏi xác nhận và hiển thị danh sách các mục cache có thể thu hồi trước khi xóa; thêm cờ -a để xóa toàn bộ cache thay vì chỉ phần không dùng gần đây, và bộ lọc --filter "until=168h" nếu muốn giữ lại cache của tuần gần nhất. Cái giá phải trả sau khi dọn sạch cache là lần build tiếp theo chậm hơn vì phải làm lại từ đầu — vì vậy trên máy build production, hãy dọn cache theo lịch thưa (hàng tháng) thay vì hàng ngày.
7. Dọn tất cả trong một lệnh: docker system prune
Khi muốn dọn dẹp Docker tổng lực trong một lần, docker system prune gộp các lớp dọn phía trên (container đã dừng, network không dùng, dangling image) vào một lệnh; thêm -a để quét cả image không dùng, và --volumes nếu muốn kèm cả volume. Chạy nốt lệnh này trên máy lab và đo lại bằng docker system df:

Đối chiếu hai lần đo: phần lớn dung lượng có thể thu hồi đã được giải phóng, những gì còn lại là các image đang thật sự phục vụ công việc. Trên VPS, bạn có thể đặt lịch dọn định kỳ mức nhẹ bằng cron — nhưng hãy giữ ở mức an toàn và kèm bộ lọc thời gian, ví dụ chỉ dọn những tài nguyên không dùng trong 30 ngày gần nhất: docker system prune -af --filter "until=720h". Cách này vừa giữ máy gọn, vừa tránh xóa nhầm thứ vừa mới dùng gần đây.
Để hình dung cụ thể, một dòng crontab dọn dẹp an toàn hàng tuần cho VPS thường trông như sau: 0 3 * * 0 docker system prune -af --filter "until=720h" >> /var/log/docker-prune.log 2>&1 — chạy lúc 3 giờ sáng Chủ nhật, chỉ dọn tài nguyên không dùng quá 30 ngày, và ghi lại kết quả vào file log để sáng hôm sau bạn kiểm tra được nó đã xóa những gì. Tuyệt đối tránh việc đặt lịch cho các biến thể kèm --volumes khi chưa có cơ chế sao lưu dữ liệu độc lập.
8. Tối ưu từ gốc: để Docker sinh ít rác hơn
Dọn dẹp Docker định kỳ là cần thiết, nhưng giỏi hơn nữa là giảm rác ngay từ khi sinh ra. Năm thói quen sau đây có tác dụng lâu dài nhất:
- Chọn image nền nhỏ: ưu tiên các bản
alpinehoặcslimkhi viết Dockerfile — chênh lệch có thể từ hơn 1 GB xuống dưới 100 MB cho mỗi image. - Dọn cache ngay trong cùng một layer: khi cài gói bằng
RUN, hãy xóa cache của trình quản lý gói trong chính lệnh đó (ví dụapt-get clean,pip --no-cache-dir). Xóa ở layer sau không làm image nhỏ đi vì layer cũ vẫn chứa dữ liệu. - Luôn có .dockerignore: ngăn file rác, thư mục
.git,node_moduleschui vào ngữ cảnh build — build vừa nhanh vừa nhẹ, như đã thực hành ở Bài 2. - Dùng –rm cho container tạm: các container chạy thử một lần (kiểm tra, xử lý file) hãy thêm cờ
--rmđể Docker tự xóa chúng khi kết thúc, khỏi tích tụ container chết. - Giới hạn dung lượng log: mặc định log của container không bị giới hạn và là nguồn phình âm thầm đáng sợ nhất — xem chi tiết ở đoạn ngay dưới đây.
Về log, hãy hình dung mức độ nghiêm trọng: một container web gặp lỗi lặp liên tục có thể ghi vài GB log chỉ trong một đêm, và vì log nằm trong thư mục dữ liệu của Docker nên lệnh df thường khiến người ta ngỡ Docker “tự phình”.
Cách xử lý gốc rễ là cấu hình trong file /etc/docker/daemon.json của máy chủ: "log-driver": "json-file", "log-opts": {"max-size": "10m", "max-file": "3"} rồi khởi động lại dịch vụ Docker — từ đó mỗi container chỉ giữ tối đa 3 file log, mỗi file 10 MB, tự luân phiên ghi đè. Với container cá biệt cần mức khác, ghi đè ngay trong lệnh chạy bằng cờ --log-opt max-size=50m. Định kỳ kiểm tra nhanh container nào đang giữ log lớn cũng là một thói quen vận hành tốt.
Ngoài ra, với các ứng dụng cần biên dịch/build từ mã nguồn, kỹ thuật multi-stage build trong Dockerfile (build ở stage đầy đủ công cụ, chỉ copy thành phẩm sang stage chạy siêu nhẹ) là cách tối ưu image mạnh nhất — rất đáng tìm hiểu sau khi bạn đã vững những kiến thức trong series này.
Để thấy sức mạnh của multi-stage, hãy hình dung một ứng dụng Node.js: build trong image đầy đủ với toàn bộ công cụ biên dịch cho ra image hơn 1 GB; với multi-stage, stage cuối chỉ gồm runtime nhỏ và thư mục thành phẩm đã build — image co xuống còn khoảng 150 MB, tức nhẹ hơn gần 7 lần. Image càng nhỏ thì pull càng nhanh, bề mặt tấn công càng hẹp và chi phí lưu trữ trên registry càng thấp — đó là lý do multi-stage được xem là chuẩn mực cho Dockerfile production hiện nay. Chi tiết các lệnh prune và tùy chọn của chúng có tại tài liệu quản lý tài nguyên của Docker.
9. Những sai lầm khi dọn dẹp cần tránh
Bên cạnh kỹ thuật, dọn dẹp Docker an toàn còn nằm ở việc tránh những sai lầm kinh điển dưới đây.
- Prune theo thói quen mà không đo trước: luôn chạy
docker system dfvà liệt kê tài nguyên trước. Lệnh prune không có nút hoàn tác. - Dọn sạch image trên production: xóa mất image phiên bản cũ đồng nghĩa mất khả năng rollback nhanh khi bản mới gặp sự cố. Hãy giữ lại các phiên bản gần nhất.
- Kèm –volumes cho system prune một cách vô thức: đây là tổ hợp nguy hiểm nhất — nó có thể xóa volume dữ liệu mà container tham chiếu vừa bị dọn ở cùng lệnh. Chỉ dùng khi đã sao lưu và chắc chắn.
- Dọn xong mà đĩa vẫn đầy: lúc này thủ phạm có thể nằm ngoài Docker (log hệ thống, file sao lưu cũ). Dùng
du -h --max-depth=1 /và kiểm tra thư mục dữ liệu của Docker để khoanh vùng tiếp.
10. Lời kết: khép lại series Docker cơ bản
Quy trình dọn dẹp Docker chuẩn chỉ gói gọn trong bốn bước: đo bằng system df, dọn container đã dừng, dọn image thừa theo mức độ thận trọng phù hợp, và chỉ động vào volume khi đã chắc chắn có sao lưu. Cộng thêm các thói quen tối ưu từ gốc, hệ thống Docker của bạn sẽ luôn gọn gàng và dễ kiểm soát.
Đây cũng là bài cuối của series Docker cơ bản trên phongdinh.info.vn. Từ các lệnh đầu tiên, viết Dockerfile, quản lý dữ liệu bằng Volume, thiết kế Network, xuất bản image lên Docker Hub cho đến dọn dẹp và tối ưu — bạn đã có đủ nền tảng để tự triển khai các ứng dụng thật bằng Docker trên VPS của mình. Chúc bạn thực hành vui vẻ, và hẹn gặp lại ở các series nâng cao tiếp theo!

Thảo luận 0 bình luận Viết bình luận Thu gọn