有了image以后,就能够开始建立并启动容器了,平时咱们都是用docker run
命令直接建立并运行一个容器,它的背后其实包含独立的两步,一步是docker create
建立容器,另外一步是docker start
启动容器,本篇将先介绍在docker create
这一步中,docker作了哪些事情。node
简单点来讲,dockerd在收到客户端的建立容器请求后,作了两件事情,一是准备容器须要的layer,二是检查客户端传过来的参数,并和image配置文件中的参数进行合并,而后存储成容器的配置文件。docker
建立一个容器用于示例json
#建立一个容器,并取名为docker_test, #-i是为了让容器能接受用户的输入,-t是指定docker为容器建立一个tty, #由于ubuntu这个镜像默认启动的进程是bash,而bash须要tty,不然会异常退出 dev@dev:~$ docker create -it --name docker_test ubuntu 967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368 dev@dev:~$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 967438113fba ubuntu "/bin/bash" 6 seconds ago Created docker_test
建立容器时,docker会为每一个容器建立两个新的layer,一个是只读的init layer,里面包含docker为容器准备的一些文件,另外一个是容器的可写mount layer,之后在容器里面对rootfs的全部增删改操做的结果都会存在这个layer中。ubuntu
# layer的元数据存储在layerdb/mounts/目录下,目录名称就是容器的ID # 里面包含了三个文件 root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# ls init-id mount-id parent # mount-id文件包含了mount layer的cacheid root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# cat mount-id 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281 # init-id文件包含了init layer的cacheid # init layer的cacheid就是在mount layer的cacheid后面加上了一个“-init” root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# cat init-id 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init # parent里面包含的是image的最上一层layer的chainid # 表示这个容器的init layer的父layer是image的最顶层layer root@dev:/var/lib/docker/image/aufs/layerdb/mounts/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# cat parent sha256:9840d207a275f956f3e634148044e63dc78df511fd72e22d8cb3dad57dc49bf6 # 能够根据parent的chainid获得它的diffid, # 这个diffid对应的确实是ubuntu:latest的最顶层layer # 如何获得image的layer信息请参考上一篇文章: # 走进docker(05):docker在本地如何管理image(镜像)? root@dev:/var/lib/docker/image# cat ./aufs/layerdb/sha256/9840d207a275f956f3e634148044e63dc78df511fd72e22d8cb3dad57dc49bf6/diff sha256:d8b353eb3025c49e029567b2a01e517f7f7d32537ee47e64a7eac19fa68a33f3
新加的这两层layer比较特殊,只保存在layerdb/mounts下面,在layerdb/sha256目录下没有相关信息,说明docker将container的layer和image的layer的元数据放在了不一样的两个目录中bash
container layer的数据和image layer的数据的管理方式是同样的,都存在/var/lib/docker/<storage-driver>
目录下面。spa
该目录下包含了每一个layer的祖先layer的cacheid操作系统
root@dev:/var/lib/docker/aufs# cat ./layers/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init 7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e 4c10796e21c796a6f3d83eeb3613c566ca9e0fd0a596f4eddf5234b87955b3c8 fd0ba28a44491fd7559c7ffe0597fb1f95b63207a38a3e2680231fb2f6fe92bd b656bf5f0688069cd90ab230c029fdfeb852afcfd0d1733d087474c86a117da3 1e83d2ea184e08eed978127311cc96498e319426abe2fb5004d4b1454598bd76 #从这里能够看出mount layer在init layer的上面 root@dev:/var/lib/docker/aufs# cat ./layers/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init 7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e 4c10796e21c796a6f3d83eeb3613c566ca9e0fd0a596f4eddf5234b87955b3c8 fd0ba28a44491fd7559c7ffe0597fb1f95b63207a38a3e2680231fb2f6fe92bd b656bf5f0688069cd90ab230c029fdfeb852afcfd0d1733d087474c86a117da3 1e83d2ea184e08eed978127311cc96498e319426abe2fb5004d4b1454598bd76 #上面的7938f2...就是ubuntu:latest最上一层layer的cacheid root@dev:~# find /var/lib/docker/image/ -name cache-id|xargs grep 7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e /var/lib/docker/image/aufs/layerdb/sha256/9840d207a275f956f3e634148044e63dc78df511fd72e22d8cb3dad57dc49bf6/cache-id:7938f2b32c53a9e0d3974f9579dd9dbb450202e1e11fe514e31556d4ea808c4e #9840d2...是ubuntu:latest最上一层layer的chainid
该目录下存放着每一个layer所包含的数据3d
#mount layer是新建的供容器写数据layer, #因为容器尚未运行,因此这里没有任何数据 root@dev:/var/lib/docker/aufs/diff# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281 0 directories, 0 files #init layer包含了docker为每一个容器所预先准备的文件 root@dev:/var/lib/docker/aufs/diff# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/ 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/ ├── dev │ └── console └── etc ├── hostname ├── hosts ├── mtab -> /proc/mounts └── resolv.conf 2 directories, 5 files
init layer里面的文件有什么做用呢?从下面的结果能够看出,除了mtab文件是指向/proc/mounts的软链接以外,其余的都是空的普通文件。code
root@dev:/var/lib/docker/aufs/diff/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init# ls -l dev total 0 -rwxr-xr-x 1 root root 0 Jun 25 11:25 console root@dev:/var/lib/docker/aufs/diff/305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init# ls -l etc total 0 -rwxr-xr-x 1 root root 0 Jun 25 11:25 hostname -rwxr-xr-x 1 root root 0 Jun 25 11:25 hosts lrwxrwxrwx 1 root root 12 Jun 25 11:25 mtab -> /proc/mounts -rwxr-xr-x 1 root root 0 Jun 25 11:25 resolv.conf
这几个文件都是Linux运行时必须的文件,若是缺乏的话会致使某些程序或者库出现异常,因此docker须要为容器准备好这些文件:进程
/dev/console: 在Linux主机上,该文件通常指向主机的当前控制台,有些程序会依赖该文件。在容器启动的时候,docker会为容器建立一个pts,而后经过bind mount的方式将pts绑定到容器里面的/dev/console上,这样在容器里面往这个文件里面写东西就至关于往容器的控制台上打印数据。这里建立一个空文件至关于占个坑,做为后续bind mount的目的路径。
hostname,hosts,resolv.conf:对于每一个容器来讲,容器内的这几个文件内容都有可能不同,这里也只是占个坑,等着docker在外面生成这几个文件,而后经过bind mount的方式将这些文件绑定到容器中的这些位置,即这些文件都会被宿主机中的文件覆盖掉。
/etc/mtab:这个文件在新的Linux发行版中都指向/proc/mounts,里面包含了当前mount namespace中的全部挂载信息,不少程序和库会依赖这个文件。
注意: 这里mtab指向的路径是固定的,但内容是变化的,取决于你从哪里打开这个文件,当在宿主机上打开时,是宿主机上/proc/mounts的内容,当启动并进入容器后,在容器中打开看到的就是容器中/proc/mounts的内容。
里面存放的是通过aufs文件系统mount以后的layer数据,即当前layer和全部的下层layer合并以后的数据,对于aufs文件系统来讲,只有在运行容器的时候才会被docker所mount,因此容器没启动的时候,这里看不到任何文件。
root@dev:/var/lib/docker/aufs/mnt# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281 0 directories, 0 files root@dev:/var/lib/docker/aufs/mnt# tree 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/ 305226f2e0755956ada28b3baf39b18fa328f1a59fd90e0b759a239773db2281-init/ 0 directories, 0 files
docker将用户指定的参数和image配置文件中的部分参数进行合并,而后将合并后生成的容器的配置文件放在/var/lib/docker/containers/下面,目录名称就是容器的ID
root@dev:/var/lib/docker/containers/967438113fba0b7a3005bcb6efae6a77055d6be53945f30389888802ea8b0368# tree . ├── checkpoints ├── config.v2.json └── hostconfig.json 1 directory, 2 files
config.v2.json: 通用的配置,如容器名称,要执行的命令等
hostconfig.json: 主机相关的配置,跟操做系统平台有关,如cgroup的配置
checkpoints: 容器的checkpoint这个功能在当前版本仍是experimental状态。
这里不详细介绍配置项的内容,后续介绍某些具体配置项的时候再来看这些文件。
checkpoints这个功能很强大,能够在当前node作一个checkpoint,而后再到另外一个node上继续运行,至关于无缝的将一个正在运行的进程先暂停,而后迁移到另外一个node上并继续运行。
docker create命令干的活比较少,主要是准备container的layer和配置文件,配置文件中的项比较多,后续会挑一些经常使用的项进行专门介绍。