前言

今天突然收到测试服务器的磁盘空间不足的报警,处理这种报警还是比较有经验的,肯定是docker的日志占用了太多的磁盘空间导致, 之前处理后,比较懒,没有记录下来。

根据以往的处理经验,这种情况就很好解决,找到日志比较大的容器,删除日志,并调整日志级别即可解决。

我兼职打杂运维工作,我们团队所有组件都在云上飘着, 有很多的微服务组件,就需要使用服务发现,链路跟踪等配套设施,也少不了使用docker

最近为了能够方便的扩容,我们决定使用HashiCorp家的轻量级的服务编排,安装了他家的几个docker服务,并把服务发现替换成了consul。 运行了几天后,出现磁盘空间不足的报警。

当你使用docker,并且容器运行比较久,程序又疯狂的输入后,就会导致docker的日志占用磁盘空间太大,这时候就需要清理一下了。

根据以住的解决问题的思路,这次记录下来,方便以后查阅,也给其遇到此问题的小伙伴一个参考。

查看磁盘空间

1
$ df -hl

输出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           794M  5.3M  789M   1% /run
/dev/vda1       148G   73G   69G  52% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           794M     0  794M   0% /run/user/0
overlay         148G   73G   69G  52% /var/lib/docker/overlay2/cb00c5676cee609000b56c66a73799105a373aad0700c5568f3d361a38089b78/merged
overlay         148G   73G   69G  52% /var/lib/docker/overlay2/64abd807c2a1b351718b5a3ddacd81ff65cb8a93b350a8ca7739a297b9800edb/merged
overlay         148G   73G   69G  52% /var/lib/docker/overlay2/f1100b6702df33a0fa0557b73ed56952cfa0385c182fd271c142b9d6204fdecd/merged
overlay         148G   73G   69G  52% /var/lib/docker/overlay2/44f6aa5c75d6e4f31747398e89bc369b63b9aad27623e8766636bbea58ae32d8/merged
........

看输出docker目录占用太多磁盘空间了,那就可以找对应的解决方案了。

docker system 命令

docker system df命令,类似于 Linux 上的df命令,用于查看 Docker 的磁盘使用情况:

1
$ docker system df
1
2
3
4
5
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          56        55        4.011GB   78.94MB (1%)
Containers      60        60        212.3MB   0B (0%)
Local Volumes   5         2         1.378kB   92B (6%)
Build Cache     0         0         0B        0B

可以看,Docker 镜像、容器、数据卷占用了多少磁盘空间。

docker system prune命令可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络,以及 dangling 镜像(即无 tag 的镜像)。

1
$ docker system prune

之前已经执行过了,所以看到是0B

1
2
3
4
5
6
7
8
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
Total reclaimed space: 0B

docker system prune -af命令清理得更加彻底,可以将没有容器使用 Docker 镜像都删掉。

1
$ docker system prune -af

可以放到释放空间69.58MB,如果有很空未使用的镜像,容器和数据卷,释放的空间还是很可观的。

1
2
3
4
5
6
7
8
9
Deleted Images:
untagged: google/cadvisor:latest
untagged: google/cadvisor@sha256:815386ebbe9a3490f38785ab11bda34ec8dacf4634af77b8912832d4f85dca04
deleted: sha256:eb12107075737019dce2d795dd82f5a72197eb3c64b2140392eaad3ba3b8a34e
deleted: sha256:3385ca422448a4891ab08f24daec3f368197be67f5c786779651f1e85cffa89b
deleted: sha256:f62b8bf389e3af31123f6529d42fb6ef233e0677284af9f4d1db8513d46d6bc8
deleted: sha256:cd7100a72410606589a54b932cabd804a17f9ae5b42a1882bd56d263e02b6215

Total reclaimed space: 69.58MB

上边是自动清理,那就可以手动清理,网上一抓一大把,我这里就不做介绍了,我这里介绍一种比较简单的方法。

如 删除所有 tag 的镜像

1
$ docker rmi $(docker images | grep "^<none>" | awk "{print $3}")

/var/lib/docker/overlay2 磁盘爆满

接下我们继续查看df -hl磁盘空间

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Filesystem      Size  Used Avail Use% Mounted on
......

overlay         148G   73G   68G  52% /var/lib/docker/overlay2/cb00c5676cee609000b56c66a73799105a373aad0700c5568f3d361a38089b78/merged
overlay         148G   73G   68G  52% /var/lib/docker/overlay2/64abd807c2a1b351718b5a3ddacd81ff65cb8a93b350a8ca7739a297b9800edb/merged
overlay         148G   73G   68G  52% /var/lib/docker/overlay2/f1100b6702df33a0fa0557b73ed56952cfa0385c182fd271c142b9d6204fdecd/merged
overlay         148G   73G   68G  52% /var/lib/docker/overlay2/44f6aa5c75d6e4f31747398e89bc369b63b9aad27623e8766636bbea58ae32d8/merged
overlay         148G   73G   68G  52% /var/lib/docker/overlay2/2561c9ef9513026d3465f7e07364ce7f34a472f307c097685e28c522c1118b3f/merged

.......

