今天工作遇到一个问题,docker部署的java后端程序报错No space left on device,空间不足。
以前也遇到一次同样的报错。虽然两次报错都是因为日志太多把空间占满了,但是情况和具体处理方式都不同,在此记录一下。
部署docker应用的虚机,都是/var分区分的100G大小,然后/data分区分的1024G。
第一次遇到的空间占满是由于java程序使用的logback日志框架,日志都保存在容器内的/apps/logs目录下面,然后这个容器长时间运行,但是日志并没有挂载出来,等保要求的日志必须保存超过6个月,恰巧这段时间程序中有个定时任务一直刷日志,导致日志量猛增,就把空间占满了。
今天这次空间占满也是因为日志太大了,日志文件的位置在宿主机的/var/lib/docker/containers/<container-id>/<container-id>-json.log,这个日志文件超过了60G,把/var目录占满了。
先说今天这种情况如何排查,如何解决。
1,首先使用df -h查看磁盘空间占用情况,发现docker所在的目录/var/lib/docker已经100%了,如果是/var没有单独分区,使用的是/根下面的空间,那么有可能是程序挂载出来的目录太大,或者上传的部署包文件日积月累的把空间占满了,但是我部署用的虚机/var目录是单独分区了的,业务使用的文件、日志、配置文件都在/data下面。那只可能是docker的原因。
df -h
2,查看一下docker的磁盘占用情况,发现镜像,容器,挂载,构建缓存都很小,占用不大。
docker system df
3, 管它三七二十一,直接来一波清理。
docker image prune 清理未使用的镜像
docker container prune 清理未启动的容器
docker network prune 清理无用的网络
docker volumes prune 清理无用的挂载
或者直接一次性清理。
docker system prune -af 强制删除关闭的容器、无用的数据卷和网络,虚悬镜像。
清理完了发现没用,空间还是占满了的。
4,查看目录的占用情况,使用du命令,dist usage的简称。
发现docker所在目录占用了39G的大小。
然后就找到一个38G大小的日志文件,就是它占用太大,把空间占满了。
把这个日志文件删除,OK了。
那么如何避免这个日志文件太大,如何控制它的大小。
单个应用,针对docker-compose启动的容器。
version: '3'
services:
redis:
container_name: redis
image: redis:6.2.5
restart: always
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "3"
volumes:
- ./redis/conf/redis.conf:/etc/redis/redis.conf
- ./redis/logs/redis.log:/etc/redis.log
ports:
- "6379:6379"
通过配置这个,控制单个日志文件大小为100M,最多生成三个。
全局配置。
# vim /etc/docker/daemon.json
{
"log-driver":"json-file",
"log-opts": {"max-size":"100m", "max-file":"3"}
}
# systemctl daemon-reload
# systemctl restart docker
那么第一次遇到的,容器内部日志文件没有挂载,导致空间占满,怎么排查到的。
就是通过docker system df命令,看到了Local Volumes占用很大 ,然后就找到了某个容器日志文件太多了,由于定时任务写的有问题,导致一直循环执行,一天就生成2w多个日志文件,把空间占满了。
所以使用docker容器部署,一定要考虑将配置文件,业务生成文件,日志文件挂载出来。
又想到了很久以前遇到的一个沙雕问题,就是业务生成的临时文件没有删除掉,docker容器又长时间运行,日积月累的导致空间满了,就是File类的delelteOnExist方法。
deleteOnExit()这个方法的意思是当JVM退出的时候删除这个文件,我理解成Files.deleteIfExists();这个方法了,如果存在就删除。
exit和exist是不同的。哈哈