Docker 故障device or resource busy

Docker 故障device or resource busy


概述:最近遇到几次出现device or resource busy的报错,当时以为是devicemapper系统的问题但是经过查资料发现这是docker的一个bug,所以就总结了下面这个写内容,希望跟大家多多交流。

出现故障原因

  1. .CentOS/RedHat 3.10.0内核NameSpace bug,由于Systemd PrivateTmp设置导致私有名字空间维护挂接磁盘状态影响全局空间卸载磁盘。
  2. Docker在创建,运行,和新增container和image的时候不会出现这个bug,仅仅是在销毁container的时候由于无法卸载挂接镜像的磁盘导致出错。
  3. Docker 无论使用哪种storage-driver均有此问题,问题并不仅仅出现在使用devicemapper storage-driver时。
  4. 任何使用unshare方式运行的进程均会激活此Bug。
  5. Centos7中默认会激活此类Bug的除了ntp服务外还有好多包括:brandbot.service,dbus-org.freedesktop.hostname1.service,dbus-org.freedesktop.import1.service,dbus-org.freedesktop.locale1.service,dbus-org.freedesktop.machine1.service,dbus-org.freedesktop.timedate1.service,httpd.service,systemd-hostnamed.service,systemd-importd.service,systemd-localed.service,systemd-machined.service,systemd-timedated.service。(ntp的bug我测试过17.12.0-ce这个版本的docker是没有出现的,但是不保证其他服务不会出现,也不保证在这个版本之前不会出现)

解决问题方法

  1. 尽量去装新版本的docker,因为新版本的会更多的修复以前的bug。
  2. 启动docker服务前修改/usr/lib/systemd/system/docker.service配置文件[Service]段中加入MountFlags=slave,然后systemctl daemon-reload,重新启动docker后,docker container挂接的磁盘将独立于全局磁盘挂接,不会再受到“Systemd PrivateTmp”影响。
  3. 如果在删除Containers出现报错这里写图片描述
    将做以下修复:
    1) 找到死掉的容器的对应ID
    docker ps -a | grep "死掉容器的名字"

    2) 删除id并会出现报错
    docker rm -f
    报错如下:remove
    /var/lib/docker/devicemapper/mnt/0e8fb9207ba6720ca61f911e751a649f5563586f170cf294750032eb9ae035a5: device or resource busy

    3) umount掉这个对应的磁盘:
    umount /var/lib/docker/devicemapper/mnt/0e8fb9207ba6720ca61f911e751a649f5563586f170cf294750032eb9ae035a5

然后我们就会发现我们的容器被删掉了

为了避免在删除容器的时候出现此类报错我们也可以在删除容器之前执行一个脚本:
#!/bin/bash
for i in $(curl -s --unix /var/run/docker.sock http://localhost/info | jq -r .DockerRootDir) /var/lib/docker; do
for m in $(tac /proc/mounts | awk '{print $2}' | grep ^${i}/); do
umount $m || true
done
done

主要目的是把多余mount的path卸载掉,这样就不会因为同时挂载导致device or resource busy问题。


其他概念

Systemd PrivateTmp : True/yes
使用独立的挂接空间运行服务,默认执行时继承系统全局挂接空间。
Systemd MountFlags: share/slave/private
设置文件系统的挂载传递标记,可设为 shared, slave, private 之一。 这些标记控制着文件系统挂载点的挂载和卸载动作如何在主机与容器之间传递。 shared 表示 挂载和卸载将会在主机和容器之间同步(双向可见); slave表示容器内的挂载和卸载不会传递到主机, 但主机中挂载的文件系统依然对容器内的进程可见。 private表示主机的挂载和卸载不会传递到容器, 同时容器中的挂载亦不会传递到主机中(双向不可见)。 本选项的默认值一般是 shared , 但如果使用了PrivateTmp=, PrivateDevices=, ProtectSystem=, ProtectHome=, ReadOnlyPaths=, InaccessiblePaths=, ReadWritePaths=选项之一, 那么本选项的默认值将会 自动从 slave降级到 private , 因为这些选项要求挂载和卸载必须不能从容器传递到主机。

参考:

[参考文档](http://niusmallnan.com/2016/12/27/docker-device-resource-busy/)
[参考文档](http://blog.kissingwolf.com/2017/09/09/Docker-%E6%95%85%E9%9A%9C%EF%BC%88device-or-resource-busy%EF%BC%89/)

你可能感兴趣的:(Docker)