Container本来也不是什么新技术,为什么Docker就火了,而前辈们如lxc、OpenVZ等没这么火。其实一部分原因得益于Docker的Image管理。Docker借鉴了vm的方式,让用户像管理vm一样的管理他们的container镜像,并且也同样叫做Image。在实现上,Docker利用container的Rootfs是从host上挂载的、并且能挂载多个目录这个特点,将Docker Image分成多个小块(这是按照vm Image的思维来说的,实际上这多个小块,每个都是一个Image,最终使用的是一个Image组合),方便管理与共享。

我们已经了解了Container是什么,那么Image是怎么转换为Container的Rootfs的?Image本身是怎么在磁盘上存储的?带着这些疑问,我们一起来看看Docker的实现。

磁盘上的image

先来看看磁盘中存储的image是什么样子的,这里以aufs为例,devicemapper的存储形式和aufs还不太一样,后续有空再来分析。

现在我们有一个image:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo docker images
  2. [sudo] password for ubuntu:
  3. REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  4. ubuntu-12.04        latest              212e4aaf49e7        25 minutes ago      172.7 MB

对应的/var/lib/docker目录下就有这些东西:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo ls -lh /var/lib/docker
  2. total 48K
  3. drwxr-xr-x 2 root root 4.0K Apr 16 22:26 apparmor
  4. drwxr-xr-x 5 root root 4.0K Jun 21 16:14 aufs
  5. drwx------ 3 root root 4.0K Jun 22 13:01 containers
  6. drwx------ 5 root root 4.0K Jun 22 12:59 devicemapper
  7. drwx------ 3 root root 4.0K Apr 16 22:16 execdriver
  8. drwx------ 6 root root 4.0K Jul 13 11:32 graph
  9. drwx------ 2 root root 4.0K Jul 13 11:40 init
  10. -rw-r--r-- 1 root root 5.0K Jun 22 13:01 linkgraph.db
  11. -rw------- 1 root root  111 Jul 13 11:32 repositories-aufs
  12. -rw------- 1 root root  180 Apr 16 22:56 repositories-devicemapper
  13. drwx------ 2 root root 4.0K Apr 16 22:16 volumes<span style="letter-spacing: 0px; color: rgb(68, 68, 68); font-family: Baskerville;"> </span>

抛开其他的不管,现在只关心里面的aufs, graph目录和repositories-aufs文件(如果是devicemapper,则是devicemapper目录和repositories-devicemapper文件,graph为共用的目录)。

