อาการ
df -h บอก /var/lib/docker กิน 80GB เต็ม disk
$ docker system prune -a --volumes -f
Total reclaimed space: 0B
อ้าว ทำไมไม่คืน?
$ sudo du -sh /var/lib/docker/containers/*/
2.3G /var/lib/docker/containers/abc123.../
14G /var/lib/docker/containers/def456.../
8G /var/lib/docker/containers/ghi789.../
ปัญหาเกือบทั้งหมดมาจาก container log file ที่ใหญ่มาก
ทำไมไม่คืน
Docker default log driver คือ json-file — log ทุก stdout/stderr ของ container ลง:
/var/lib/docker/containers/<id>/<id>-json.log
ไฟล์นี้ โตได้ไม่จำกัด ถ้าไม่ตั้ง limit
ที่สำคัญ — ถ้า container ยัง running, process ยังเปิด file handle อยู่ ถ้าลบไฟล์ด้วย rm พื้นที่จะไม่คืนจนกว่า process จะปิด file (Linux behavior ทั่วไป)
วิธีแก้
Step 1: หา container ที่ log ใหญ่ที่สุด
sudo du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null \
| sort -hr | head -10
ผลลัพธ์:
12G /var/lib/docker/containers/def456abc/def456abc-json.log
8.3G /var/lib/docker/containers/ghi789def/ghi789def-json.log
Step 2: หา container name จาก ID
docker inspect --format='{{.Name}}' def456abc
# /noisy-app
Step 3: Truncate log โดย container ยังรันอยู่
ถ้า container กำลังรัน — อย่า rm ไฟล์ ใช้ truncate แทน:
# truncate ไฟล์ให้ขนาด 0 — process ที่เปิด file อยู่ใช้ต่อได้
sudo truncate -s 0 /var/lib/docker/containers/def456abc/def456abc-json.log
> แทนก็ได้:
sudo sh -c 'echo > /var/lib/docker/containers/def456abc/def456abc-json.log'
ทันทีที่ truncate — df -h จะเห็นพื้นที่คืน
Step 4: ถ้ารู้ว่าจะลบทั้ง container
docker rm -f noisy-app
docker system prune -f
ทำไม rm ตรงๆ ไม่ดี
ถ้าใช้ rm /var/lib/docker/containers/*/*-json.log:
- Container ยังรัน → file handle ยังเปิด → space ไม่คืน (deleted but inode in use)
- ตรวจด้วย
lsof | grep deleted:sudo lsof | grep deleted | head # docker 1234 ... deleted /var/lib/docker/containers/.../json.log
ต้อง restart container ถึงจะคืน — กระทบ service
ใช้ truncate ดีกว่า — file size = 0 ทันที process ยังเปิดต่อได้ไม่งง
ป้องกันไม่ให้เกิดอีก
วิธีที่ 1: ตั้ง log limit ใน Docker daemon (แนะนำ)
/etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "3"
}
}
restart docker:
sudo systemctl restart docker
ตั้งแบบนี้ — ทุก container ใหม่จะมี log สูงสุด 50MB × 3 = 150MB
สำคัญ: config นี้ใช้กับ container ใหม่ เท่านั้น — container ที่รันอยู่แล้วยังใช้ config เดิม ต้อง restart container ถึง apply
วิธีที่ 2: ตั้ง per-container ใน compose
services:
app:
image: myapp
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
วิธีที่ 3: เปลี่ยนเป็น log driver อื่น
ถ้า log เยอะมาก — ส่งออกไปเก็บข้างนอก ใช้ centralized logging แทน:
{
"log-driver": "loki",
"log-opts": {
"loki-url": "http://loki.internal:3100/loki/api/v1/push",
"loki-batch-size": "400"
}
}
ดู Centralized Logging ด้วย Loki สำหรับ stack ที่ต้องตั้งฝั่ง receiver
หา space ที่หายไปด้วย ncdu
sudo apt install ncdu
sudo ncdu /var/lib/docker
interactive ลำดับ folder ตามขนาด — กด Enter เพื่อ explore กด d เพื่อลบ
อย่าลืมส่วนอื่นของ Docker
/var/lib/docker มีของอื่นนอกจาก log:
sudo du -sh /var/lib/docker/*
อาจเห็น:
containers/— container data + logimage/— layer ของ imagevolumes/— named volumeoverlay2/— storage layer ของ container ที่รันbuildkit/— cache ของ docker build
แต่ละอันมีคำสั่ง prune ของมัน:
docker container prune # ลบ container ที่หยุด
docker image prune -a # ลบ image ที่ไม่ใช้
docker volume prune # ลบ volume ที่ไม่มี container ใช้
docker builder prune # ลบ build cache
# ทำทุกอย่างพร้อมกัน
docker system prune -a --volumes -f
เช็คลิสต์เวลา disk เต็ม
# 1. ดูว่า /var/lib/docker ใหญ่จริงมั้ย
sudo du -sh /var/lib/docker
# 2. หา container ที่ log ใหญ่สุด
sudo du -sh /var/lib/docker/containers/*/*-json.log | sort -hr | head
# 3. truncate log (ระหว่าง container ยังรัน)
sudo truncate -s 0 /var/lib/docker/containers/<id>/<id>-json.log
# 4. หรือ prune ของที่ไม่ใช้
docker system prune -a --volumes -f
# 5. ตั้ง daemon config ป้องกัน
sudo nano /etc/docker/daemon.json
sudo systemctl restart docker
# 6. restart container ที่อยู่ก่อนตั้ง config
docker compose down && docker compose up -d
สรุป
ถ้าเจอ Docker disk เต็ม — 80% เกิดจาก log ใหญ่
วิธีแก้:
- เร็ว:
truncate -s 0ที่ไฟล์ json.log - ถาวร: ตั้ง
max-size+max-fileใน daemon config
ตั้ง config ที่ถูกตั้งแต่ install Docker ครั้งแรก ก็จะไม่กลับมาเจอเหตุการณ์นี้อีก