如何释放docker volume未使用空间到主机?需停止容器吗?
是否需要停止对应容器?
不需要提前永久停止容器,仅在需要释放进程占用的文件句柄时,根据业务可接受的中断程度选择操作即可:如果业务完全不允许中断,可通过服务重载释放句柄,全程不中断业务;如果可以接受秒级中断,直接重启对应容器是兼容性最高、操作最简单的方案,重启完成后容器会自动恢复运行。
删了数据空间没释放的核心原因
Linux系统下文件删除后空间不会立刻归还给系统,只有当所有指向该文件的文件句柄都被持有进程关闭,且存储层的空闲块被回收后,空间才会真正在宿主机层面显示为可用。你遇到的情况基本是两类原因:
- 你删除的文件正被容器内运行的进程打开持有,系统仅标记文件为删除状态,未回收对应的磁盘块
- Docker使用块级存储驱动(devicemapper、btrfs、zfs等)时,文件删除后存储层的空闲空间没有做trim回收,仍被Docker存储池占用
具体操作步骤
- 先释放被进程占用的文件句柄
先在宿主机执行命令查找已删除但仍被占用的文件:
从输出结果里核对你之前删除的100GB文件对应的进程,如果确实是目标容器内的进程在占用:lsof | grep deleted- 无中断方案:确认容器内持有句柄的服务,执行服务重载命令让进程重新加载文件、释放旧句柄,比如Nginx服务可执行
docker exec <你的容器名或ID> nginx -s reload,其他常见服务可对应执行重载命令,操作全程服务不中断,句柄释放后空间会自动回收。 - 低中断方案:如果找不到具体是哪个进程占用,或者服务不支持平滑重载,直接执行命令重启对应容器:
重启过程仅会造成对应容器秒级到十几秒的业务中断,容器重新启动后所有旧进程退出,持有的文件句柄会全部释放,被占用的空间会立刻归还宿主机。docker restart <你的容器名或ID>
- 无中断方案:确认容器内持有句柄的服务,执行服务重载命令让进程重新加载文件、释放旧句柄,比如Nginx服务可执行
- 回收存储层未释放的空闲块
如果执行完上一步lsof查不到对应已删除文件的占用记录,空间还是没释放,就是存储层空闲块未回收导致的,根据你用的挂载类型处理:- 绑定挂载(bind mount,即直接把宿主机本地目录挂载进容器的模式):直接对挂载点所在的宿主机分区执行trim命令,比如挂载目录在系统根分区就执行:
执行完成后文件系统会自动标记空闲块,空间会立刻更新为可用。fstrim / - Docker默认管理的volume(文件默认存在
/var/lib/docker/volumes路径下):先执行命令查看Docker的存储驱动:docker info | grep "Storage Driver"- 如果是最常用的overlay2驱动:直接对
/var/lib/docker所在的分区执行fstrim即可,不需要额外操作。 - 如果是devicemapper驱动(常见于老版本Docker):进入容器内部对volume挂载路径执行
fstrim <容器内volume挂载路径>即可将空闲块回收到存储池。 - 如果是btrfs/zfs驱动:btrfs执行
btrfs balance start -dusage=50 /var/lib/docker回收空闲块,zfs执行zfs trim <对应zfs数据集路径>完成回收。
- 如果是最常用的overlay2驱动:直接对
- 绑定挂载(bind mount,即直接把宿主机本地目录挂载进容器的模式):直接对挂载点所在的宿主机分区执行trim命令,比如挂载目录在系统根分区就执行:
- 磁盘100%满导致Docker命令无法执行的应急处理
如果当前磁盘可用空间为0,Docker服务可能因为无法写入元数据无法响应命令,先执行命令清空容器运行日志临时腾挪空间,注意不要直接rm日志文件,否则会因为句柄占用无法释放空间:
腾出几十MB空间后Docker即可恢复响应,再执行前面的步骤完成空间释放。# 找到对应容器的日志路径,执行截断清空 truncate -s 0 /var/lib/docker/containers/<目标容器ID>/<目标容器ID>-json.log
注意:不要在磁盘满的状态下直接手动删除/var/lib/docker路径下的各类文件,很容易损坏Docker存储元数据导致容器、卷数据丢失。
内容的提问来源于stack exchange,提问作者user7976988
相关产品推荐
相关产品推荐

