然后要明白这些 images 是如何让 containers 使用的。最后简短介绍一些 images 和 containers 操作。
为了很好的使用存储引擎,必须明白 Dcoker 是如何创建和存储 images 的。
Images and layers下图,Ubuntu15.04 image 包含了 4 个堆 image layers.
layers 被堆放在顶端,以形成容器根文件系统的基础。
每个 Docker image 都会参照只读列表里的 layers, 这些 layers 代表不同的文件系统。
下图,展示了以 Ubuntu15.04 为基础的容器。
对正在运行的容器做所有的修改,比如创建新文件,修改已存在的文件,删除文件。这些操作都是在可写的容器层。
当创建一个新的容器,将底层堆的最上层设置成可写,通常这层叫做 "containers layer"
Docker 存储引擎负责堆放这些 layers, 然后提供一个统一的展示。
Containers and layers下图显示多个容器共用 Ubuntu15.04image:
因为每个容器有自己的可写容器层,所有的更改都存储在这容器层中,这意味着多个容器可以同时使用同一个底层 image。
当容器被删除的时候这个可写层也就被删除了。而底层的 image 没有改变。
容器和镜像主要的不同就是,顶层可写层。所有的修改操作都是存储在这个可写层的。
存储引擎的两个关键技术:堆栈 image 层和 copy-on-write.
docker 存储引擎负责开启和管理 image 层 和可写的 container 层。
Copy-on-write 策略copy-on-write 是个很想共享和复制的策略。
共享是提升资源利用率的很好途径。
一般在 / var/lib/docker/. 目录中。
所有 image 和 containers 层存在与 Dcoker 本地的存储空间中,都被存储引擎管理。
- zane@zane-V:~$ docker pull ubuntu:15.04
- 15.04: Pulling from library/ubuntu
- 9502adfba7f1: Pull complete
- 4332ffb06e4b: Pull complete
- 2f937cc07b5f: Pull complete
- a3ed95caeb02: Pull complete
- Digest: sha256:2fb27e433b3ecccea2a14e794875b086711f5d49953ef173d8a03e8707f1510f
- Status: Downloaded newer image forubuntu:15.04
4. 在 Dockerfile 文件的目录下启动命令行,并创建新 image
3. 保存并退出文件
RUN echo "Hello world" > /tmp/newfile
FROM ubuntu:15.04
2. 在 image 中 /tmp 目录增加 newfile, 内容为 "Hello world"
FROM ubuntu:15.04
1. 在空目录中写 Dockerfile,以 15.04 为基础
做些实验来说明共享 image:
尽管显示的方式不同,但是 1.10 前后都是可以共享 image 层的。
在 docker1.10 之前,存储每个 layer 都是以 image layer ID 为目录名称存储的。docker1.10 之后就不是这样了。
这 4 个 image layer 分别存在自己目录中,当然这些目录在 Dcoker 本地的存储空间中
从上面的输出来看,实际上 pull 了 4 个 image layer. 这四个 image layers 组成了 ubuntu:15.04 这个 Dcokerimage。
- zane@zane-V:~/mydockerbuild$ docker build -t changed-ubuntu .
- Sending build context to Docker daemon 2.048 kB
- Step 1: FROM ubuntu:15.04---> d1b55fd07600
- Step 2: RUNecho "Hello world"> /tmp/newfile
- ---> Runningin 914cfa4e2724
- ---> 3a3a082982a2
- Removing intermediate container 914cfa4e2724
- Successfully built 3a3a082982a2
5. 运行 docker image 命令验证新 changed-ubuntu image 已经在 docker 本地存储空间
上面的输出显示新的 image 被创建 ID:3a3a082982a2
- zane@zane-V:~/mydockerbuild$ docker images
- REPOSITORY TAG IMAGE ID CREATED SIZE
- changed-ubuntu latest 3a3a082982a23minutes ago131.3 MB
- zane/aiapple007d2f5f84bec8712days ago275.1 MB
- zane/aiapple009d2f5f84bec8712days ago275.1 MB
- ziapple latest d2f5f84bec87 12days ago275.1MB
6. 运行 docker history 命令来查看创建 changed-ubuntu image 时使用了哪些 image 层。
- zane@zane-V:~/mydockerbuild$ docker history changed-ubuntu
- IMAGE CREATED CREATED BY SIZE COMMENT
- 3a3a082982a2 6minutes ago /bin/sh-cecho "Hello world"> /tmp/newfile12 B
- d1b55fd07600 11months ago /bin/sh-c #(nop) CMD ["/bin/bash"]0 B
- 11months ago /bin/sh-csed-i's/^#\s*\(deb.*universe\)$/ 1.879 kB 11months ago /bin/sh-cecho '#!/bin/sh'> /usr/sbin/polic701 B
- 11months ago /bin/sh-c #(nop) ADDfile:3f4708cf445dc1b537131.3MB
图片是官方例子,其实本地的 3a3a082982a2,就是官方例子中的 94e6b7d2c720.
注意:changed-ubuntu image 并没有自己独享的每一个 image 层。从下图中可以看到,新 image 与 ubuntu15.04 是共享底层的 4 个 image 的。
可以看到他们的创建时间都是很久之前的。
可以看到只有 3a3a082982a2 是刚创建的,且执行了我们预期的命令。而其余 4 个都是 ubuntu.15.04 原本就有的。
重写 Dcokerfile:
那么如果再以 changed-ubuntu 为基础 image 再创建新的 image 呢?
可以看到 docker history 还可以看到每一层的大小,我们刚刚创建的 3a3a082982a2 只有 12B,也就是说,我们刚刚创建了 changed-ubuntu 只额外占用了 12B 的空间,其余都是共享的。
- zane@zane-V:~/mydockerbuild$cat Dockerfile
- FROM changed-ubuntu
- RUN echo "Based on changed-ubuntu"> /tmp/new.t
创建新的 image:
- zane@zane-V:~/mydockerbuild$ docker build -t bashed_on_changed-ubuntu .
- Sending build context to Docker daemon 2.048 kB
- Step 1: FROM changed-ubuntu
- ---> 3a3a082982a2
- Step 2: RUNecho "Based on changed-ubuntu"> /tmp/new.t
- ---> Runningin 0132c351fa33
- ---> 93a447865aa6
- Removing intermediate container 0132c351fa33
- Successfully built 93a447865aa6
查看新 image 的 history
- zane@zane-V:~/mydockerbuild$ docker history bashed_on_changed-ubuntu
- IMAGE CREATED CREATED BY SIZE COMMENT
- 93a447865aa6 29seconds ago /bin/sh-cecho "Based on changed-ubuntu"> /24 B
- 3a3a082982a2 31minutes ago /bin/sh-cecho "Hello world"> /tmp/newfile12 B
- d1b55fd07600 11months ago /bin/sh-c #(nop) CMD ["/bin/bash"]0 B
- 11months ago /bin/sh-csed-i's/^#\s*\(deb.*universe\)$/ 1.879 kB 11months ago /bin/sh-cecho '#!/bin/sh'> /usr/sbin/polic701 B
- 11months ago /bin/sh-c #(nop) ADDfile:3f4708cf445dc1b537131.3MB
可以看到 bashed_on_changed-ubuntu, 共享了 changed-ubuntu 的所有 image,在重新创建了 93a447865aa6;并且只占用了额外的 24B。
复制使容器更效率每个容器有它自己的可写层。
只有容器层是可写的,共享 image 层都是只读的。这样保证了,多个容器层底层共享 image 的数据安全。
操作的细节取决于不同的存储引擎,对于 AUFS 和 OverlayFS 存储引擎来说 copy-on-write 操作非常完美:
当在容器中修改一个已存在的文件,Dcoker 使用存储引擎执行 copy-on-write 操作。
1. 在命令行运行 5 次 docker run
如果以我们刚刚创建的 changed-ubuntu 为基础运行了 5 个容器会发生什么?
- zane@zane-V:~$ docker run -dit changed-ubuntu bash
- 9635de83c668a61be7077ad309798a686fbfe29abf5f152dc84d641dd4b84a7b
- zane@zane-V:~$ docker run -dit changed-ubuntu bash
- f92f01d11ff0d93f09ca6b94ebda3b699dc959297cf90565acf7f337d1c8af03
- zane@zane-V:~$ docker run -dit changed-ubuntu bash
- a341fec4b3604a21dda733839cfea56005712335daa8344ece0a22c4df53076a
- zane@zane-V:~$ docker run -dit changed-ubuntu bash
- 54b836a993084953972507015515ad4a9c8c779508ad1a581a7b50fa0a496f42
- zane@zane-V:~$ docker run -dit changed-ubuntu bash
- 7f3ea62f1430b20ab7948281d88ef96140a688cf7bd08454c40ce1ad3d057620
2. 运行 docker ps 命令验证 5 个容器正常运行中
以 changed-ubuntu image 为基础启动了 5 个容器。当每个容器被创建后,Dcoker 会分别增加一个可写层,并分配随机的 UUID。
- zane@zane-V:~$ dockerps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 7f3ea62f1430 changed-ubuntu"bash" 3minutes ago Up3 minutes berserk_borg
- 54b836a99308 changed-ubuntu"bash" 3minutes ago Up3 minutes condescending_mccarthy
- a341fec4b360 changed-ubuntu"bash" 3minutes ago Up3 minutes ecstatic_saha
- f92f01d11ff0 changed-ubuntu"bash" 3minutes ago Up3 minutes hungry_mestorf
- 9635de83c668 changed-ubuntu"bash" 3minutes ago Up3minutes
3. 列出本地存储的内容
上面 5 个运行的容器,都共享 changed-ubuntu 镜像。CONTAINER ID 是由 UUID 所派生的。
- $ sudo ls /
- var / lib / docker / containers
copy-on-write
因为在启动的时候,Dcoker 仅需要为每个容器创建一个可写层。
数据卷和存储引擎当容器被删除时,任何存储到数据卷的数据都会持久化在 docker 主机上。
数据卷驻留在 Docker 主机上的本地存储区域之外,进一步增强了它们与存储驱动程序控制的独立性。
可以挂载多个数据卷到容器。多个容器也可以共享一个或者多个数据卷。
数据卷是不被 docker 的存储引擎所控制的。读写数据卷是绕过存储引擎的,并以本机主机速度运行。
数据卷是 docker 本地主机的文件系统里的一个目录或者文件,这个目录或文件是直接挂载到容器里的。
当删除容器时,任何没有存到数据卷里的容器修改内容,也会被删除。
总结来源: http://www.cnblogs.com/Aiapple/p/6971292.html