+29

Hết dung lượng disk do chạy Docker trong thời gian dài

Khi chạy docker trong thời gian dài các bạn sẽ gặp phải tình huống đầy ổ đĩa, nguyên nhân sẽ có nhiều: log của app, kích thước ổ nhỏ quá, ... Hôm nay mình xin chia sẻ quá trình debug khi hết ổ đĩa và sau đó là cách dọn dẹp Docker định kì.

Mình có tự mua một con server ở nhà cấu hình: dual xeon, ram 128GB, disk 2TB, (mình mua cấu hình này ~13tr) để chạy máy ảo, nghịch ngợm các thứ. Các máy ảo cấu hình cũng ổn, ít thì 4cpu, 8GB RAM, 128GB disk, nhiều thì 12cpu, 24GB RAM, 256GB disk. Cứ nghĩ chả phải monitor, đặt cảnh báo alert thì một ngày, bạn mình dùng chung với mình bảo backend chết, lúc này các bạn sẽ thấy một vài dấu hiệu như: chỉ query được dữ liệu, backend trả về lỗi 500, ...

Tìm nguyên nhân

Mình ssh ngay vào con vm để kiểm tra, dấu hiệu đầu tiên các bạn có thể thấy ngay là khi ấn TAB để gợi ý lệnh sẽ có lỗi như sau:

vagrant@tuana9a-dev ~ $ cd /etc/ng [TAB]
bash: No space left on device

(trên là ví dụ minh họa, mình không nhớ chính xác message)

Khi biết là hết disk ngay lập tức mình chạy lệnh df để kiểm tra disk còn trống bao nhiêu.

vagrant@tuana9a-dev ~ $ df -h                   
Filesystem      Size  Used Avail Use% Mounted on
udev            3.9G     0  3.9G   0% /dev
tmpfs           798M  9.3M  789M   2% /run
/dev/sda3       124G   84G   34G  72% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/sda1       462M  222M  212M  52% /boot
tmpfs           798M     0  798M   0% /run/user/1000
vagrant@tuana9a-dev ~ $ 

Ở trên hình thì /dev/sda3 chưa đầy mà trong quá khứ thì nó đã bị đầy một lần rùi 95%, khi đầy thì cột Used sẽ cao và Avail sẽ thấp.

Lúc này các bạn đừng hoảng, ngày xưa mình cũng thắc mắc là OS khi hoạt động sẽ cần không gian bộ nhớ để cho các file tạm, các chương trình khi thực thi khả năng cao sẽ tương tác với các file tạm này để có thể hoạt động bình thường, đặc biệt với Linux thì mọi thứ đều là file, giờ hết disk rồi thì OS chết hả, không fix được nữa hả? Vẫn fix được, mình có tìm từ khóa Reserved Disk Space On Linux thì tìm được cái này https://unix.stackexchange.com/questions/7950/reserved-space-for-root-on-a-filesystem-why, đại loại linux sẽ "chừa" khoảng 5% con số chính xác có thể khác nhau tùy theo format disk, tùy theo loại filesystem hoặc tùy theo OS nên là vẫn thở được các bạn nhé.

Tiếp tục kiểm tra kích thước của từng thư mục từ thư mục root bằng lệnh du (lệnh này scan toàn bộ file nên nếu dùng với thư mục root / sẽ hơi lâu)

vagrant@tuana9a-dev ~ $ sudo du -h --max-depth 1 /              
45G	    /var
1.2G	/lib
2.4G	/opt
16K	    /lost+found
9.3M	/run
0	    /sys
1.3M	/tmp
4.0K	/srv
0	    /dev
4.0K	/mnt
8.0K	/snap
4.0K	/lib64
20K	    /exports
13G	    /usr
6.7M	/etc
27G	    /home
8.0K	/media
15M	    /sbin
222M	/boot
4.0K	/yourpath
16M	    /bin
268K	/root
du: cannot access '/proc/10305/task/10305/fd/3': No such file or directory
du: cannot access '/proc/10305/task/10305/fdinfo/3': No such file or directory
du: cannot access '/proc/10305/fd/4': No such file or directory
du: cannot access '/proc/10305/fdinfo/4': No such file or directory
0	/proc
86G	/
vagrant@tuana9a-dev ~ $ 

Thấy thư mục /var lớn nhất, check tiếp bên trong thư mục đó.

vagrant@tuana9a-dev ~ $ sudo du -h --max-depth 1 /var
40G	    /var/lib
4.0K	/var/opt
3.6M	/var/crash
28K	    /var/tmp
4.0K	/var/snap
12K	    /var/www
842M	/var/cache
4.0K	/var/local
36K	    /var/spool
2.7M	/var/backups
3.4G	/var/log
4.0K	/var/mail
45G     /var

