• 0

  • 456

  • 收藏

docker-3.5 graphdriver

None

关注Linux

1星期前

OverlayFS介绍

OverlayFS是一种堆叠文件系统,它依赖并建立在其它的文件系统之上(例如ext4fs和xfs等等),并不直接参与磁盘空间结构的划分,仅仅将原来底层文件系统中不同的目录进行“合并”,然后向用户呈现,这也就是联合挂载技术,对比于AUFS,OverlayFS速度更快,实现更简单。 而Linux 内核为Docker提供的OverlayFS驱动有两种:overlay和overlay2。而overlay2是相对于overlay的一种改进,在inode利用率方面比overlay更有效。但是overlay有环境需求:docker版本17.06.02+,宿主机文件系统需要是ext4或xfs格式。

联合挂载

overlayfs通过三个目录:lower目录、upper目录、以及work目录实现,其中lower目录可以是多个,work目录为工作基础目录,挂载后内容会被清空,且在使用过程中其内容用户不可见,最后联合挂载完成给用户呈现的统一视图称为为merged目录。

演示

使用mount命令挂载overlayfs语法如下:

mount -t overlay overlay -o lowerdir=lower1:lower2:lower3,upperdir=upper,workdir=work merged_dir

mkdir -p /tmp/test A A/aa B C worker
echo "from A" > A/a.txt
echo "from B" > B/b.txt
echo "from C" > C/c.txt
mount -t overlay overlay -o lowerdir=A:B:lower3,upperdir=C,workdir=worker /tmp/test

ll /tmp/test
total 16
drwxr-xr-x 2 root root 4096 Oct 21 20:24 aa
-rw-r--r-- 1 root root    7 Oct 21 20:23 a.txt
-rw-r--r-- 1 root root    7 Oct 21 20:24 b.txt
-rw-r--r-- 1 root root    7 Oct 21 20:24 c.txt

mount |grep test
overlay on /tmp/test type overlay (rw,relatime,lowerdir=A:B,upperdir=C,workdir=worker)
复制代码

Docker中的overlay驱动

介绍了overlay驱动原理以后再来看Docker中的overlay存储驱动,以下是来自docker官网关于overlay的工作原理图:

在上述图中可以看到三个层结构,即:lowerdir、uperdir、merged,

  • lowerdir是只读的image layer,其实就是rootfs,对比我们上述演示的目录A和B,我们知道image layer可以分很多层,所以对应的lowerdir是可以有多个目录。
  • upperdir则是在lowerdir之上的一层,这层是读写层,在启动一个容器时候会进行创建,所有的对容器数据更改都发生在这里层,对比示例中的C。
  • merged目录是容器的挂载点,也就是给用户暴露的统一视角,对比示例中的/tmp/test。

而这些目录层都保存在了/var/lib/docker/overlay2/或者/var/lib/docker/overlay/(如果使用overlay)。

演示

docker run -it --name busybox busybox:latest sh
mount |grep overlay

ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var

mount |grep overlay
overlay on / type overlay (rw,relatime,lowerdir=/export/App/docker/overlay2/l/ZADXGS7J7SCVNZFOPBVA5DGDKA:/export/App/docker/overlay2/l/2NFGMN2NYKTZAIGDJOHC3RB64C,upperdir=/export/App/docker/overlay2/a8866f1095d5d24b04cfa39a600a68a2e027590090381e661561b40b043c56be/diff,workdir=/export/App/docker/overlay2/a8866f1095d5d24b04cfa39a600a68a2e027590090381e661561b40b043c56be/work)
复制代码

如何工作

当容器中发生数据修改时候overlayfs存储驱动又是如何进行工作的?以下将阐述其读写过程:

读:

  • 如果文件在容器层(upperdir),直接读取文件;
  • 如果文件不在容器层(upperdir),则从镜像层(lowerdir)读取;

修改:

  • 首次写入: 如果在upperdir中不存在,overlay和overlay2执行copy_up操作,把文件从lowdir拷贝到upperdir,由于overlayfs是文件级别的(即使文件只有很少的一点修改,也会产生的copy_up的行为),后续对同一文件的在此写入操作将对已经复制到容器的文件的副本进行操作。这也就是常常说的写时复制(copy-on-write)
  • 删除文件和目录: 当文件在容器被删除时,在容器层(upperdir)创建whiteout文件,镜像层(lowerdir)的文件是不会被删除的,因为他们是只读的,但without文件会阻止他们显示,当目录在容器内被删除时,在容器层(upperdir)一个不透明的目录,这个和上面whiteout原理一样,阻止用户继续访问,即便镜像层仍然存在。 