依然还是/var/lib/docker/overlay2 容器输出的日志太大,导致目录占用的磁盘空间太大。

关于overlay2的介绍,可以参考:

官方文档 Use the OverlayFS storage driver

官方文档 Use the OverlayFS storage driver

那就继续找元凶,进行到/var/lib/docker目录中,使用du -h --max-depth=1命令,查看目录占用的磁盘空间

1
2
$ cd /var/lib/docker
$ du -h --max-depth=1
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
4.0K	./swarm
4.0K	./tmp
80K	./volumes
4.0K	./runtimes
304K	./network
108K	./buildkit
du: cannot access './overlay2/d41f6fcde566b05684ec84b0db63a2fd415abfe9ef3358a66fc6194eb80bc2ad': No such file or directory
du: cannot access './overlay2/d41f6fcde566b05684ec84b0db63a2fd415abfe9ef3358a66fc6194eb80bc2ad-init': No such file or directory
8.7G	./overlay2
16K	./plugins
35G	./containers
20M	./image
43G	.

发现containers目录占用空间最大,继续查看

Containers 包含的我们容器自身的容量、产生的数据容量、产生的日志容量

1
2
$ cd containers
$ du -h --max-depth=1
1
2
3
4
5
6
......
376K	./b84aafb5508aaa1fa5eb94d25997928ded41f6030b8f6785245cfbee40bd1c20
1.6G	./a89cd1bcecbc43be22bdb792f779059f6b03b716a724ac35cc6a80d70b3f83cd
48K	./b12c8ec602a84f8898b6d5b8318ce858788fe46c7040ed449e4a7051144d380b
21G	./807edbf4dbcf6cb4239eead128439c5e5667d56fe951f341fcf0325dab2d6a30
.....

看到有一个21G的目录807edbf4dbcf6cb4239eead128439c5e5667d56fe951f341fcf0325dab2d6a30,这也是容器的ID。

复制容器ID的前10个字符,查看是哪个容器

1
$ docker ps | grep 807edbf4d | awk '{print $1 "  " $2}'
1
2
容器ID         镜像
807edbf4dbcf  nginx:alpine

我们先使用命令删除日志

1
$ truncate -s 0 /var/lib/docker/containers/807edbf4dbcf6cb4239eead128439c5e5667d56fe951f341fcf0325dab2d6a30/807edbf4dbcf6cb4239eead128439c5e5667d56fe951f341fcf0325dab2d6a30-json.log

在使用du -h --max-depth=1命令查看磁盘空间

1
$ du -h --max-depth=1
1
2
3
4
5
6
......
376K	./b84aafb5508aaa1fa5eb94d25997928ded41f6030b8f6785245cfbee40bd1c20
1.6G	./a89cd1bcecbc43be22bdb792f779059f6b03b716a724ac35cc6a80d70b3f83cd
48K	./b12c8ec602a84f8898b6d5b8318ce858788fe46c7040ed449e4a7051144d380b
76K	./807edbf4dbcf6cb4239eead128439c5e5667d56fe951f341fcf0325dab2d6a30
......

哇哦,看到了吗? 变为了76K,这就是我们要的效果。

限制日志大小

可以参与官方文档自行尝试 Configure logging drivers

批量清理

程序员都是懒惰的,我们不想一个一个的去清理,那就写个脚本,自动化起来。

准备脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
path=/var/lib/docker/containers/
echo ""
echo "========== Clean Docker Containers Log =========="
echo "Path: "$path
cd $path
for file in $(ls)
do
    if [ -d $file ];then
        echo $file"-json.log"
        cat /dev/null > $file/$file-json.log
      else
        echo 0
    fi
done
echo "========== Clean Docker Containers Log =========="
echo ""

把这保存为clean_docker_container_log.sh,记得设置可执行权限,然后执行

1
2
3
$ ./clean_docker_container_log.sh

$ du -h --max-depth=1
1
2
3
4
5
6
....
32K	./b84aafb5508aaa1fa5eb94d25997928ded41f6030b8f6785245cfbee40bd1c20
1.6M	./a89cd1bcecbc43be22bdb792f779059f6b03b716a724ac35cc6a80d70b3f83cd
32K	./b12c8ec602a84f8898b6d5b8318ce858788fe46c7040ed449e4a7051144d380b
32K	./5107888903e6f03d00ff5ea8454a6710fc07a9143dc42fa9a2996ad1c0d84d51
....

还记得之前有个1.6G的容器吗? 现在变成了1.6M,这就是我们要的效果。

自动化

接下来我们自动化起来,配置自动化执行上边的脚本,在对应的机器上配置crontab

  1. crontab -e
  2. 添加如下指令,替换你自己的文件路径
    1
    2
    3
    
     # clean docker container log
     # 每周一3点执行
     0 3 * * 1 sh /root/clean_docker_container_log.sh
    

总结

总之不管是docker原因,还是其它原因,通过正确的方法,找到问题,去解决问题,才是最重要的。

希望以上会对你有所帮助,如果有不对的地方,欢迎指正。

参考资料

Docker Container Log 文件限制

如何清理Docker占用的磁盘空间?

Docker - 清理Docker占用的磁盘空间