aufs目录的结构如下:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo tree /var/lib/docker/aufs -L 3
  2. /var/lib/docker/aufs
  3. |-- diff
  4. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  5. |       |-- bin
  6. |       |-- boot
  7. |       |-- dev
  8. |       |-- etc
  9. |       |-- home
  10. |       |-- lib
  11. |       |-- lib64
  12. |       |-- media
  13. |       |-- mnt
  14. |       |-- opt
  15. |       |-- proc
  16. |       |-- root
  17. |       |-- run
  18. |       |-- sbin
  19. |       |-- selinux
  20. |       |-- srv
  21. |       |-- sys
  22. |       |-- tmp
  23. |       |-- usr
  24. |       `-- var
  25. |-- layers
  26. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  27. `-- mnt
  28. `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d

layers目录和mnt目录里面目前还只有一个空目录,后面再来看。这里主要是diff目录下对应image的目录,image内部的所有文件都在这。

而graph目录的结构如下:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo tree /var/lib/docker/graph -L 3
  2. /var/lib/docker/graph
  3. |-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  4. |   |-- json
  5. |   `-- layersize
  6. |-- 317c1f4475ad860bdcf0e529fd03f181b2c6b64e5b78358051efc94c8f728cd7
  7. |   |-- json
  8. |   `-- layersize
  9. |-- bcd86fdd0ba0b84f10f4539f99e8730958fc1028d35495f8dd11ae1913370e42
  10. |   |-- json
  11. |   `-- layersize
  12. `-- _tmp

这里只看212e这个image,另外两个image其实是devicemapper下的image,所有image的描述都放在graph目录下。json文件为image的描述文件,主要是创建这个image的container配置信息,layersize文件内为该image的大小。

最后看看repositories-aufs文件:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo cat /var/lib/docker/repositories-aufs |python -m json.tool
  2. {
  3. "Repositories": {
  4. "ubuntu-12.04": {
  5. "latest": "212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d"
  6. }
  7. }
  8. }

其实就是描述在aufs模式下有哪些image可用。

了解了image包括哪些东西,接下来再看看这些东西是怎么用的。

从Image到Container

当我们通过命令行docker run创建一个container并运行时,其中就经历了从image到container rootfs的转化,蓝图如下(省略了其他操作):

上图横轴为执行流程,纵轴是对每个过程的解释。

因为docker run命令实际的执行主要分两步:create和start。在create过程中,主要是将image挂载到/var/lib/docker/aufs/mnt/:id-init目录 (:id为container id),并且取消掉对某些文件/文件夹的挂载,重新创建一份新的。这里的文件/文件夹主要为:

[plain] view plaincopy
  1. "/dev/pts":         "dir",
  2. "/dev/shm":         "dir",
  3. "/proc":            "dir",
  4. "/sys":             "dir",
  5. "/.dockerinit":     "file",
  6. "/.dockerenv":      "file",
  7. "/etc/resolv.conf": "file",
  8. "/etc/hosts":       "file",
  9. "/etc/hostname":    "file",
  10. "/dev/console":     "file",
  11. "/etc/mtab":        "/proc/mounts",

然后在start流程中,主要是生成container真正的rootfs目录/var/lib/docker/aufs/mnt/:id, 然后又将几个/host上的目录挂载到rootfs,主要是 /etc/hosts, /etc/hostname, /etc/resolv.conf等。

(其实这里没看明白为啥这几个文件要这样处理,也没看明白为什么要用:id-init目录隔一层。主要是对aufs不熟悉,后面再学习一下。)

现在来看看,当我们创建了一个container后,aufs目录有什么变化:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo tree -L 3 /var/lib/docker/aufs
  2. [sudo] password for ubuntu:
  3. /var/lib/docker/aufs
  4. |-- diff
  5. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167
  6. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167-init
  7. |   |   |-- dev
  8. |   |   `-- etc
  9. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  10. |       |-- bin
  11. |       |-- boot
  12. |       |-- dev
  13. |       |-- etc
  14. |       |-- home
  15. |       |-- lib
  16. |       |-- lib64
  17. |       |-- media
  18. |       |-- mnt
  19. |       |-- opt
  20. |       |-- proc
  21. |       |-- root
  22. |       |-- run
  23. |       |-- sbin
  24. |       |-- selinux
  25. |       |-- srv
  26. |       |-- sys
  27. |       |-- tmp
  28. |       |-- usr
  29. |       `-- var
  30. |-- layers
  31. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167
  32. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167-init
  33. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  34. `-- mnt
  35. |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167
  36. |   |-- bin
  37. |   |-- boot
  38. |   |-- dev
  39. |   |-- etc
  40. |   |-- home
  41. |   |-- lib
  42. |   |-- lib64
  43. |   |-- media
  44. |   |-- mnt
  45. |   |-- opt
  46. |   |-- proc
  47. |   |-- root
  48. |   |-- run
  49. |   |-- sbin
  50. |   |-- selinux
  51. |   |-- srv
  52. |   |-- sys
  53. |   |-- tmp
  54. |   |-- usr
  55. |   `-- var
  56. |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167-init
  57. `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d

这里创建了一个id为09b1的container,其中/aufs/mnt/09b1xxx 为rootfs, /aufs/layers目录下的文件,主要存储image的parents image id。

小结

Docker的image管理涉及到不少linux文件系统使用的细节,对linux文件系统掌握得不深的话,这部分就只能看个大概的流程。而且这只是其中的aufs部分,其他的devicemapper、btrfs、vfs部分的都不太一样。下来先补习一下linux文件系统知识,再回过头来看看docker的image管理,可能会稍微轻松些。

Container本来也不是什么新技术,为什么Docker就火了,而前辈们如lxc、OpenVZ等没这么火。其实一部分原因得益于Docker的Image管理。Docker借鉴了vm的方式,让用户像管理vm一样的管理他们的container镜像,并且也同样叫做Image。在实现上,Docker利用container的Rootfs是从host上挂载的、并且能挂载多个目录这个特点,将Docker Image分成多个小块(这是按照vm Image的思维来说的,实际上这多个小块,每个都是一个Image,最终使用的是一个Image组合),方便管理与共享。