注意事项

  • copy_up操作只发生在文件首次写入,以后都是只修改副本,
  • overlayfs只适用两层目录,,相比于比AUFS,查找搜索都更快。
  • 容器层的文件删除只是一个“障眼法”,是靠whiteout文件将其遮挡,image层并没有删除,这也就是为什么使用docker commit 提交保存的镜像会越来越大,无论在容器层怎么删除数据,image层都不会改变。

overlay2镜像存储结构

演示

docker pull ubuntu:latest
latest: Pulling from library/ubuntu
22e816666fd6: Pull complete 
079b6d2a1e53: Pull complete 
11048ebae908: Pull complete 
c58094023a2e: Pull complete 
Digest: sha256:a7b8b7b33e44b123d7f997bd4d3d0a59fafc63e203d17efedf09ff3f6f516152

ll /export/docker/overlay2/
total 20
drwx------ 3 root root 4096 Oct 24 17:33 838141f4c7c9149154205bac27d4ae0ae086dfdc4f413407c353a97f3d43ae02
drwx------ 4 root root 4096 Oct 24 17:33 9b82d3a2c058b274dd1051fc0e2c4c9ca1f2793cbdf297aff0fcd10716e991ef
drwx------ 4 root root 4096 Oct 24 17:33 a907b9c7b7bfd96c1441b1a9edc3bea3bc61f2b33fc58e86e3ab68cde9e77e2f
drwx------ 4 root root 4096 Oct 24 17:33 ba3c23adebb270971f52a2a2d21c6893f11526e57528364bf45313d6278719dd
drwxr-xr-x 2 root root 4096 Oct 24 17:33 l

# 这里面多了一个l目录包含了所有层的软连接,短链接使用短名称,避免mount时候参数达到页面大小限制(演示中mount命令查看时候的短目录):
ll /export/docker/overlay2/l/
total 16
lrwxrwxrwx 1 root root 72 Oct 24 17:33 AO2U6ITJIKIGXU7M2IJYXDD6N6 -> ../838141f4c7c9149154205bac27d4ae0ae086dfdc4f413407c353a97f3d43ae02/diff
lrwxrwxrwx 1 root root 72 Oct 24 17:33 JKGV2VMSBGJHYRN5XLAB5NVKOH -> ../ba3c23adebb270971f52a2a2d21c6893f11526e57528364bf45313d6278719dd/diff
lrwxrwxrwx 1 root root 72 Oct 24 17:33 VYRTWUOWCPSALLE5VBODX5GJO4 -> ../a907b9c7b7bfd96c1441b1a9edc3bea3bc61f2b33fc58e86e3ab68cde9e77e2f/diff
lrwxrwxrwx 1 root root 72 Oct 24 17:33 YIAHNEKOMA24I4LWRIDEODBZ2H -> ../9b82d3a2c058b274dd1051fc0e2c4c9ca1f2793cbdf297aff0fcd10716e991ef/diff

# 在这之上的镜像还多了work目录和lower文件,lower文件用于记录父层的短名称,work目录用于联合挂载指定的工作目录。
ll ba3c23adebb270971f52a2a2d21c6893f11526e57528364bf45313d6278719dd/
total 16
drwxr-xr-x 3 root root 4096 Oct 24 17:33 diff
-rw-r--r-- 1 root root   26 Oct 24 17:33 link
-rw-r--r-- 1 root root   86 Oct 24 17:33 lower
drwx------ 2 root root 4096 Oct 24 17:33 work
复制代码

而这些目录和镜像的关系是怎么组织在的一起呢?答案是通过元数据关联。元数据分为image元数据和layer元数据。

image元数据

镜像元数据存储在了/var/lib/docker/image/<storage_driver>/imagedb/content/sha256/目录下,名称是以镜像ID命名的文件,镜像ID可通过docker images查看,这些文件以json的形式保存了该镜像的rootfs信息、镜像创建时间、构建历史信息、所用容器、包括启动的Entrypoint和CMD等等。例如ubuntu镜像的id为cf0f3ca922e0:

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              cf0f3ca922e0        5 days ago          64.2MB