Tiếp tục với thư mục /var/lib thì tìm ra thằng /var/lib/docker nặng nhất, cụ thể lúc đấy khoảng 80GB.

vagrant@tuana9a-dev ~ $ sudo du -h --max-depth 1 /var/lib/docker
4.0K	/var/lib/docker/runtimes
40G     /var/lib/docker/overlay2
148K	/var/lib/docker/volumes
4.9M	/var/lib/docker/containers
4.0K	/var/lib/docker/tmp
4.0K	/var/lib/docker/swarm
152K	/var/lib/docker/network
56M	    /var/lib/docker/image
39M	    /var/lib/docker/buildkit
16K	    /var/lib/docker/plugins
40G	    /var/lib/docker

Nhìn vào cấu trúc thư mục này cũng đoán được docker hoạt động như nào:

  • volumes để chứa các thông tin liên quan tới volumes: metadata, có thể chứa cả dữ liệu luôn, chính xác thì các bạn tự kiểm tra nhé.
  • containers chứa các thông tin liên quan tới container: metadata, log, ..., nếu app các bạn nhiều log thì thư mục này cũng to vl luôn.
  • network chứa thông tin liên quan tới network: metadata, cấu hình network, ...
  • ...

Thằng overlay2 là gì mà sao ăn lắm disk thế nhỉ? Các bạn tự google để xem chi tiết nhé - spoiler: data structure này rất hay nhé.

Ok vậy đã tìm được nguyên nhân là do docker, bước tiếp theo là xem cái gì dọn dẹp được thì dọn dẹp. Các thứ mình nghĩ có thể dọn dẹp được bao gồm:

  • Log của các container
  • Các volume không còn được sử dụng
  • Các container đã stopped
  • Các image mà không được sử dụng
  • Build cache

Tìm được các thứ cần dọn dẹp rồi thì bắt đầu dọn.

Dọn dẹp

Dọn dẹp log của container, đơn giản là làm nó trống trơn.

for f in /var/lib/docker/containers/*/*-json.log
do
  cat /dev/null > $f
done

Dọn volume mà không được sử dụng nữa.

docker volume prune -a

Dọn các docker image mà không được sử dụng nữa.

docker image prune -a

Dọn các container không còn chạy nữa.

docker container prune

Các bạn để ý khi build lại container thì lần sau thường nhanh hơn lần trước, nhanh như vậy chắc chẳn là do cache ròi.

Build xong thì dọn thôi.

docker builder prune

docker system prune

Phiên bản sau này của docker có lệnh docker system prune sẽ tự động làm kha khá các việc dọn dẹp cho chúng ta.

root@tuana9a-dev:/var/lib/docker# docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N] y
Deleted Networks:
docker-registry_default
Deleted build cache objects:
98jlfzkgw1hjfdk22sd5460x5
3o8xbgqhl6e49n3illj8fenid
o692cdjs4pm8ni4l4rg8v4hpw
pobyjug26w7kddhf68st2sj5t
p3imtyiehrh0pqfptsyfyftaj
...
Total reclaimed space: 25.17GB
root@tuana9a-dev:/var/lib/docker#

Muốn sạch hơn nữa các bạn có thể docker system prune -a

Tích hợp vào crontab

Dọn dẹp log container, các bạn có thể chọn dọn dẹp định kỳ vào khoảng thời gian tùy theo sở thích, gu thẩm mĩ, tình yêu, ...

UPDATE 2024: Lưu ý: khi để trong /etc/cron.*/*, tên file không để đuôi .sh nếu ko cronjob sẽ không hoạt động https://askubuntu.com/questions/337204/cron-daily-jobs-not-running

Cấu hình chạy hằng ngày (daily)

sudo -s
cat <<EOF > /etc/cron.daily/clear-container-logs
#!/bin/sh
for f in /var/lib/docker/containers/*/*-json.log
do
  cat /dev/null > \$f
done
EOF
chmod +x /etc/cron.daily/clear-container-logs

Hoặc dọn theo tuần (weekly)

sudo -s
cat <<EOF > /etc/cron.weekly/clear-container-logs
#!/bin/sh
for f in /var/lib/docker/containers/*/*-json.log
do
  cat /dev/null > \$f
done
EOF
chmod +x /etc/cron.weekly/clear-container-logs

Hoặc tạo script file rồi crontab -e, ...

Tích hợp crontab với các thứ còn lại tương tự nhá.

Next step

Đây là ý nghĩa của việc đẻ ra "monitor", sau vụ này mình đã triển khai combo monitor: prometheus + node_exporter + grafana + alertmanager, cứ vượt 80% disk là cảnh báo, cuộc sống an nhàn, đời đời thảnh thơi. Triển khai hệ thống monitor nằm ngoài phạm vi bài viết này.

Hết.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.