Home Archives Categories Tags

Docker、AUFS、inode耗尽和一个小工具

发布时间: 更新时间: 总字数:1218 阅读时间:3m 作者: 分享

使用docker过程中,遇到No space left on device,刚开始以为是没有存储空间,后来发现是inode耗尽导致。

问题

遇到过这样的错误吧:

No space left on device

然而当 df -H 的时候,又是这样:

# df -H

Filesystem Size Used Avail Use% Mounted on
 udev 1.1G 4.1k 1.1G 1% /dev
 tmpfs 210M 758k 209M 1% /run
 /dev/xvda1 43G 18G 23G 45% /

明明还有那么多空间。。。当然,有经验的人肯定立刻就想到了:

# df -i

Filesystem Inodes IUsed IFree IUse% Mounted on
 udev 253256 430 252826 1% /dev
 tmpfs 255939 473 255466 1% /run
 /dev/xvda1 2621440 2618687 2753 100% /

原来是 inode 耗尽了。

原因

Inode 全名 Index Node,主要是用于保存文件大小、类型等文件系统对象(文件、目录)的元数据,它本身并不存储实际数据,一个文件或者文件夹都对应一个 inode

Inode 的总数和大小是在创建文件系统时候指定的,文件系统创建后就不能更改。所以在你创建了大量的文件、文件夹和链接( symlink )之后,你的 inode 资源就会越来越少了。

Inode 耗尽应该算是在 Docker 下使用 AUFS 常见的问题了。众所周知, AUFS 是 Docker 最先支持的存储驱动,具备速度快、节省存储空间、管理简单等优点,尽管 Linux 内核并不直接支持 AUFS ,但不妨碍很多 Ubuntu 用户直接使用 AUFS 。

但是我们也不能就这么简单地把锅甩给 AUFS ,还是要自己做好应用程序的监控和设计。

工具

这里介绍一个简单、方便的工具: inodes ( https://github.com/tripflex/inodes ) ,这个工具可以方便计算指定文件夹的inodes使用情况,你再也不必使用 find + for + df 这些网上流传的各种命令组合了。

安装非常简单,只需要下载二进制文件就可以了:

wget -O /bin/inodes https://raw.smyl.es/inodes/master/inodes
chmod +x /bin/inodes

使用也简单,参数如下:

  • -d inodes -d /path/to/dir 可选。要查看的路径,默认使用当前目录。
  • -t inodes -t 50000 可选。树形显示使用超过了50000个 inode 的目录。
  • -e inodes -e 100 可选。过滤掉使用inode小于100个的目录。

这个应用执行后结果大概是这样的:

------------------------------------------
	INODE USAGE SUMMARY
------------------------------------------
    INODES |       SIZE | DIRECTORY
------------------------------------------
  1        |   4.0K     | bin
  1        |   4.0K     | etc
  1        |   4.0K     | games
  1        |   4.0K     | include
  1        |   4.0K     | lib
  1        |   4.0K     | lib64
  1        |   4.0K     | libexec
  1330     |   313M     | qcloud
  1        |   4.0K     | sbin
  23       |   92K      | share
  1        |   4.0K     | src
------------------------------------------
1364       | 313M       | /usr/local/
------------------------------------------

解决

首先找到inode到底都被哪些目录占用了,方法可采用上面介绍的工具,但是这个过程可能比较耗时,甚至几个小时。

然后,清除没有用的东西即可:比如镜像、容器和Volume。

删除没用的镜像:

docker images -qf dangling=true | xargs docker rmi

删除没用的Volume:

docker volume ls -qf dangling=true |xargs docker volume rm

再不行,备份数据,重新格式化或者加硬盘,在创建文件系统的时候,指定一个比较大的inode数,比如:

mkfs -t ext4 -N

或者干脆换不使用 inode 的文件系统,比如 btrfs 或 DeviceMapper 。

建议

关于如何使用 Docker + AUFS ,官方有一份详细的说明 ( https://docs.docker.com/engine/userguide/storagedriver/aufs-driver/ ),大家可以参考下。其中说道了 Volume ,由于 Volume 略过了存储驱动,所以就省去了一些必要的初始化设置工作和 CoW ,所以重 IO 的数据都推荐使用 Volume 。

这里其实有一个问题, 如果 Docker 镜像中定义了 Volume ,而启动的时候又没有通过 -v 选项为定义的 Volume 指定绑定的 HOST 路径,那么 Docker 就会自动在/var/lib/docker/volumes/ 文件夹下面创建一个 Volume 供新启动的容器使用。

坑爹的地方在于,如果你通过 docker rm 命令删除这个容器的时候, Docker 默认是不会删除这些默认创建的 Volume 的。

那么这里大叔就给大家一些建议:

  • 有一说一,没用的 Volume 别写到 Dockerfile 里去
  • 写到了 Dockerfile ,就尽量为其指定宿主机路径
  • 删除的时候使用 -v 选项

参考

最新评论
加载中...