cat /export/docker/image/overlay2/imagedb/content/sha256/cf0f3ca922e08045795f67138b394c7287fbc0f4842ee39244a1a1aaca8c5e1c   
{
    "architecture": "amd64",
    "config": {
        "Hostname": "",
        "Domainname": "",
        "User": "",
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
            "PATH=/usr/local/sb
in:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Cmd": [
            "/bin/bash"
        ],
        "ArgsEscaped": true,
        "Image": "sha256:79762efc126691a84ceec9ff37eb51494597a4be3dfb55bb28319edf7d029f04",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypo
int": null,
        "OnBuild": null,
        "Labels": null
    },
    "container": "9cd5aac672039c24c1fc7578b06045a02fdeb97141f53851909df81f5bdf2627",
    "container_config": {
        "Hostname": "9cd5aac67203",
        "Domainname": "",
        "User": "",
        "AttachStdin": false,
        "AttachStdout": false,
        "AttachStderr": false,
        "Tty": false,
        "OpenStdin": false,
        "StdinOnce": false,
        "Env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
        ],
        "Cmd": [
            "/bin/sh",
            "-c",
            "#(nop) ",
            "CMD [\"/bi
n/bash\"]"
        ],
        "ArgsEscaped": true,
        "Image": "sha256:79762efc126691a84ceec9ff37eb51494597a4be3dfb55bb28319edf7d029f04",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": null,
        "OnBuild": null,
        "Labels": {
            
        }
    },
    "created": "2019-10-1
8T18:48:51.632346407Z",
    "docker_version": "18.06.1-ce",
    "history": [
        {
            "created": "2019-10-18T18:48:49.35320434Z",
            "created_by": "/bin/sh -c #(nop) ADD file:d13b09e8b3cc98bf0868e2af7a49b14622d2111e2a4e10341859902e43bd87
2a in / "
        },
        {
            "created": "2019-10-18T18:48:50.103034647Z",
            "created_by": "/bin/sh -c [ -z \"$(apt-get indextargets)\" ]"
        },
        {
            "created": "2019-10-18T18:48:50.787856146Z",
            "created_by": "/bin/sh -c set -xe \t\t\u0026\u0026
 echo '#!/bin/sh' \u003e /usr/sbin/policy-rc.d \t\u0026\u0026 echo 'exit 101' \u003e\u003e /usr/sbin/policy-rc.d \t\u0026\u0026 chmod +x /usr/sbin/policy-rc.d \t\t\u0026\u0026 dpkg-divert --local --rename --add
 /sbin/initctl \t\u0026\u0026 cp -a /usr/sbin/policy-rc.d /sbin/initctl \t\u0026\u0026 sed -i 's/^exit.*/exit 0/' /sbin/initctl \t\t\u0026\u0026 echo 'force-unsafe-io' \u003e /etc/dpkg/dpkg.cfg.d/docker-apt-spe
edup \t\t\u0026\u0026 echo 'DPkg::Post-Invoke { \"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\"; };' \u003e /etc/apt/apt.conf.d/docker-clean \t\u0026\u
0026 echo 'APT::Update::Post-Invoke { \"rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true\"; };' \u003e\u003e /etc/apt/apt.conf.d/docker-clean \t\u0026\u0026
 echo 'Dir::Cache::pkgcache \"\"; Dir::Cache::srcpkgcache \"\";' \u003e\u003e /etc/apt/apt.conf.d/docker-clean \t\t\u0026\u0026 echo 'Acquire::Languages \"none\";' \u003e /etc/apt/apt.conf.d/docker-no-languages
 \t\t\u0026\u0026 echo 'Acquire::GzipIndexes \"true\"; Acquire::CompressionTypes::Order:: \"gz\";' \u003e /etc/apt/apt.conf.d/docker-gzip-indexes \t\t\u0026\u0026 echo 'Apt::AutoRemove::SuggestsImportant \"fals
e\";' \u003e /etc/apt/apt.conf.d/docker-autoremove-suggests"
        },
        {
            "created": "2019-10-18T18:48:51.466908877Z",
            "created_by": "/bin/sh -c mkdir -p /run/systemd \u0026\u0026 echo 'docker' \u003e /run/systemd/container"
        },
        {
            "created": "2019-10-18T18:48:51.632346407Z",
            "created_by": "/bin/sh -c #(nop)  CMD [\"/bin/bash\"]",
            "empty_layer": true
        }
    ],
    "os": "linux",
    "rootfs": {
        "type": "layers",
        "diff_ids": [
            "sha256:a090697502b8d19fbc83afb24d8fb59b01e48bf87763a00ca55cfff42423ad36",
            "sha256:97e6b67a30f1efeb050ada13c2afa1afd748e175ae744027dd0cce1f2931a594",
            "sha256:100ef12ce3a46c3242d186dbbadedff1638dc1f69cab4e1fbf73489049c01c25",
            "sha256:19331eff40f01dd084a3f966cc6939e828d617d777163706b8a13d0f972704d1"
        ]
    }
}
复制代码

