Docker Image 管理:从 Image 到 Container

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】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 目录下就有这些东西:

image

【plain】

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


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

aufs 目录的结构如下:

【plain】

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】

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]

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]

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]

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 管理:从 Image 到 Container)