这是一篇碎碎念,想到哪儿就写到哪儿。。
官网上说:Docker hosts running the devicemapper storage driver default to a configuration mode known as loop-lvm. This mode uses sparse files to build the thin pool used by image and container snapshots. The mode is designed to work out-of-the-box with no additional configuration. However, production deployments should not run under loop-lvm mode.
所有的资料都说生产环境中建议用direct-lvm进行存储。网上说优点是便于扩容,备份和数据的迁移,还有的说性能更好。
扩容,备份和数据易迁移是使用外挂硬盘的优点,并不能解释为什么devicemapper用direct-lvm存储模式被官方强烈推荐。甚至在第一次启动docker的时候如果devicemapper不是用direct-lvm还会被警告:
WARNING: Usage of loopback devices is strongly discouraged for production use. Either use –storage-opt dm.thinpooldev or use –storage-opt dm.no_warn_on_loop_devices=true to suppress this warning.
性能好这个优点有一定道理,网上有人对此做过性能的测试http://blog.csdn.net/gushenbusi/article/details/49494629,得出结论“direct-lvm直接使用dm-thin内核模块,直接使用raw分区,在高负载和高密度下具有性能优势。”可能我没有在高负载高密度下使用docker的需求,所以使用direct-lvm的性能优势对我作用也不大。
在实际使用过程中碰到的问题是:在centos7.1下使用docker1.8.1,devicemapper的loop-lvm模式。某天发现容器的空间被占满了,于是便将文件清掉。然后发现了奇怪的情况:删除容器内的文件,宿主机并不会释放空间,容器空间依然是被占满的。在对精简池(thin pool),宿主机磁盘,和容器限制大小进行了改变,并在docker1.8.2和docker1.12.6下分别进行实验,发现有以下情况:
在centos7.1下,docker1.8.2和1.12.6容器内文件的变化对宿主机存储空间的影响基本一致:

  • 容器内内生成文件,再删除,宿主机不会释放空间,需要删除容器才会释放空间。
  • 容器内生成文件,再删除,宿主机不会释放空间,再生成文件,宿主机重新可能会重新分配空间;也可能不会重新分配空间。
  • docker1.8.2下:
    资源池预设空间小于宿主机磁盘大小,在容器中生成文件大于容器预设大小时,无法写入文件,但容器不会崩。
    资源池预设空间大于宿主机磁盘大小,在容器中生成文件大于容器预设大小时,无法写入文件,但容器崩,退出后将无法再启动容器。
    docker1.12.6下,当容器中生成文件大于容器预设大小时,无法写入文件,且容器崩溃。
  • 当资源池和宿主机的预设空间大于宿主机空间,在容器中生成文件大于容器预设大小时,宿主机提示磁盘空间占满,docker1.8.2导致了宿主机崩溃,docker1.12.6则不会导致宿主机崩溃,但删除容器后不会释放空间,需要删除devicemapper文件夹。

http://www.cnblogs.com/Andrew-XinFei/p/6245330.html这篇文章中提到:

devicemapper + loop-lvm 还有一个缺陷,因为它是稀疏文件,所以它会不断增长。用户在使用过程中会注意到 /var/lib/docker/devicemapper/devicemapper/data 不断增长,而且无法控制。很多人会希望删除镜像或者可以解决这个问题,结果发现效果并不明显。原因就是这个稀疏文件的空间释放后基本不进行垃圾回收的问题。因此往往会出现即使删除了文件内容,空间却无法回收,随着使用这个稀疏文件一直在不断增长。所以:对于 CentOS/RHEL 的用户来说,在没有办法使用 UnionFS 的情况下,一定要配置 direct-lvm 给 devicemapper,无论是为了性能,稳定性还是空间利用率。

