Docker 存储可以分为分层文件系统和卷,本文将介绍 AUFS 分层文件系统。 1. 基础知识1.1 Linux 的 rootfs 和 bootfs一个典型的 Linux 系统要能运行的话,它至少需要两个文件系统:
Linux 系统在启动时,roofs 首先会被挂载为只读模式,然后在启动完成后被修改为读写模式,随后它们就可以被修改了。 1.2 AUFSAUFS 是一种 Union File System(联合文件系统),又叫 Another UnionFS,后来叫Alternative UnionFS,再后来叫成高大上的 Advance UnionFS。所谓 UnionFS,就是把不同物理位置的目录合并mount到同一个目录中。UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。 举个例子,在 Ubuntu 14.04 系统上现有如下目录结构:
$ tree
.
├── fruits
│ ├── apple
│ └── tomato
└── vegetables
├── carrots
└── tomato
输入以下几个命令: # 创建一个mount目录 $ mkdir mnt # 把水果目录和蔬菜目录union mount到 ./mnt目录中 $ sudo mount -t aufs -o dirs=./fruits:./vegetables none ./mnt # 查看./mnt目录 $ tree ./mnt ./mnt ├── apple ├── carrots └── tomato 我们可以看到在./mnt目录下有三个文件,苹果apple、胡萝卜carrots和蕃茄tomato。水果和蔬菜的目录被union到了./mnt目录下了。 我们来修改一下其中的文件内容: $ echo mnt > ./mnt/apple $ cat ./mnt/apple mnt $ cat ./fruits/apple mnt 上面的示例,我们可以看到./mnt/apple的内容改了,./fruits/apple的内容也改了。 $ echo mnt_carrots > ./mnt/carrots $ cat ./vegetables/carrots $ cat ./fruits/carrots mnt_carrots 关于 AUFS 的几个特点:
本部分内容主要应用自 Docker基础技术:AUFS。 2. Docker 文件系统2.1 Docker 镜像的 rootfs前面基础知识部分谈到过,同一个内核版本的所有 Linux 系统的 bootfs 是相同的,而 rootfs 则是不同的。在 Docker 中,基础镜像中的 roofs 会一直保持只读模式,Docker 会利用 union mount 来在这个 rootfs 上增加更多的只读文件系统,最后它们看起来就像一个文件系统即容器的 rootfs。 (图片来源) 可见在一个Linux 系统之中,
以 training/webapp 镜像为例, root@docker1:/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa# docker history training/webapp IMAGE CREATED CREATED BY SIZE COMMENT 6fae60ef3446 16 months ago /bin/sh -c #(nop) CMD ["python" "app.py"] 0 B <missing> 16 months ago /bin/sh -c #(nop) EXPOSE 5000/tcp 0 B <missing> 16 months ago /bin/sh -c #(nop) WORKDIR /opt/webapp 0 B <missing> 16 months ago /bin/sh -c #(nop) ADD dir:9b2a69f6f30d18b02b5 703 B <missing> 16 months ago /bin/sh -c pip install -qr /tmp/requirements. 4.363 MB <missing> 16 months ago /bin/sh -c #(nop) ADD file:c59059439864153904 41 B <missing> 16 months ago /bin/sh -c DEBIAN_FRONTEND=noninteractive apt 135.3 MB <missing> 16 months ago /bin/sh -c apt-get update 20.8 MB <missing> 16 months ago /bin/sh -c #(nop) MAINTAINER Docker Education 0 B <missing> 17 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B <missing> 17 months ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/ 1.895 kB <missing> 17 months ago /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic 194.5 kB <missing> 17 months ago /bin/sh -c #(nop) ADD file:f4d7b4b3402b5c53f2 188.1 MB 它是基于 Ubuntu Docker 基础镜像。在基础镜像层中,我们能看到完整的 Ubuntu rootfs: root@docker1:/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa# ls -l total 76 drwxr-xr-x 2 root root 4096 Apr 27 2015 bin drwxr-xr-x 2 root root 4096 Apr 11 2014 boot drwxr-xr-x 3 root root 4096 Apr 27 2015 dev drwxr-xr-x 61 root root 4096 Apr 27 2015 etc drwxr-xr-x 2 root root 4096 Apr 11 2014 home drwxr-xr-x 12 root root 4096 Apr 27 2015 lib drwxr-xr-x 2 root root 4096 Apr 27 2015 lib64 drwxr-xr-x 2 root root 4096 Apr 27 2015 media drwxr-xr-x 2 root root 4096 Apr 11 2014 mnt drwxr-xr-x 2 root root 4096 Apr 27 2015 opt drwxr-xr-x 2 root root 4096 Apr 11 2014 proc drwx------ 2 root root 4096 Apr 27 2015 root drwxr-xr-x 7 root root 4096 Apr 27 2015 run drwxr-xr-x 2 root root 4096 Apr 27 2015 sbin drwxr-xr-x 2 root root 4096 Apr 27 2015 srv drwxr-xr-x 2 root root 4096 Mar 13 2014 sys drwxrwxrwt 2 root root 4096 Apr 27 2015 tmp drwxr-xr-x 10 root root 4096 Apr 27 2015 usr drwxr-xr-x 11 root root 4096 Apr 27 2015 var 我们来看两种典型的文件: (1)bin 目录中的文件会被直接使用 root@docker1:/var/lib/docker/aufs/diff# find -iname mountpoint ./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/bin/mountpoint (2)在基础镜像层中 proc 目录为空,也就是说容器中看到的 proc 目录中的文件是后来生成的。 2.2 Docker 使用的 AUFS 文件系统关于 Docker的分层镜像,除了 aufs,docker还支持btrfs, devicemapper和vfs,你可以使用 -s 或 –storage-driver= 选项来指定相关的镜像存储。在Ubuntu 14.04下,Docker 默认 Ubuntu的 AUFS。因为 AUFS 还没有进入Linux 内核主干的原因,RedHat 上使用的是 devicemapper。 我们可以在 docker info 命令的输出中查看所使用的存储驱动: Storage Driver: aufs Root Dir: /var/lib/docker/aufs Backing Filesystem: extfs Dirs: 19 Dirperm1 Supported: false 以一个正在运行着的 Docker 容器为例,其镜像有13层: "RootFS": { "Type": "layers", "Layers": [ "sha256:1154ba695078d29ea6c4e1adb55c463959cd77509adf09710e2315827d66271a", "sha256:528c8710fd95f61d40b8bb8a549fa8dfa737d9b9c7c7b2ae55f745c972dddacd", "sha256:37ee47034d9b78f10f0c5ce3a25e6b6e58997fcadaf5f896c603a10c5f35fb31", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:b75c0703b86b8ccbdc1f1b28b4982774768861ac250f83bdb940b1e90291f302", "sha256:5c121779bb29172c628a21087ea8ced766959da2f223c8b6bd4ffe943ace43d8", "sha256:3ee91c5cb95b01496b4afdc721ba7fd3c22e0e5e2f3e9e70d3f8579b5082d4f3", "sha256:6bbb1d0f845289217e20b66697fa7d651394d89983b0f5a89b88f037194476fe", "sha256:b44b0832d4c6bf33122ce3aa896b133df88275e6d20663a9bf2d941f764ac1fd", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" ] } 从 AUFS 的角度,可以看到有一个可写的容器层和14个只读的镜像层: root@docker1:/sys/fs/aufs/si_ab487e40195df24f# cat * /var/lib/docker/aufs/diff/2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab=rw #可写的容器层 /var/lib/docker/aufs/diff/2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab-init=ro+wh #本层及以下是只读的镜像层 /var/lib/docker/aufs/diff/5472f8388f9a61f6bd84498201a5ad71a2ec88cda16c42a3a1da7c30da45f102=ro+wh /var/lib/docker/aufs/diff/61dcf0881e790bf52ec555727b58641791adeefadcc7abc2a77fd228bde1371a=ro+wh /var/lib/docker/aufs/diff/f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e=ro+wh /var/lib/docker/aufs/diff/45818d286499870412357d66eb6af951699f89db785c7c6a242d2e1ac99734f9=ro+wh /var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa=ro+wh /var/lib/docker/aufs/diff/85cb840562788e1b458e68265e62fd2da9d0d7e737256500e8a276bcb237183c=ro+wh /var/lib/docker/aufs/diff/c18ba8efcb455e97f6aabe3985b147f6a37b8f5ad090373e88ddd326b4f90896=ro+wh /var/lib/docker/aufs/diff/25de7dcc3a06f0caa3c701d4ed6c62f03e0757f6d477cc822db6e884bb366441=ro+wh /var/lib/docker/aufs/diff/ad9e831217594cdfecd5e824690b0e52f2e16d6e2bb39b7143e66d467150cfe8=ro+wh /var/lib/docker/aufs/diff/56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0=ro+wh /var/lib/docker/aufs/diff/31bc6290457af4e560a3103020c85fbb5dfcfb201b0662a33165260529f87c07=ro+wh /var/lib/docker/aufs/diff/e104672666119006648d0b82988c49527e52c64629750c5c9adde88acc790682=ro+wh /var/lib/docker/aufs/diff/7a085e415855435121fb7837c26a5e951f622bc69364d9228d409a4929b627e1=ro+wh 根据上面 AUFS 的定义,容器的文件系统是从 14 个只读镜像层和1个可写容器层通过 AUFS mount 出来的。示意图如下: (图片来源) 这种分层文件系统可以通过官网的图来清晰的展示出来:
做一些实验: (1)在容器中创建一个文件,该文件会被创建在可写的容器层中 root@docker1:/var/lib/docker/aufs/diff# find -iname createdbysammy ./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/opt/webapp/createdbysammy root@docker1:/var/lib/docker/aufs/diff# ls -lt total 60 drwxr-xr-x 9 root root 4096 Oct 4 22:37 2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab drwxr-xr-x 6 root root 4096 Oct 1 11:56 2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab-init (2)修改一个镜像层中的文件 修改前,文件 /etc/apt/sources.list 出现在两个层中: root@docker1:/var/lib/docker/aufs/diff# find -iname sources.list ./f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e/etc/apt/sources.list ./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/etc/apt/sources.list 在容器中对它进行修改后,它被拷贝到了容器层然后被修改了: root@docker1:/var/lib/docker/aufs/diff# find -iname sources.list ./f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e/etc/apt/sources.list ./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/etc/apt/sources.list ./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/etc/apt/sources.list 而另外两个层中的文件保持了不变。这说明了 AUFS 的 CoW 特性。 (3)删除容器层中的文件 容器中的文件 ./usr/local/lib/python2.7/dist-packages/itsdangerous.py 位于 56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0 层中,这是一个只读层。 在容器内删除它: root@fa385836d5b9:/# find -iname itsdangerous.py ./usr/local/lib/python2.7/dist-packages/itsdangerous.py root@fa385836d5b9:/# rm ./usr/local/lib/python2.7/dist-packages/itsdangerous.py root@fa385836d5b9:/# find -iname itsdangerous.py 然后,容器层中出现了一个 .wh 文件,而镜像层中的文件保持不变: root@docker1:/var/lib/docker/aufs/diff# find -iname *itsdangerous.py ./56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0/usr/local/lib/python2.7/dist-packages/itsdangerous.py ./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/usr/local/lib/python2.7/dist-packages/.wh.itsdangerous.py 在手工将 .wh 文件删除后,文件就会再次回到容器中。
rm ./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/usr/local/lib/python2.7/dist-packages/.wh.itsdangerous.py
root@fa385836d5b9:/# find -iname itsdangerous.py ./usr/local/lib/python2.7/dist-packages/itsdangerous.py 参考链接:
(责任编辑:IT) |