本文共 10311 字,大约阅读时间需要 34 分钟。
使用docker目录创建一个volume,并将该volume挂载到容器的/my_Cvol目录下
# docker volume create my_vo# docker run -itd --rm --mount source=my_vol,target=/my_Cvol busybox:latest /bin/sh
查看该volume,其源目录实际在/var/lib/docker/volumes/my_vol/_data下
# docker volume inspect my_vol[ { "CreatedAt": "2018-12-24T22:42:18+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/my_vol/_data", "Name": "my_vol", "Options": null, "Scope": "local" }]
查看使用docker inspect容器相关信息,可以看到volume的挂载信息,挂载到容器中的目录是可读写的。这样在容器的/my_Cvol目录下的操作也会同步到host的/var/lib/docker/volumes/my_vol/_data目录中。
"Mounts": [ { "Type": "volume", "Name": "my_vol", "Source": "/var/lib/docker/volumes/my_vol/_data", "Destination": "/my_Cvol", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" }
查看host上/var/lib/docker/volumes/my_vol/_data的MAC属性可以看到它们变为了容器的MAC属性,这样也防止了容器操作不属于其权限范围的文件
# ls -Z-rw-------. root root system_u:object_r:container_var_lib_t:s0 metadata.dbdrwxr-xr-x. root root system_u:object_r:container_var_lib_t:s0 my_vol
使用tmpfs主要用于存储临时数据,由于tmpfs使用的是共享内存方式,所以其效率比较高。使用tmpfs时有如下2个选项用于指定tmpfs的大小和访问权限:
tmpfs-size:指定tmpfs的大小
tmpfs-mode:指定mount的目录权限
首先安装docker插件
# docker plugin install --grant-all-permissions vieux/sshfs
在node1节点上创建位于node2节点的卷,登陆的ssh密码为root,对端ip为192.168.80.161
# docker volume create --driver vieux/sshfs -o sshcmd=root@192.168.80.161:/home/sshvolume -o password=root sshvolume
在host上查看容器进程的挂载信息,可以看到其实际使用了fuse.sshfs的方式挂载了来自的root@192.168.80.161:/home/sshvolume目录
# cat /proc/19574/mountinfo |grep 176502 399 0:49 / /sshvolume rw,nosuid,nodev,relatime master:176 - fuse.sshfs root@192.168.80.161:/home/sshvolume rw,user_id=0,group_id=0
node1上查看docker卷信息,可以看到新增了drive为vieux/sshfs:latest,名字为sshvolume的卷
# docker volume lsDRIVER VOLUME NAMEvieux/sshfs:latest sshvolume
在node1上创建一个容器,并将上一步的卷挂载到容器,在容器内部创建2个文件夹,登陆到node2的/home/sshvolume,可以看到该目录下有node1的容器创建的文件夹
docker run -itd --mount source=sshvolume,target=/sshvolume busybox:latest /bin/sh
docker storage driver
storage driver负责不同layer之间的交互,它允许在容器的读写层创建数据,读写层数据不会被持久化,且读写效率较低。如所示,容器镜像的layer是只读的,当创建一个容器时,会新增一个读写层,称为”container layer“,对容器的所有修改都在该layer上进行。当容器删除后,该读写层也会被删除。不同的storage driver实现不同,但所有的storage driver都使用了如下栈式镜像结构以及CoW(copy-on-write)策略。这是对的描述
而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。所以无论有多少个容器共享同一个image,所做的写操作都是对从image中复制到自己的文件系统中的复本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。使用CoW可以有效的提高磁盘的利用率。
使用docker ps -s可以查看镜像大小,可以看到"SIZE"有2个值,如container id为5b22377a773d的容器中,38B表示容器读写层的数据总和;virtual表示只读的镜像层加上读写层的大小,不同的容器可能会共用部分或全部的镜像层,因此计算容器占用空间大小不能简单地对virtual进行叠加
# docker ps -sCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE5b22377a773d echo:v1 "/bin/sh" 2 hours ago Up 2 hours practical_darwin 38B (virtual 1.2MB)803ee1eb5acf echo:v1 "sh -c /home/echo.sh" 2 hours ago Up 2 hours hungry_hertz 66B (virtual 1.2MB)
当在5b22377a773d中手动创建一个非空文件之后,可以看到size变为了95B
# docker ps -sCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES SIZE5b22377a773d echo:v1 "/bin/sh" 2 hours ago Up 2 hours practical_darwin 95B (virtual 1.2MB)803ee1eb5acf 6d495122f721 "sh -c /home/echo.sh" 2 hours ago Up 2 hours hungry_hertz 66B (virtual 1.2MB)
当使用docker pull拉取一个容器镜像时,会在/var/lib/docker/<storage-driver>/layers/下面保存各个layer。
容器的读写层只保存修改过的变动,而未修改的文件或目录等则不会被保存在读写层。当修改容器中已经存在的文件时,会执行CoW操作,此时在镜像层中逐层搜索该文件,当找到该文件时,会将文件拷贝到容器的读写层(容器的镜像只读层可共享,但读写层不可以共享,CoW技术可以最大化减小容器占用的磁盘,提高磁盘利用率)。当CoW的读写效率比较低,可能会影响IO效率,需要注意以下2点:
ocker的storage driver使用插件方式提供功能。插件的选择取决于docker的版本以及使用的系统等,对storage driver的选择有如下建议,可以看出目前主要推荐overlay2。overlay和devicemapper已经在docker 18.09版本中被废除
Linux distribution | Recommended storage drivers | Alternative drivers |
---|---|---|
Docker Engine - Community on Ubuntu | overlay2 or aufs (for Ubuntu 14.04 running on kernel 3.13) | overlay , devicemapper , zfs , vfs |
Docker Engine - Community on Debian | overlay2 (Debian Stretch), aufs or devicemapper (older versions) | overlay , vfs |
Docker Engine - Community on CentOS | overlay2 | overlay , devicemapper , zfs , vfs |
Docker Engine - Community on Fedora | overlay2 | overlay , devicemapper , zfs , vfs |
不同storage driver所需要的文件系统如下:
Storage driver | Supported backing filesystems |
---|---|
overlay2 , overlay | xfs with ftype=1, ext4 |
aufs | xfs , ext4 |
devicemapper | direct-lvm |
btrfs | btrfs |
zfs | zfs |
vfs | any filesystem |
不同的storage driver各有优缺点:
在对storage driver修改时需要注意
Important: When you change the storage driver, any existing images and containers become inaccessible. This is because their layers cannot be used by the new storage driver. If you revert your changes, you can access the old images and containers again, but any that you pulled or created using the new driver are then inaccessible.
下面讲解下overlay2的文件结构和特点,首先下载一个centos镜像,查看改镜像有如下3个layer
# docker history centos:latestIMAGE CREATED CREATED BY SIZE COMMENT1e1148e4cc2c 2 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B2 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B 2 months ago /bin/sh -c #(nop) ADD file:6f877549795f4798a… 202MB
使用docker inspect查看该镜像可以看到其文件系统
"GraphDriver": { "Data": { "MergedDir": "/var/lib/docker/overlay2/0bb8525e901534d5c3884a9e47b91d27f887278d0433506126c45081a2a482b8/merged", "UpperDir": "/var/lib/docker/overlay2/0bb8525e901534d5c3884a9e47b91d27f887278d0433506126c45081a2a482b8/diff", "WorkDir": "/var/lib/docker/overlay2/0bb8525e901534d5c3884a9e47b91d27f887278d0433506126c45081a2a482b8/work" }, "Name": "overlay2" },
使用docker run -itd centos:latest /bin/sh启动一个centos的容器,此时会自动创建overlay需要的lowerdir,upperdir,merged和workdir,使用docker inspect命令,可以看到该容器的overlay2使用情况
"GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d-init/diff:/var/lib/docker/overlay2/0bb8525e901534d5c3884a9e47b91d27f887278d0433506126c45081a2a482b8/diff", "MergedDir": "/var/lib/docker/overlay2/7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d/merged", "UpperDir": "/var/lib/docker/overlay2/7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d/diff", "WorkDir": "/var/lib/docker/overlay2/7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d/work" }, "Name": "overlay2" },
merged,upperdir和lowerdir的定义如下,upperdir为容器的读写层,lowerdir为容器的镜像只读层,merged为二者的合集
在容器创建后在/var/lib/docker/overlay2下面会生成2个新的目录,其中7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d-init用于设置容器的初始环境
drwx------. 5 root root 69 Feb 13 22:17 7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0ddrwx------. 4 root root 55 Feb 13 22:17 7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d-init
在7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d目录下可以看到如下文件和目录:diff为该容器的UpperDir,对于容器的读写层,在容器中创建的文件或目录都会体现在该目录中(如下图,在容器的/home下创建一个名为newfile的文件和一个名为newfoler的目录,在diff/home下面也会同步体现该变化)。
# tree -L 1
. ├── diff ├── link ├── lower ├── merged └── work# pwd
/var/lib/docker/overlay2/7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d/diff/home# ll total 0 -rw-r--r--. 1 root root 0 Feb 13 23:52 newfile drwxr-xr-x. 2 root root 6 Feb 13 23:54 newfolder# cat link
SKDGVP5O54VJTAXE7CQNUMIVLQlink中包含了一个指向本目录diff文件夹的索引SKDGVP5O54VJTAXE7CQNUMIVLQ,可以在/var/lib/docker/l目录下找到其定义,其实是个系统链接(l目录存在的意义是防止挂载时符号超出页大小限制--默认4k)。
# ll ../l |grep SKDGVP5O54VJTAXE7CQNUMIVLQlrwxrwxrwx. 1 root root 72 Feb 13 22:17 SKDGVP5O54VJTAXE7CQNUMIVLQ -> ../7aa485418eedcd1443f76018b94b76870de074d732f6e0d5b3e4305a6d896f0d/diff
lower的内容如下,其实就是上述的GraphDriver.Data.LowerDir,对应容器镜像的只读层
# cat lowerl/G6URSFRXVFKZI5ESH2BGXG7LFS:l/T6OXBIDQ2GU523P5CXINFO3VH5
merged为lower和link的合集,work为OverlayFS内部使用的文件夹。
overlayFS读文件时使用时有如下特性:
overlayFS写文件或目录时有如下特性:
由于overlayFS的CoW特性,在容器中需要注意以下2点(详情参见):
TIPS:
参考:
https://docs.docker.com/storage/storagedriver/
https://arkingc.github.io/2017/05/05/2017-05-05-docker-filesystem-overlay/
https://docs.docker.com/storage/storagedriver/overlayfs-driver/
转载地址:http://oxakz.baihongyu.com/