上面的 diff_id 对应的的是一个镜像层,其排列也是有顺序的,从上到下依次表示镜像层的最低层到最顶层: diff_id如何关联进行层?具体说来,docker 利用 rootfs 中的每个diff_id 和历史信息计算出与之对应的内容寻址的索引(chainID) ,而chaiID则关联了layer层,进而关联到每一个镜像层的镜像文件。

layer元数据

  镜像层只包含一个具体的镜像层文件包。用户在 docker 宿主机上下载了某个镜像层之后,docker 会在宿主机上基于镜像层文件包和 image 元数据构建本地的 layer 元数据,包括 diff、parent、size 等。而当 docker 将在宿主机上产生的新的镜像层上传到 registry 时,与新镜像层相关的宿主机上的元数据也不会与镜像层一块打包上传。

  Docker 中定义了 Layer 和 RWLayer 两种接口,分别用来定义只读层和可读写层的一些操作,又定义了 roLayer 和 mountedLayer,分别实现了上述两种接口。其中,roLayer 用于描述不可改变的镜像层,mountedLayer 用于描述可读写的容器层。

roLayer

  具体来说,roLayer 存储的内容主要有索引该镜像层的 chainID、该镜像层的校验码 diffID、父镜像层 parent、storage_driver 存储当前镜像层文件的 cacheID、该镜像层的 size 等内容。这些元数据被保存在 /var/lib/docker/image/<storage_driver>/layerdb/sha256/<chainID>/ 文件夹下。如下: 

ll /export/docker/image/overlay2/layerdb/sha256
total 16
drwx------ 2 root root 4096 Oct 24 17:33 a090697502b8d19fbc83afb24d8fb59b01e48bf87763a00ca55cfff42423ad36
drwx------ 2 root root 4096 Oct 24 17:33 b9997ded97a1c277d55be0d803cf76ee6e7b2e8235d610de0020a7c84c837b93
drwx------ 2 root root 4096 Oct 24 17:33 c808877c0adcf4ff8dcd2917c5c517dcfc76e9e8a035728fd8f0eae195d11908
drwx------ 2 root root 4096 Oct 24 17:33 cdf75cc6b4d28e72a9931be2a88c6c421ad03cbf984b099916a74f107e6708ff
复制代码
ll /export/docker/overlay2/
total 20
drwx------ 3 root root 4096 Oct 24 17:33 838141f4c7c9149154205bac27d4ae0ae086dfdc4f413407c353a97f3d43ae02
drwx------ 4 root root 4096 Oct 24 17:33 9b82d3a2c058b274dd1051fc0e2c4c9ca1f2793cbdf297aff0fcd10716e991ef
drwx------ 4 root root 4096 Oct 24 17:33 a907b9c7b7bfd96c1441b1a9edc3bea3bc61f2b33fc58e86e3ab68cde9e77e2f
drwx------ 4 root root 4096 Oct 24 17:33 ba3c23adebb270971f52a2a2d21c6893f11526e57528364bf45313d6278719dd
复制代码

  每个chainID目录下会存在三个文件cache-id、diff、size: cache-id文件:docker随机生成的uuid,内容是保存镜像层的目录索引,也就是/var/lib/docker/overlay2/中的目录,这就是为什么通过chainID能找到对应的layer目录。   

  以chainID为d801a12f6af7beff367268f99607376584d8b2da656dcd8656973b7ad9779ab4 对应的目录为 130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5,也就保存在/var/lib/docker/overlay2/130ea10d6f0ebfafc8ca260992c8d0bef63a1b5ca3a7d51a5cd1b1031d23efd5

