CI服务器磁盘清理命令
综述
在一台只负责运行 CI 的服务器上,常见堆积这些资源:
- 构建得到的 Image
- 构建过程中的 Build Cache
- 容器日志
- 系统日志
尤其是前两项。在我们项目组的前端CI服务器上,前两项一般每周增长几十GB。
找出大体积目录
sudo du -xh / | sort -rh | head -30
其中第一个参数/表示在哪个目录开始查找。每次运行,找到一个大体积目录后,可以递归执行这条命令。最后得到的结果大概是:
$ sudo du -xhd1 /var/lib/ | sort -rh
# 94G /var/lib/containerd
# 94G /var/lib
# 244M /var/lib/apt
# 132M /var/lib/docker
这就能说明是docker占用了空间。
Docker本身也提供了查询占用的命令:
docker system df -v
清理Image
docker system prune -f
准确地说不仅仅是废弃的镜像,也包括所有的docker认为可以安全删除的资源:
- stopped containers
- unused networks
- dangling images(没有tag、无人引用的镜像层)
- build cache(部分)
这条命令相对安全,可以放心地每周执行一次。由于清理了缓存,会一定程度上降低下次构建速度,不过很快就会恢复。
在此基础上,这条命令支持更多参数:
docker system prune -af --volumes
其中,-a会清理包括有Tag的镜像,--volumes会清理有命名的数据卷。这条命令比较危险,而且也不是日常维护所需,不要使用。
清理构建缓存
上面的命令只能清理大约一半的硬盘占用增长量,剩下的量基本属于构建缓存占用,也就是/var/lib/containerd目录下的东西。
清理命令:
docker builder prune --all
这条命令会彻底清理所有构建缓存,也同样会导致更大程度地降低下次构建速度。构建缓存包括go mod download, pnpm i这类在构建中间步骤安装的依赖。
因此不建议经常使用,只作为发现硬盘空间不足时、手动执行的兜底工具。
不过也有一些辅助参数,可以根据时间或者体积来判断,供参考:
docker builder prune -af --filter "until=168h"
docker builder prune -af --keep-storage 20GB
清理容器日志
一条命令查询所有容器的日志体积:
docker ps -aq | while read id; do
name=$(docker inspect --format='{{.Name}}' $id | cut -c2-)
log=$(docker inspect --format='{{.LogPath}}' $id)
size=$(sudo du -sh $log 2>/dev/null | cut -f1)
echo "$size $name"
done | sort -hr
日志文件的生命周期跟随容器本身,因此清理是容易且不需要操心的。对于某些长期运行的容器,可以考虑配置Docker守护进程来限制日志体积:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
清理系统日志
查询:
journalctl --disk-usage
清理:
sudo journalctl --vacuum-time=7d
定时执行
最常见的定时任务的部署方式无非是crontab,这很简单,但是又很麻烦——我指的是,它“很不云原生”,它需要污染宿主机器。
跟neilpang这位老哥的想法一致,我极度讨厌在一台docker宿主机上安装任何东西,哪怕只是一个简单的shell脚本。
因此我更建议启动一个常驻容器(-d),在容器内运行一个内置了crontab能力的二进制程序(尤其是golang编写的),通过子进程docker cli(甚至是直接进程内RPC)来执行清理或者其他任务。不要反驳我,毕竟,在AI时代,写一个简易版本的crontab的难度跟喝水差不了太多。