我们已经了解了Container是什么,那么Image是怎么转换为Container的Rootfs的?Image本身是怎么在磁盘上存储的?带着这些疑问,我们一起来看看Docker的实现。

磁盘上的image

先来看看磁盘中存储的image是什么样子的,这里以aufs为例,devicemapper的存储形式和aufs还不太一样,后续有空再来分析。

现在我们有一个image:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo docker images
  2. [sudo] password for ubuntu:
  3. REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
  4. ubuntu-12.04        latest              212e4aaf49e7        25 minutes ago      172.7 MB

对应的/var/lib/docker目录下就有这些东西:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo ls -lh /var/lib/docker
  2. total 48K
  3. drwxr-xr-x 2 root root 4.0K Apr 16 22:26 apparmor
  4. drwxr-xr-x 5 root root 4.0K Jun 21 16:14 aufs
  5. drwx------ 3 root root 4.0K Jun 22 13:01 containers
  6. drwx------ 5 root root 4.0K Jun 22 12:59 devicemapper
  7. drwx------ 3 root root 4.0K Apr 16 22:16 execdriver
  8. drwx------ 6 root root 4.0K Jul 13 11:32 graph
  9. drwx------ 2 root root 4.0K Jul 13 11:40 init
  10. -rw-r--r-- 1 root root 5.0K Jun 22 13:01 linkgraph.db
  11. -rw------- 1 root root  111 Jul 13 11:32 repositories-aufs
  12. -rw------- 1 root root  180 Apr 16 22:56 repositories-devicemapper
  13. drwx------ 2 root root 4.0K Apr 16 22:16 volumes<span style="letter-spacing: 0px; color: rgb(68, 68, 68); font-family: Baskerville;"> </span>

抛开其他的不管,现在只关心里面的aufs, graph目录和repositories-aufs文件(如果是devicemapper,则是devicemapper目录和repositories-devicemapper文件,graph为共用的目录)。