# cat a090697502b8d19fbc83afb24d8fb59b01e48bf87763a00ca55cfff42423ad36/cache-id 
838141f4c7c9149154205bac27d4ae0ae086dfdc4f413407c353a97f3d43ae02
# cat b9997ded97a1c277d55be0d803cf76ee6e7b2e8235d610de0020a7c84c837b93/cache-id 
9b82d3a2c058b274dd1051fc0e2c4c9ca1f2793cbdf297aff0fcd10716e991ef
# cat c808877c0adcf4ff8dcd2917c5c517dcfc76e9e8a035728fd8f0eae195d11908/cache-id 
ba3c23adebb270971f52a2a2d21c6893f11526e57528364bf45313d6278719dd
# cat cdf75cc6b4d28e72a9931be2a88c6c421ad03cbf984b099916a74f107e6708ff/cache-id 
a907b9c7b7bfd96c1441b1a9edc3bea3bc61f2b33fc58e86e3ab68cde9e77e2f
复制代码

diff文件:保存了镜像元数据中的diff_id(与元数据json中的diff_ids中的uuid对应) 在 layer 的所有属性中,diffID 采用 SHA256 算法,基于镜像层文件包的内容计算得到。而 chainID 是基于内容存储的索引,它是根据当前层与所有祖先镜像层 diffID 计算出来的,具体算如下: 如果该镜像层是最底层(没有父镜像层),该层的 diffID 便是 chainID。该镜像层的 chainID 计算公式为 chainID(n)=SHA256(chain(n-1) diffID(n)),也就是根据父镜像层的 chainID 加上一个空格和当前层的 diffID,再计算 SHA256 校验码。 

# cat a090697502b8d19fbc83afb24d8fb59b01e48bf87763a00ca55cfff42423ad36/diff 
sha256:a090697502b8d19fbc83afb24d8fb59b01e48bf87763a00ca55cfff42423ad36
# cat b9997ded97a1c277d55be0d803cf76ee6e7b2e8235d610de0020a7c84c837b93/diff 
sha256:97e6b67a30f1efeb050ada13c2afa1afd748e175ae744027dd0cce1f2931a594
# cat c808877c0adcf4ff8dcd2917c5c517dcfc76e9e8a035728fd8f0eae195d11908/diff 
sha256:19331eff40f01dd084a3f966cc6939e828d617d777163706b8a13d0f972704d1
# cat cdf75cc6b4d28e72a9931be2a88c6c421ad03cbf984b099916a74f107e6708ff/diff 
sha256:100ef12ce3a46c3242d186dbbadedff1638dc1f69cab4e1fbf73489049c01c25
复制代码

size文件:保存了镜像层的大小

mountedLayer

mountedLayer 信息存储的可读init层以及容器挂载点信息包括:容器 init 层ID(init-id)、联合挂载使用的ID(mount-id)以及容器层的父层镜像的 chainID(parent)。相关文件位于/var/lib/docker/image/<storage_driver>/layerdb/mounts/<container_id>/ 目录下。 可以看到initID是在mountID后加了一个-init,同时initID就是存储在/var/lib/docker/overlay2/的目录名称:

查看mountID还可以直接通过mount命令查看对应挂载的mountID,对应着/var/lib/docker/overlay2/目录,这也是overlayfs呈现的merged目录:

关于init层  init层是以一个uuid+-init结尾表示,夹在只读层和读写层之间,作用是专门存放/etc/hosts、/etc/resolv.conf等信息,需要这一层的原因是当容器启动时候,这些本该属于image层的文件或目录,比如hostname,用户需要修改,但是image层又不允许修改,所以启动时候通过单独挂载一层init层,通过修改init层中的文件达到修改这些文件目的。而这些修改往往只读当前容器生效,而在docker commit提交为镜像时候,并不会将init层提交。该层文件存放的目录为/var/lib/docker/overlay2/<init_id>/diff 