感觉这段话是解决了上述问题。于是便千辛万苦申请了磁盘,设置之后发现情况并没有改变,删除文件磁盘依然不会释放空间,可能对上述文章理解有误吧,总之改成direct-lvm模式也没有解决我的问题。如果容器内有持续增长的文件,比如日志文件这种,撑爆容器是迟早的事情针对这种情况,目前想到的方法是将这些文件外挂到宿主机上,不知道还有没有别的方法。
上文说到千辛万苦挂磁盘,也想说一下。对于设置direct-lvm模式,官网讲得很清楚:https://docs.docker.com/engine/userguide/storagedriver/device-mapper-driver/#configure-docker-with-devicemapper,过了英语四级的小伙伴就不要犯懒了。总之我犯了个懒,还用了百度,百度了中文安装方法。还是上述文章,里面的步骤写的很清楚,但是我运行老是报错,我的环境是centos7.3,docker1.12.6,出现的问题,在起容器的时候会有:
/usr/bin/docker-current: Error response from daemon: shim error: docker-runc not installed on system.
在给容器映射端口的时候有:
/usr/bin/docker-current: Error response from daemon: driver failed programming external connectivity on endpoint stoic_wright (35ded5c721d0ccde517d932e54c4062197a84252a72b951de4fd66fbe6f01d88): exec: “docker-proxy”: executable file not found in $PATH.
仔细对照官网,发现官网在添加direct-pool信息的时候,是将其直接写入配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost Desktop]# vi /usr/lib/systemd/system/docker.service
[Service]
Type=notify
NotifyAccess=all
EnvironmentFile=-/etc/sysconfig/docker
EnvironmentFile=-/etc/sysconfig/docker-storage
EnvironmentFile=-/etc/sysconfig/docker-network
Environment=GOTRACEBACK=crash
Environment=DOCKER_HTTP_HOST_COMPAT=1
Environment=PATH=/usr/libexec/docker:/usr/bin:/usr/sbin
ExecStart=/usr/bin/dockerd-current \
--add-runtime docker-runc=/usr/libexec/docker/docker-runc-current \
--default-runtime=docker-runc \
--exec-opt native.cgroupdriver=systemd \
--userland-proxy-path=/usr/libexec/docker/docker-proxy-current \
--storage-driver=devicemapper \
--storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool \
--storage-opt=dm.use_deferred_removal=true \
--storage-opt=dm.use_deferred_deletion=true
$OPTIONS \

而上述文章采用了drop-in方法(官网也有提及),修改了daemon.conf和daemon.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@srv00 ~]# mkdir /etc/systemd/system/docker.service.d
[root@srv00 ~]# vi /etc/systemd/system/docker.service.d/daemon.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
[root@srv00 ~]# vi /etc/docker/daemon.json
{
"storage-driver": "devicemapper",
"storage-opts": [
"dm.thinpooldev=/dev/mapper/vgdocker-thinpool",
"dm.use_deferred_removal=true",
"dm.use_deferred_deletion=true"
]
}

不同在于ExecStart,原始配置文件启动的是/usr/bin/dockerd-current,而drop-in的方法启动的是/usr/bin/dockerd
进入/usr/libexec/docker/文件夹,确实没有docker-runcdocker-proxy存在,有的是docker-runc-currentdocker-proxy-current。加上两个软连接,问题解决:

1
2
3
# cd /usr/libexec/docker/
# sudo ln -s docker-runc-current docker-runc
# sudo ln -s docker-proxy-current docker-proxy

使用配置文件本来是件好事,比如修改配置不必重启服务,只需发送SIGHUP信号即可。
但是目前在dockerd中使用配置文件会有一些问题:例如无法得知具体哪项生效了,启动日志以及docker info,还有ps -ef都不会给出生效配置,这对于排障很不方便。
当 dockerd的参数和daemon.json文件中的配置有所重复或者冲突,会直接导致引擎启动失败。因此在这些问题解决前,先使用修改docker.service这类做法来实现。
https://blog.lab99.org/post/docker-2016-07-14-faq.html这篇文章解决了我的很多疑惑,对初学者很有意义。