aufs目录的结构如下:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo tree /var/lib/docker/aufs -L 3
  2. /var/lib/docker/aufs
  3. |-- diff
  4. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  5. |       |-- bin
  6. |       |-- boot
  7. |       |-- dev
  8. |       |-- etc
  9. |       |-- home
  10. |       |-- lib
  11. |       |-- lib64
  12. |       |-- media
  13. |       |-- mnt
  14. |       |-- opt
  15. |       |-- proc
  16. |       |-- root
  17. |       |-- run
  18. |       |-- sbin
  19. |       |-- selinux
  20. |       |-- srv
  21. |       |-- sys
  22. |       |-- tmp
  23. |       |-- usr
  24. |       `-- var
  25. |-- layers
  26. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  27. `-- mnt
  28. `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d

layers目录和mnt目录里面目前还只有一个空目录,后面再来看。这里主要是diff目录下对应image的目录,image内部的所有文件都在这。

而graph目录的结构如下:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo tree /var/lib/docker/graph -L 3
  2. /var/lib/docker/graph
  3. |-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  4. |   |-- json
  5. |   `-- layersize
  6. |-- 317c1f4475ad860bdcf0e529fd03f181b2c6b64e5b78358051efc94c8f728cd7
  7. |   |-- json
  8. |   `-- layersize
  9. |-- bcd86fdd0ba0b84f10f4539f99e8730958fc1028d35495f8dd11ae1913370e42
  10. |   |-- json
  11. |   `-- layersize
  12. `-- _tmp

这里只看212e这个image,另外两个image其实是devicemapper下的image,所有image的描述都放在graph目录下。json文件为image的描述文件,主要是创建这个image的container配置信息,layersize文件内为该image的大小。

最后看看repositories-aufs文件:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo cat /var/lib/docker/repositories-aufs |python -m json.tool
  2. {
  3. "Repositories": {
  4. "ubuntu-12.04": {
  5. "latest": "212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d"
  6. }
  7. }
  8. }

其实就是描述在aufs模式下有哪些image可用。

了解了image包括哪些东西,接下来再看看这些东西是怎么用的。

从Image到Container

当我们通过命令行docker run创建一个container并运行时,其中就经历了从image到container rootfs的转化,蓝图如下(省略了其他操作):

上图横轴为执行流程,纵轴是对每个过程的解释。

因为docker run命令实际的执行主要分两步:create和start。在create过程中,主要是将image挂载到/var/lib/docker/aufs/mnt/:id-init目录 (:id为container id),并且取消掉对某些文件/文件夹的挂载,重新创建一份新的。这里的文件/文件夹主要为:

[plain] view plaincopy
  1. "/dev/pts":         "dir",
  2. "/dev/shm":         "dir",
  3. "/proc":            "dir",
  4. "/sys":             "dir",
  5. "/.dockerinit":     "file",
  6. "/.dockerenv":      "file",
  7. "/etc/resolv.conf": "file",
  8. "/etc/hosts":       "file",
  9. "/etc/hostname":    "file",
  10. "/dev/console":     "file",
  11. "/etc/mtab":        "/proc/mounts",

然后在start流程中,主要是生成container真正的rootfs目录/var/lib/docker/aufs/mnt/:id, 然后又将几个/host上的目录挂载到rootfs,主要是 /etc/hosts, /etc/hostname, /etc/resolv.conf等。

(其实这里没看明白为啥这几个文件要这样处理,也没看明白为什么要用:id-init目录隔一层。主要是对aufs不熟悉,后面再学习一下。)

现在来看看,当我们创建了一个container后,aufs目录有什么变化:

[plain] view plaincopy
  1. ubuntu@ubuntu:~$ sudo tree -L 3 /var/lib/docker/aufs
  2. [sudo] password for ubuntu:
  3. /var/lib/docker/aufs
  4. |-- diff
  5. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167
  6. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167-init
  7. |   |   |-- dev
  8. |   |   `-- etc
  9. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  10. |       |-- bin
  11. |       |-- boot
  12. |       |-- dev
  13. |       |-- etc
  14. |       |-- home
  15. |       |-- lib
  16. |       |-- lib64
  17. |       |-- media
  18. |       |-- mnt
  19. |       |-- opt
  20. |       |-- proc
  21. |       |-- root
  22. |       |-- run
  23. |       |-- sbin
  24. |       |-- selinux
  25. |       |-- srv
  26. |       |-- sys
  27. |       |-- tmp
  28. |       |-- usr
  29. |       `-- var
  30. |-- layers
  31. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167
  32. |   |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167-init
  33. |   `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d
  34. `-- mnt
  35. |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167
  36. |   |-- bin
  37. |   |-- boot
  38. |   |-- dev
  39. |   |-- etc
  40. |   |-- home
  41. |   |-- lib
  42. |   |-- lib64
  43. |   |-- media
  44. |   |-- mnt
  45. |   |-- opt
  46. |   |-- proc
  47. |   |-- root
  48. |   |-- run
  49. |   |-- sbin
  50. |   |-- selinux
  51. |   |-- srv
  52. |   |-- sys
  53. |   |-- tmp
  54. |   |-- usr
  55. |   `-- var
  56. |-- 09b1be94a4444076375b7cb386609990622a1746802858ea85f1de607c1e5167-init
  57. `-- 212e4aaf49e7cde3c280d05f1a6bd74ecf66ad83917fa757137deb0dae82806d

这里创建了一个id为09b1的container,其中/aufs/mnt/09b1xxx 为rootfs, /aufs/layers目录下的文件,主要存储image的parents image id。

小结

Docker的image管理涉及到不少linux文件系统使用的细节,对linux文件系统掌握得不深的话,这部分就只能看个大概的流程。而且这只是其中的aufs部分,其他的devicemapper、btrfs、vfs部分的都不太一样。下来先补习一下linux文件系统知识,再回过头来看看docker的image管理,可能会稍微轻松些。

Docker Image执行流程相关推荐

  1. 追源索骥:透过源码看懂Flink核心框架的执行流程

    https://www.cnblogs.com/bethunebtj/p/9168274.html 追源索骥:透过源码看懂Flink核心框架的执行流程 前言 1.从 Hello,World WordC ...

  2. 步步深入MySQL:架构-gt;查询执行流程-gt;SQL解析顺序!

    一.前言 本文将从MySQL总体架构--->查询执行流程--->语句执行顺序来探讨一下其中的知识. 二.MySQL架构总览 架构最好看图,再配上必要的说明文字. 下图根据参考书籍中一图为原 ...

  3. 追源索骥:透过源码看懂Flink核心框架的执行流程--来自GitHub

    追源索骥:透过源码看懂Flink核心框架的执行流程 联系qq2499496272可进行删除,需要文件版本的私聊!!~ 文章目录 追源索骥:透过源码看懂Flink核心框架的执行流程 前言 1.从 ~~H ...

  4. docker技术学习流程

    docker安装 安装docker(乌班图)-需要su权限 官网: Install Docker Engine on Ubuntu | Docker Documentation 帮助文档: 1.卸载旧 ...

  5. Mysql复习计划(一)- 字符集、文件系统和SQL执行流程

    Mysql复习计划(一)- 字符集.文件系统和SQL执行流程 前言 一. Mysql字符集 1.1 Mysql5.7和8.0的默认字符集 1.1.1 修改默认的字符集 1.1.2 修改已有库表的字符集 ...

  6. Docker的RUN流程和Docker原理、Docker的常用命令、其他命令

    Docker的RUN流程和Docker原理 Run流程 底层原理 Docker是怎么工作的 Docker为什么比VM快 Docker的常用命令 帮助命令 镜像命令 查看镜像 搜索镜像 下载镜像 指定版 ...

  7. MyBatis 的执行流程,面试的时候用得上

    前言 MyBatis可能很多人都一直在用,但是MyBatis的SQL执行流程可能并不是所有人都清楚了,那么既然进来了,通读本文你将收获如下: 1.Mapper接口和映射文件是如何进行绑定的 2.MyB ...

  8. 动态执行流程分析和性能瓶颈分析的利器——gperftools的Cpu Profiler

    在<动态执行流程分析和性能瓶颈分析的利器--valgrind的callgrind>中,我们领略了valgrind对流程和性能瓶颈分析的强大能力.本文将介绍拥有相似能力的gperftools ...

  9. 动态执行流程分析和性能瓶颈分析的利器——valgrind的callgrind

    在<内存.性能问题分析的利器--valgrind>一文中我们简单介绍了下valgrind工具集,本文将使用callgrind工具进行动态执行流程分析和性能瓶颈分析.(转载请指明出于brea ...

最新文章

  1. 乔布斯当年是这样面试我的,你能挺到哪一步?
  2. 数据结构 - 反转单链表(C++)
  3. 读《分布式一致性原理》JAVA客户端API操作3
  4. Vue学习(组件的定义及调用、路由)-学习笔记
  5. C#的async和await
  6. 前端学习(804):替换字符串和转换为数组
  7. 【PAT甲级 - 1013】Battle Over Cities (25分)(并查集)
  8. javascirpt历史澄清误解基本概念特点编程语言web2.0网页javascript - javascirpt知识大全...
  9. MATLAB中的清除,oop – 在MATLAB中清除类定义
  10. javaScript笔记整理(一)
  11. 学python能赚钱吗-哪种Python程序员最赚钱?爬虫数据告诉你!
  12. 2018ACM-ICPC南京赛区网络赛: B. The writing on the wall
  13. java 对象与引用_Java --对象引用与对象的区别
  14. SQL Server 远程连接出错~~~无法访问服务器
  15. 计算机视觉 || Canny算子实现边缘分割并进一步处理
  16. 时尚html输入框,12款经典时尚的HTML5应用
  17. 《嵌入式系统设计师教程》读后感:2.6嵌入式系统电源
  18. ecshop小京东首页分类楼层左侧广告修改方法
  19. 盘点程序员的花式赚外快的骚操作
  20. 5. 第五阶段 测试开发技术 - JAVA

热门文章

  1. fonts.conf
  2. DELETE_FAILED_INTERNAL_ERROR Error while Installing APK
  3. 模拟jQuery--获取事件的封装
  4. VS2012:出现devenv.sln解决方案保存对话框
  5. 话里话外:参展管理信息化年会 聚会谈咨询需求有市场
  6. 网络管理员考试案例梳理、真题透解与强化训练
  7. HackerOne漏洞奖励计划扩展至开源漏洞
  8. 追风猎洞只能喝西北风吗?
  9. VMware ESXi 高危漏洞的补丁被指不完整
  10. Codeforces Round #542(Div. 2) B.Two Cakes