docker run -it --name test ubuntu:latest /bin/bash
root@079d1e912224:/# echo "test" > /tmp/test
root@079d1e912224:/# mount |grep overlay
overlay on / type overlay (rw,relatime,lowerdir=/export/docker/overlay2/l/W5IG7GJ5GPVE2KH6U6QF227O6C:/export/docker/overlay2/l/JKGV2VMSBGJHYRN5XLAB5NVKOH:/export/docker/overlay2/l/VYRTWUOWCPSALLE5VBODX5GJO4:/export/docker/overlay2/l/YIAHNEKOMA24I4LWRIDEODBZ2H:/export/docker/overlay2/l/AO2U6ITJIKIGXU7M2IJYXDD6N6,upperdir=/export/docker/overlay2/b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1/diff,workdir=/export/docker/overlay2/b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1/work)


ll /export/docker/image/overlay2/layerdb/mounts/079d1e912224e0a00f77612d4f5731027055d3d02e8f6912298d67a852900d21/
init-id   mount-id  parent   

cat /export/docker/image/overlay2/layerdb/mounts/079d1e912224e0a00f77612d4f5731027055d3d02e8f6912298d67a852900d21/init-id   
b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1-init

cat /export/docker/image/overlay2/layerdb/mounts/079d1e912224e0a00f77612d4f5731027055d3d02e8f6912298d67a852900d21/mount-id 
b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1

cat /export/docker/image/overlay2/layerdb/mounts/079d1e912224e0a00f77612d4f5731027055d3d02e8f6912298d67a852900d21/parent 
sha256:c808877c0adcf4ff8dcd2917c5c517dcfc76e9e8a035728fd8f0eae195d11908

ll /export/docker/overlay2/
total 28
drwx------ 3 root root 4096 Oct 24 17:33 838141f4c7c9149154205bac27d4ae0ae086dfdc4f413407c353a97f3d43ae02
drwx------ 4 root root 4096 Oct 24 17:33 9b82d3a2c058b274dd1051fc0e2c4c9ca1f2793cbdf297aff0fcd10716e991ef
drwx------ 4 root root 4096 Oct 24 17:33 a907b9c7b7bfd96c1441b1a9edc3bea3bc61f2b33fc58e86e3ab68cde9e77e2f
drwx------ 5 root root 4096 Oct 24 18:06 b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1
drwx------ 4 root root 4096 Oct 24 18:06 b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1-init
drwx------ 4 root root 4096 Oct 24 17:33 ba3c23adebb270971f52a2a2d21c6893f11526e57528364bf45313d6278719dd
drwxr-xr-x 2 root root 4096 Oct 24 18:06 l

cat b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1/diff/tmp/test 
test

cat b65d22f08f3a34bc7fd2afb4f2e534980f17f549bfeed6a40933396e9de665f1/merged/tmp/test 
test
复制代码

通过以上的内容介绍,一个容器完整的层应由三个部分组成,如下图: 镜像层:也称为rootfs,提供容器启动的文件系统 init层: 用于修改容器中一些文件如/etc/hostname、/etc/resolv.conf等容器层:使用联合挂载统一给用户提供的可读写目录

挂载

FROM ubuntu:14.04 :设置基础镜像,此时会使用基础镜像ubuntu:14.04的所* 有镜像层,为简单起见,图中将其作为一个整体展示。

ADD run.sh /:将Dockerfile所在目录的文件run.sh加至镜像的根目录,此时新一层的镜像只有一项内容,即根目录下的run.sh.

VOLUME /data:设定镜像的VOLUME,此VOLUME在容器内部的路径为/data。需要注意的是,此时并未在新一层的镜像中添加任何文件,但更新了镜像的json文件,以便通过此镜像启动容器时获取这方面的信息。

CMD ["./run.sh"]:设置镜像的默认执行入口,此命令同样不会在新建镜像中添加任何文件,仅仅在上一层镜像json文件的基础上更新新建镜像的json文件。

图中的顶上两层,是Docker为Docker容器新建的内容,而这两层属于容器范畴。 这两层分别为Docker容器的初始层(Init Layer)与可读写层(Read-Write Layer)。

初始层: 大多是初始化容器环境时,与容器相关的环境信息,如容器主机名,主机host信息以及域名服务文件等。

读写层: Docker容器内的进程只对可读写层拥有写权限,其他层对进程而言都是只读的(Read-Only)。 另外,关于VOLUME以及容器的hosts、hostname、resolv.conf文件等都会挂载到这里。

参考

overlayfs

Docker 联合文件系统(Union Filesystem)

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

Linux中文社区

456

相关文章推荐

未登录头像

暂无评论