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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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 plain copy print ?
  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管理,可能会稍微轻松些。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