คำตอบสั้น ๆ: ตรวจว่า Docker ใช้พื้นที่ดิสก์ไปกับอะไร แล้วลบ Image, Container, Build Cache ที่ไม่ใช้ด้วยคำสั่ง prune อย่างปลอดภัยโดยไม่ทำข้อมูลใน Volume หาย
คู่มือนี้อธิบาย Docker ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
เซิร์ฟเวอร์ที่ใช้ Docker มาสักระยะมักมีพื้นที่ดิสก์ลดลงเรื่อย ๆ โดยไม่รู้ตัว เพราะทุกครั้งที่ดึง Image เวอร์ชันใหม่ Image เก่ายังค้างอยู่ Container ที่หยุดแล้วไม่ถูกลบ และการ Build Image สร้าง Cache สะสมไว้ใน /var/lib/docker สุดท้ายดิสก์เต็มจนฐานข้อมูลเขียนไม่ได้หรือบริการล่ม
Docker มีคำสั่งตระกูล prune สำหรับลบของที่ไม่ได้ใช้แล้ว บทความนี้อธิบายวิธีดูว่าพื้นที่หายไปกับอะไร คำสั่งแต่ละตัวลบอะไรบ้าง ตัวไหนปลอดภัย ตัวไหนเสี่ยงทำข้อมูลหาย และวิธีตั้งให้ทำความสะอาดอัตโนมัติ
สิ่งที่ต้องเตรียม
- Linux Server ที่ใช้ Docker Engine รุ่นปัจจุบัน (23.0 ขึ้นไป) ตรวจด้วย
docker version - สิทธิ์
sudoหรือผู้ใช้ในกลุ่มdocker - ไฟล์สำรองของ Volume ที่มีข้อมูลสำคัญ ก่อนใช้คำสั่งใดที่เกี่ยวกับ Volume ดู สำรองและกู้คืนข้อมูล Docker Volume
ขั้นตอนที่ 1: ดูว่าพื้นที่ถูกใช้ไปกับอะไร
เริ่มจากภาพรวมของทั้งเครื่อง
df -h /var/lib/docker
จากนั้นให้ Docker สรุปการใช้พื้นที่ของตัวเอง
docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 5 9.8GB 7.2GB (73%)
Containers 9 5 310MB 120MB (38%)
Local Volumes 7 4 3.1GB 900MB (29%)
Build Cache 63 0 2.4GB 2.4GB
คอลัมน์ RECLAIMABLE คือพื้นที่ที่คืนได้เพราะไม่มี Container ที่ทำงานอยู่ใช้งาน ตัวอย่างนี้ Image กินพื้นที่มากที่สุด ถ้าต้องการรายละเอียดทีละรายการ เช่น Volume ใดใหญ่และยังมี Container ผูกอยู่หรือไม่ ใช้
docker system df -v
ถ้า docker system df รวมแล้วน้อยกว่าที่ df -h แสดงมาก ให้ตรวจไฟล์ Log ของ Container ซึ่งไม่ได้นับรวมในตารางนี้
sudo sh -c 'du -h /var/lib/docker/containers/*/*-json.log' | sort -h | tail
ถ้าไฟล์ Log ใหญ่เป็น GB แก้ต้นเหตุตาม จำกัดขนาด Log ของ Docker Container เพราะ prune ไม่ลบ Log ของ Container ที่ยังอยู่
ขั้นตอนที่ 2: รู้จักคำสั่ง prune แต่ละตัว
| คำสั่ง | ลบอะไร | ความเสี่ยง |
|---|---|---|
docker container prune | Container ที่หยุดแล้วทั้งหมด | ต่ำ แต่ไฟล์ที่เขียนใน Container นั้น (นอก Volume) จะหาย |
docker image prune | Image แบบ dangling (ไม่มี TAG แสดงเป็น <none>) | ต่ำมาก |
docker image prune -a | Image ทุกตัวที่ไม่มี Container ใช้ รวมตัวที่มี TAG | ต่ำ แต่ครั้งหน้าต้องดาวน์โหลดใหม่ |
docker builder prune | Build Cache | ต่ำ Build ครั้งหน้าช้าลง |
docker network prune | Network ที่ไม่มี Container ใช้ | ต่ำ |
docker volume prune | Anonymous Volume ที่ไม่มี Container ใช้ | สูง ข้อมูลหายถาวร |
docker volume prune -a | Volume ทุกตัวที่ไม่มี Container ใช้ รวม Named Volume | สูงมาก |
ตั้งแต่ Docker Engine 23.0 เป็นต้นมา docker volume prune ลบเฉพาะ Anonymous Volume เป็นค่าเริ่มต้น ต้องใส่ -a จึงจะลบ Named Volume ด้วย บทความเก่าบนอินเทอร์เน็ตที่เขียนก่อนหน้านั้นอาจอธิบายต่างจากนี้
หมายเหตุ: คำว่า "ไม่มี Container ใช้" รวมถึงกรณีที่คุณเพิ่งสั่ง
docker compose downไป Volume ฐานข้อมูลของโปรเจกต์ที่ปิดชั่วคราวจะถูกมองว่าไม่ได้ใช้และถูกลบได้ ห้ามใช้volume prune -aบนเครื่องจริงโดยไม่ตรวจรายการก่อนเด็ดขาด
ขั้นตอนที่ 3: ใช้ docker system prune
docker system prune รวมหลายคำสั่งไว้ในคำสั่งเดียว ค่าเริ่มต้นจะลบ Container ที่หยุดแล้ว, Network ที่ไม่ได้ใช้, Image แบบ dangling และ Build Cache ที่ไม่ได้อ้างอิง ระบบจะแสดงรายการและถามยืนยันก่อนเสมอ
docker system prune
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- unused build cache
Are you sure you want to continue? [y/N]
ถ้อยคำของรายการอาจต่างกันเล็กน้อยตามเวอร์ชันของ Docker (บางรุ่นเขียนว่า all dangling build cache) อ่านรายการให้ครบก่อนพิมพ์ y เมื่อเสร็จจะแสดงบรรทัด Total reclaimed space: ...
ถ้าต้องการคืนพื้นที่มากขึ้น เพิ่ม -a เพื่อลบ Image ทุกตัวที่ไม่มี Container ใช้
docker system prune -a
ทั้งสองแบบ ไม่ลบ Volume เว้นแต่จะใส่ --volumes เพิ่ม ซึ่งไม่แนะนำให้ใช้ในงานประจำ
ลบเฉพาะของที่เก่ากว่ากำหนด
ตัวเลือก --filter "until=..." ช่วยเก็บของที่เพิ่งสร้างไว้ เช่น Image ที่เพิ่งดึงมาเพื่อเตรียม Deploy
docker image prune -a --filter "until=168h"
docker builder prune --filter "until=72h"
ตัวอย่างแรกลบ Image ที่ไม่ได้ใช้และสร้างนานกว่า 7 วัน ตัวอย่างที่สองลบ Build Cache ที่เก่ากว่า 3 วัน
ขั้นตอนที่ 4: ตรวจก่อนลบ Volume
ถ้า Volume กินพื้นที่มากและต้องการลบ ให้ดูรายการที่ไม่มี Container ผูกอยู่ก่อน
docker volume ls -f dangling=true
ตรวจเนื้อหาของ Volume ที่ไม่แน่ใจ โดยเปิดดูแบบอ่านอย่างเดียว
docker run --rm -v ชื่อvolume:/data:ro debian:bookworm-slim ls -la /data
จากนั้นลบทีละตัวด้วยชื่อ ซึ่งปลอดภัยกว่าการ prune ทั้งหมด
docker volume rm ชื่อvolume
ขั้นตอนที่ 5: ตั้งทำความสะอาดอัตโนมัติ
สำหรับเครื่องที่ Deploy บ่อย ตั้ง Cronjob ให้ลบ Image และ Build Cache เก่าทุกสัปดาห์ โดยไม่แตะ Volume
sudo crontab -e
0 3 * * 0 /usr/bin/docker image prune -af --filter "until=168h" >> /var/log/docker-prune.log 2>&1
15 3 * * 0 /usr/bin/docker builder prune -f --filter "until=168h" >> /var/log/docker-prune.log 2>&1
-f ข้ามการถามยืนยัน จึงใช้ใน Cron ได้ ตรวจ path ของคำสั่งด้วย which docker ก่อน เพราะบางระบบติดตั้งไว้คนละที่ พื้นฐานการเขียน Cron ดูได้ที่ วิธีตั้ง Cronjob หรือ Crontab เพื่อให้ Script ทำงานอัตโนมัติบน Linux
ตรวจสอบผลลัพธ์
docker system df
df -h /var/lib/docker
คอลัมน์ RECLAIMABLE ควรลดลงใกล้ 0 สำหรับประเภทที่เพิ่งลบ และ df -h ต้องแสดงพื้นที่ว่างเพิ่มขึ้น จากนั้นตรวจว่าบริการทั้งหมดยังทำงานปกติด้วย docker ps และเปิดเว็บไซต์ทดสอบ