Cách khắc phục khi ổ đĩa bị đầy trong quá trình sử dụng Docker?

Cách khắc phục khi ổ đĩa bị đầy trong quá trình sử dụng Docker?

·

6 min read

Nếu bạn thường xuyên build image bằng Docker, thì chắc các bạn cũng để ý khi build lại thì lần sau thường sẽ nhanh hơn phần trước. Nhanh như vậy đó là do Docker đã cache lại để quá trình build image của chúng ta được nhanh hơn.

Tất nhiên cái gì cũng có cái giá của nó ^^. Mình cũng đã từng gặp trường hợp như vậy khi triển khai dự án ở công ty, mình dựng 1 server GitHub Action self-hosted để chạy CI (Continuous Innovation) build image mới nhất từ Repo mỗi khi đẩy code vào nhánh prod, staging hoặc dev.

Truy tìm giấu vết

Quá trình này hoạt động cũng được gọi là ổn định cho đến khi 1 vấn đề xảy ra 😒

Error: no space left on device

Lối bên trên chỉ mang tính chất minh hoạ, nhưng đại loại là lỗi trả về có dạng no space left on device. Ngay lập tức mình kết nối vào server để xem tình hình ra sao. Sau đó chạy lệnh df để kiểm tra disk còn bao nhiêu % ổ đĩa trống.

ubuntu@builder:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           791M  3.3M  787M   1% /run
/dev/sda2        98G   98G   0     99% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           791M  4.0K  791M   1% /run/user/1000

(Kết quả đã được mình chế cháo lại 😁, nhưng đại loại là sẽ có dạng như vậy) Nhìn kết quả bên trên chắc các bạn cũng sẽ thấy /dev/sda2 đang đầy 99%. khi đầy thì cột Used sẽ cao, Avail sẽ thấp và cột Use% sẽ hiển thị % sử dụng ổ đĩa

Tiếp tục kiểm tra kích thước của từng thư mục từ thư mục root

sudo du -h --max-depth 1 /

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

sudo du -h --max-depth 1 /var

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

ubuntu@builder:~$ 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

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ì chúng ta bắt đầu dọn dẹp thôi.

Xoá các volume không sử dụng nữa

Câu lệnh dọn dẹp các volume mà không được sử dụng nữa.

docker volume prune -f

Xoá các image không sử dụng nữa

Câu lệnh dọn dẹp các image mà không được sử dụng nữa.

docker image prune -a -f

Xoá các container không sử dụng nữa

Câu lệnh dọn dẹp các container mà không được sử dụng nữa.

docker container prune -f

Xoá các builder không sử dụng nữa

Câu lệnh dọn dẹp các builder mà không được sử dụng nữa. (Server builder của mình nặng nhất phần này, vì phải build image liên tục dẫn tới cache làm đầy ổ cứng)

docker builder prune -a -f

Câu lệnh giúp dọn dẹp nhanh chóng 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.

ubuntu@builder:~$ 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-network_default
Deleted build cache objects:
98jlfzkgw1hjfdk22sd5460x5
3o8xbgqhl6e49n3illj8fenid
o692cdjs4pm8ni4l4rg8v4hpw
pobyjug26w7kddhf68st2sj5t
p3imtyiehrh0pqfptsyfyftaj
...
Total reclaimed space: 80.17GB

Hoặc chạy lệnh xoá tất cả

docker system prune -a -f

Xoá các container logs

Thứ chiếm dung lượng ổ đĩa tiếp theo là Docker Json Logs, mặc định khi cài Docker thì toàn bộ logs của container sẽ được Docker lưu ở thư mục /var/lib/docker/containers/\* ở dạng json, nếu ta không thường xuyên xóa logs ở thư mục này thì nó sẽ lên tới vài chục hoặc vài trăm GB.

Để xóa logs ở thư mục này ta có vài cách sau:

  • Cấu hình crontab

  • Dùng logrotate

  • Giới hạn dung lượng logs của container

Dọn dẹp log của container, đơn giản là làm nó trống trơn. (Sử dụng quyền root nếu bị lỗi Permission denied )

Xóa thủ công với crontab

sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"

Cấu hình crontab:

# daily
sudo -s

cat <<EOF > /etc/cron.daily/clear-container-logs
#!/bin/sh
truncate -s 0 /var/lib/docker/containers/**/*-json.log
EOF

chmod +x /etc/cron.daily/clear-container-logs

Tự động với logrotate

Nếu bạn muốn giữ lại logs thì có thể dùng logrotate để tự động giảm dung lượng logs của Docker.

Hầu hết các Linux Distro đều cài sẵn logrotate, cấu hình logrotate cho tệp tin logs của Docker rất đơn giản, ta tạo tệp tin logrotate-container ở thư mục /etc/logrotate.d và dán cấu hình ở dưới vào:

/var/lib/docker/containers/*/*.log {
  rotate 7
  daily
  compress
  missingok
  delaycompress
  copytruncate
}

Chạy thử:

logrotate -fv /etc/logrotate.d/logrotate-container

Măc định logrotate có sẵn crontab nằm ở thư mục /etc/cron.daily để chạy logrotate hằng ngày nên ta không cần phải cấu hình crontab thêm.

Giới hạn dung lượng logs của container

Từ phiên bản 1.8 trở đi thì Docker có sẵn chức năng logrotate cho json logs. Khi chạy container ta thêm vào thuộc tính --log-opt vào để giới hạn dung lượng logs của container.

docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=5 nginx

Trong đó:

  • --log-driver=json-file: Đặt log driver cho container là json-file.
  • --log-opt max-size=10m: Giới hạn kích thước tối đa của mỗi tập tin log là 10 megabytes. Bạn có thể thay đổi giá trị theo nhu cầu của mình.
  • --log-opt max-file=5: Giới hạn số lượng tập tin log tối đa là 5. Khi số lượng tập tin vượt quá giới hạn, các tập tin cũ hơn sẽ bị ghi đè. Bạn có thể thay đổi giá trị theo nhu cầu của mình.

Nếu bạn đang chạy một container đang hoạt động, bạn có thể thay đổi cấu hình log driver bằng cách sử dụng lệnh docker update

docker update --log-opt max-size=10m --log-opt max-file=5 <container_id>

Nếu ta cần cấu hình cho toàn bộ container thì thêm cấu hình sau vào daemon.json, nằm ở thư mục /etc/docker/ trên Linux và ở thư mục C:\ProgramData\docker\config\ trên Windows.

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Kết luận

Trên đây là 1 số cách để tránh và khắc phục khi ổ đĩa bị đầy trong quá trình học tập và sử dụng Docker. Cách khắc phục tuy đơn giản nhưng vấn đề này rất quan trọng nên các bạn hãy cẩn thận chọn cách phù hợp để cấu hình cho máy chủ của mình nhé ^^.

Nội dung tham khảo

Nội dung bài viết này được mình tìm hiểu, tham khảo, đúc kết và tổng hợp lại từ nhiều nguồn. Mọi người có thể xem thêm các bài viết sau: