AUFS是一种Union File System,所谓UnionFS就是把不一样物理位置的目录合并mount到同一个目录中。UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一块儿,而后,你就能够对这个只读的CD/DVD上的文件进行修改(固然,修改的文件存于硬盘上的目录里)。html
AUFS又叫Another UnionFS,后来叫Alternative UnionFS,后来可能以为不够霸气,叫成Advance UnionFS。是个叫Junjiro Okajima(岡島順治郎)在2006年开发的,AUFS彻底重写了早期的UnionFS 1.x,其主要目的是为了可靠性和性能,而且引入了一些新的功能,好比可写分支的负载均衡。AUFS在使用上全兼容UnionFS,并且比以前的UnionFS在稳定性和性能上都要好不少,后来的UnionFS 2.x开始抄AUFS中的功能。可是他竟然没有进到Linux主干里,就是由于Linus不让,基本上是由于代码量比较多,并且写得烂(相对于只有3000行的union mount和10000行的UnionFS,以及其它平均下来只有6000行代码左右的VFS,AUFS竟然有30000行代码),因此,岡島不断地改进代码质量,不断地提交,不断地被Linus拒掉,因此,到今天AUFS都还进不了Linux主干(今天你能够看到AUFS的代码其实还好了,比起OpenSSL好N倍,要么就是Linus对代码的质量要求很是高,要么就是Linus就是不喜欢AUFS)。linux
不过,好在有不少发行版都用了AUFS,好比:Ubuntu 10.04,Debian6.0, Gentoo Live CD支持AUFS,因此,也OK了。docker
好了,扯完这些闲话,咱们仍是看一个示例吧(环境:Ubuntu 14.04)shell
$ tree.ubuntu
├── fruitsbash
│ ├── apple网络
│ └── tomatoapp
└── vegetables负载均衡
├── carrotsoop
└── 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
上面的示例,咱们能够看到,咱们修改了./mnt/carrots的文件内容,./vegetables/carrots并无变化,反而是./fruits/carrots的目录中出现了carrots文件,其内容是咱们在./mnt/carrots里的内容。
也就是说,咱们在mount aufs命令中,咱们没有指它vegetables和fruits的目录权限,默认上来讲,命令行上第一个(最左边)的目录是可读可写的,后面的全都是只读的。(通常来讲,最前面的目录应该是可写的,然后面的都应该是只读的)
因此,若是咱们像下面这样指定权限来mount aufs,你就会发现有不同的效果(记得先把上面./fruits/carrots的文件删除了):
$ sudo mount -t aufs -o dirs=./fruits=rw:./vegetables=rw none ./mnt
$ echo "mnt_carrots" > ./mnt/carrots
$ cat ./vegetables/carrots
mnt_carrots
$ cat ./fruits/carrots
cat: ./fruits/carrots: No such file or directory
如今,在这状况下,若是咱们要修改./mnt/tomato这个文件,那么到底是哪一个文件会被改写?
$ echo "mnt_tomato" > ./mnt/tomato
$ cat ./fruits/tomato
mnt_tomato
$ cat ./vegetables/tomato
I am a vegetable
可见,若是有重复的文件名,在mount命令行上,越往前的就优先级越高。
那么,这种UnionFS有什么用?
历史上,有一个叫Knoppix的Linux发行版,其主要用于Linux演示、光盘教学、系统急救,以及商业产品的演示,不须要硬盘安装,直接把CD/DVD上的image运行在一个可写的存储设备上(好比一个U盘上),其实,也就是把CD/DVD这个文件系统和USB这个可写的系统给联合mount起来,这样你对CD/DVD上的image作的任何改动都会在被应用在U盘上,因而乎,你能够对CD/DVD上的内容进行任意的修改,由于改动都在U盘上,因此你改不坏原来的东西。
咱们能够再发挥一下想像力,你也能够把一个目录,好比你的源代码,做为一个只读的template,和另外一个你的working directory给union在一块儿,而后你就能够作各类修改而不用惧怕会把源代码改坏了。有点像一个ad hoc snapshot。
Docker把UnionFS的想像力发挥到了容器的镜像。你是否还记得我在介绍Linux Namespace上篇中用mount namespace和chroot山寨了一镜像。如今当你看过了这个UnionFS的技术后,你是否是就明白了,你彻底能够用UnionFS这样的技术作出分层的镜像来。
下图来自Docker的官方文档Layer,其很好的展现了Docker用UnionFS搭建的分层镜像。
关于docker的分层镜像,除了aufs,docker还支持btrfs, devicemapper和vfs,你可使用 -s 或 –storage-driver= 选项来指定相关的镜像存储。在Ubuntu 14.04下,docker默认Ubuntu的 aufs(在CentOS7下,用的是devicemapper,关于devicemapper,我会以之后的文章中讲解)你能够在下面的目录中查看相关的每一个层的镜像:
/var/lib/docker/aufs/diff/<id>
在docker执行起来后(好比:docker run -it ubuntu /bin/bash ),你能够从/sys/fs/aufs/si_[id]目录下查看aufs的mount的状况,下面是个示例:
#ls /sys/fs/aufs/si_b71b209f85ff8e75/
br0 br2 br4 br6 brid1 brid3 brid5 xi_path
br1 br3 br5 brid0 brid2 brid4 brid6
# cat /sys/fs/aufs/si_b71b209f85ff8e75/*
/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7=rw
/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7-init=ro+wh
/var/lib/docker/aufs/diff/d0955f21bf24f5bfffd32d2d0bb669d0564701c271bc3dfc64cfc5adfdec2d07=ro+wh
/var/lib/docker/aufs/diff/9fec74352904baf5ab5237caa39a84b0af5c593dc7cc08839e2ba65193024507=ro+wh
/var/lib/docker/aufs/diff/a1a958a248181c9aa6413848cd67646e5afb9797f1a3da5995c7a636f050f537=ro+wh
/var/lib/docker/aufs/diff/f3c84ac3a0533f691c9fea4cc2ceaaf43baec22bf8d6a479e069f6d814be9b86=ro+wh
/var/lib/docker/aufs/diff/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158=ro+wh
/run/shm/aufs.xino
你会看到只有最顶上的层(branch)是rw权限,其它的都是ro+wh权限只读的。
关于docker的aufs的配置,你能够在/var/lib/docker/repositories-aufs这个文件中看到。
AUFS的一些特性
AUFS有全部Union FS的特性,把多个目录,合并成同一个目录,并能够为每一个须要合并的目录指定相应的权限,实时的添加、删除、修改已经被mount好的目录。并且,他还能在多个可写的branch/dir间进行负载均衡。
上面的例子,咱们已经看到AUFS的mount的示例了。下面咱们来看一看被union的目录(分支)的相关权限:
rw表示可写可读read-write。
ro表示read-only,若是你不指权限,那么除了第一个外ro是默认值,对于ro分支,其永远不会收到写操做,也不会收到查找whiteout的操做。
rr表示real-read-only,与read-only不一样的是,rr标记的是天生就是只读的分支,这样,AUFS能够提升性能,好比再也不设置inotify来检查文件变更通知。
权限中,咱们看到了一个术语:whiteout,下面我来解释一下这个术语。
通常来讲ro的分支都会有wh的属性,好比 “[dir]=ro+wh”。所谓whiteout的意思,若是在union中删除的某个文件,其实是位于一个readonly的分支(目录)上,那么,在mount的union这个目录中你将看不到这个文件,可是read-only这个层上咱们没法作任何的修改,因此,咱们就须要对这个readonly目录里的文件做whiteout。AUFS的whiteout的实现是经过在上层的可写的目录下创建对应的whiteout隐藏文件来实现的。
相关术语
Branch – 就是各个要被union起来的目录(就是我在上面使用的dirs的命令行参数)
Branch根据被union的顺序造成一个stack,通常来讲最上面的是可写的,下面的都是只读的。
Branch的stack能够在被mount后进行修改,好比:修改顺序,加入新的branch,或是删除其中的branch,或是直接修改branch的权限
Whiteout 和 Opaque
若是UnionFS中的某个目录被删除了,那么就应该不可见了,就算是在底层的branch中还有这个目录,那也应该不可见了。
Whiteout就是某个上层目录覆盖了下层的相同名字的目录。用于隐藏低层分支的文件,也用于阻止readdir进入低层分支。
Opaque的意思就是不容许任何下层的某个目录显示出来。
在隐藏低层档的状况下,whiteout的名字是'.wh.<filename>’。
在阻止readdir的状况下,名字是’.wh..wh..opq’或者 ’.wh.__dir_opaque’。
来自 <https://coolshell.cn/articles/17061.html>
同一个内核版本的全部Linux系统的bootfs是相同的,而rootfs则是不一样的。在Docker 中,基础镜像中的roofs会一直保持只读模式,Docker会利用union mount来在这个rootfs上增长更多的只读文件系统,最后它们看起来就像一个文件系统即容器的rootfs。
关于 Docker的分层镜像,除了 aufs,docker还支持btrfs, devicemapper和vfs,你可使用 -s 或 –storage-driver= 选项来指定相关的镜像存储。在Ubuntu 14.04下,Docker 默认 Ubuntu的 AUFS。由于 AUFS 尚未进入Linux 内核主干的缘由,RedHat 上使用的是 devicemapper。
镜像(image)是动态的容器的静态表示(specification),包括容器所要运行的应用代码以及运行时的配置。Docker 镜像包括一个或者多个只读层( read-only layers ),所以,镜像一旦被建立就不再能被修改了。
一个运行着的Docker 容器是一个镜像的实例( instantiation )。从同一个镜像中运行的容器包含有相同的应用代码和运行时依赖。可是不像镜像是静态的,每一个运行着的容器都有一个可写层( writable layer ,也成为容器层 container layer),它位于底下的若干只读层之上。运行时的全部变化,包括对数据和文件的写和更新,都会保存在这个层中。所以,从同一个镜像运行的多个容器包含了不一样的容器层。
四种单节点网络模式
bridge 模式
Docker 容器默认使用 bridge 模式的网络。其特色以下:
iptables 的 SNTA 规则,使得从容器离开去外界的网络包的源 IP 地址被转换为 Docker 主机的IP地址:
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
MASQUERADE all -- 172.18.0.0/16 0.0.0.0/0
Host 模式
Host 模式并无为容器建立一个隔离的网络环境。而之因此称之为host模式,是由于该模式下的 Docker 容器会和 host 宿主机共享同一个网络 namespace,故 Docker Container能够和宿主机同样,使用宿主机的eth0,实现和外界的通讯。换言之,Docker Container的 IP 地址即为宿主机 eth0 的 IP 地址。其特色包括:
container 模式
Container 网络模式是 Docker 中一种较为特别的网络的模式。处于这个模式下的 Docker 容器会共享其余容器的网络环境,所以,至少这两个容器之间不存在网络隔离,而这两个容器又与宿主机以及除此以外其余的容器存在网络隔离。
none 模式
网络模式为 none,即不为 Docker 容器构造任何网络环境。一旦Docker 容器采用了none 网络模式,那么容器内部就只能使用loopback网络设备,不会再有其余的网络资源。Docker Container的none网络模式意味着不给该容器建立任何网络环境,容器只能使用127.0.0.1的本机网络。