คำตอบสั้น ๆ: หา Container ที่มีไฟล์ Log ใหญ่ ล้างไฟล์อย่างปลอดภัย และตั้ง max-size กับ max-file ใน daemon.json หรือ Docker Compose ไม่ให้ Log เต็มดิสก์อีก
คู่มือนี้อธิบาย Container ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย
ทุกข้อความที่โปรแกรมใน Container พิมพ์ออกทาง stdout และ stderr จะถูก Docker เก็บไว้ ค่าเริ่มต้นของ Docker Engine บน Linux คือ Log Driver แบบ json-file ซึ่ง ไม่จำกัดขนาด ไฟล์จึงโตขึ้นเรื่อย ๆ Container ที่พิมพ์ Log เยอะ เช่น Web Server ที่มีผู้เข้าชมมาก หรือแอปที่เปิดโหมด Debug ทิ้งไว้ สร้างไฟล์ Log หลายสิบ GB ได้ภายในไม่กี่สัปดาห์ จนดิสก์เต็ม
บทความนี้แสดงวิธีหาว่า Container ใดมี Log ใหญ่ ล้างไฟล์ที่ใหญ่อยู่แล้วอย่างปลอดภัย และตั้งการหมุนเวียน Log (Log Rotation) ทั้งแบบค่าเริ่มต้นของทั้งเครื่องและแบบรายโปรเจกต์ใน Docker Compose
สิ่งที่ต้องเตรียม
- Linux Server ที่ใช้ Docker Engine (ตัวอย่างนี้ทดสอบแนวทางกับ Ubuntu 22.04/24.04 และ AlmaLinux/Rocky Linux 8-9)
- สิทธิ์
sudo - ช่วงเวลาที่รีสตาร์ต Docker และสร้าง Container ใหม่ได้ เพราะการเปลี่ยนค่า Log มีผลกับ Container ที่สร้างใหม่เท่านั้น
ขั้นตอนที่ 1: หา Container ที่มีไฟล์ Log ใหญ่
ไฟล์ Log ของ Driver json-file อยู่ที่ /var/lib/docker/containers/<ID>/<ID>-json.log ดูขนาดทั้งหมดเรียงจากเล็กไปใหญ่
sudo sh -c 'du -h /var/lib/docker/containers/*/*-json.log' | sort -h | tail
120M /var/lib/docker/containers/3f2a.../3f2a...-json.log
8.4G /var/lib/docker/containers/9c1d.../9c1d...-json.log
ชื่อโฟลเดอร์เป็น ID ของ Container ดูว่าเป็นตัวไหนด้วยคำสั่งนี้ ซึ่งแสดงชื่อ Container คู่กับ path ของไฟล์ Log
docker ps -aq | xargs docker inspect --format '{{.Name}} {{.LogPath}}'
ตรวจว่า Container แต่ละตัวใช้ Log Driver และตัวเลือกใดอยู่
docker inspect --format '{{.HostConfig.LogConfig}}' web
ถ้าได้ {json-file map[]} แปลว่าไม่มีการจำกัดขนาด
ขั้นตอนที่ 2: ล้างไฟล์ Log ที่ใหญ่อยู่แล้ว
ถ้าดิสก์ใกล้เต็ม ให้ล้างไฟล์ก่อนเพื่อคืนพื้นที่ทันที ใช้ truncate เพื่อทำให้ไฟล์ว่างเปล่าโดยไม่ลบไฟล์ทิ้ง
sudo truncate -s 0 "$(docker inspect --format '{{.LogPath}}' web)"
หมายเหตุ: Log ที่ถูกล้างจะหายถาวร ถ้าต้องใช้เป็นหลักฐานหรือหาสาเหตุปัญหา ให้คัดลอกเก็บก่อน เช่น
docker logs --since 24h web > web-last24h.log 2>&1และห้ามใช้rmลบไฟล์-json.logขณะ Container ทำงาน เพราะ Docker ยังเปิดไฟล์ค้างไว้ พื้นที่จะไม่ถูกคืนจนกว่าจะรีสตาร์ต และคำสั่งdocker logsอาจใช้งานไม่ได้
การล้างเป็นแค่การแก้เฉพาะหน้า ไฟล์จะโตกลับมาอีก ขั้นตอนถัดไปคือการแก้ที่ต้นเหตุ
ขั้นตอนที่ 3: ตั้งค่าเริ่มต้นให้ทั้งเครื่องใน daemon.json
แก้หรือสร้างไฟล์ /etc/docker/daemon.json (ถ้ามีไฟล์อยู่แล้ว ให้เพิ่มคีย์เข้าไปใน Object เดิม อย่าเขียนทับค่าอื่นที่ตั้งไว้)
sudo nano /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
max-sizeขนาดสูงสุดของไฟล์ Log แต่ละไฟล์ ก่อนเริ่มไฟล์ใหม่ (หน่วยk,m,g)max-fileจำนวนไฟล์สูงสุดที่เก็บไว้ ไฟล์เก่าที่สุดจะถูกลบเมื่อครบ ตัวอย่างนี้จึงใช้พื้นที่ไม่เกินประมาณ 30 MB ต่อ Container- ค่าใน
log-optsต้องเป็นข้อความในเครื่องหมายคำพูด ทั้งหมด แม้จะเป็นตัวเลข เช่น"3"ถ้าเขียน3เฉย ๆ Docker จะเริ่มทำงานไม่ได้
ทางเลือก: Log Driver แบบ local
Driver local หมุนเวียนไฟล์และบีบอัดให้อัตโนมัติ โดยค่าเริ่มต้นเก็บไม่เกิน 5 ไฟล์ ไฟล์ละ 20 MB ใช้พื้นที่น้อยกว่า json-file แต่ไฟล์เป็นรูปแบบภายในของ Docker อ่านผ่าน docker logs ได้ตามปกติ แต่เครื่องมือเก็บ Log ภายนอกที่อ่านไฟล์ JSON โดยตรงจะอ่านไม่ได้
{
"log-driver": "local"
}
| Driver | จำกัดขนาดเอง | บีบอัด | เหมาะกับ |
|---|---|---|---|
json-file (ค่าเริ่มต้น) | ไม่ ต้องตั้ง max-size | ได้ ถ้าตั้ง "compress": "true" | ต้องการให้เครื่องมืออื่นอ่านไฟล์ JSON ได้ |
local | ใช่ (5 x 20 MB) | ใช่ | เซิร์ฟเวอร์ทั่วไปที่ดู Log ด้วย docker logs |
journald | ตามการตั้งค่าของ journald | ใช่ | ต้องการรวม Log กับ journalctl |
ถ้าเลือก journald ขนาดรวมถูกควบคุมโดยค่า SystemMaxUse ของ journald ดูรายละเอียดที่ อ่าน Log ระบบบน Linux ด้วย journalctl
ขั้นตอนที่ 4: ตรวจไฟล์และรีสตาร์ต Docker
ตรวจความถูกต้องของไฟล์ก่อนรีสตาร์ต (Docker Engine 23.0 ขึ้นไป)
sudo dockerd --validate --config-file=/etc/docker/daemon.json
ผลที่ถูกต้องคือ configuration OK จากนั้นรีสตาร์ตบริการ
sudo systemctl restart docker
หมายเหตุ: การรีสตาร์ต Docker ทำให้ Container ทั้งหมดบนเครื่องหยุดและเริ่มใหม่ (ยกเว้นเปิด
live-restoreไว้) เว็บไซต์จะหยุดให้บริการชั่วครู่ ควรทำในช่วงที่มีผู้ใช้น้อย ถ้า Docker เริ่มไม่ขึ้นหลังรีสตาร์ต ให้ดูสาเหตุด้วยsudo journalctl -u docker -n 50ซึ่งส่วนใหญ่เป็น JSON ผิดรูปแบบ