为了更好的使用storage driver,最好首先了解Docker如何构建,如何存储images,镜像如何被container使用。
Images和Layers
Docker镜像是通过一组layer构建的
FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py
上面的Dockerfile由4个命令构成,每个都会创建一个layer,而me层layer都是与之前layer的不同。
Contianer & Layer
多个容器共享Ubuntu 15.04镜像
Container Size
如果要大致查看容器的大小,可以
docker ps -s
其中,size表示每个容器writable layer的数据量。
virtual size表示size加上read-only镜像的数据量。
docker镜像
当使用docker pull
命令拉取镜像是,通常会存储在/var/lib/docker/
$ docker pull ubuntu:15.04
15.04: Pulling from library/ubuntu
1ba8ac955b97: Pull complete
f157c4e5ede7: Pull complete
0b7e98f84c4c: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:5e279a9df07990286cce22e1b0f5b0490629ca6d187698746ae5e28e604a640e
Status: Downloaded newer image for ubuntu:15.04
每层layer会存放在Docker host的本地存储区域的专有目录,比如/var/lib/docker/<storage-driver>/layers/
比如,默认的storage driver使用aufs
$ ls /var/lib/docker/aufs/layers
1d6674ff835b10f76e354806e16b950f91a191d3b471236609ab13a930275e24
5dbb0cbe0148cf447b9464a358c1587be586058d9a4c9ce079320265e2bb94e7
bef7199f2ed8e86fa4ada1309cfad3089e0542fec8894690529e4c04a7ca2d73
ebf814eccfe98f2704660ca1d844e4348db3b5ccc637eb905d4818fbfb00a06a
假设,有两个不同的Dockerfile,创建镜像acme/my-base-image:1.0
FROM ubuntu:16.10
COPY . /app
第2个镜像基于acme/my-base-image:1.0
,添加新的layer
FROM acme/my-base-image:1.0
CMD /app/hello.sh
第2个镜像将包含第1个镜像的所有layers,同时包括新添加的layer。
首先,创建cow-test/
目录,并进入该目录。在该目录创建hello.sh
#!/bin/sh
echo "Hello world"
修改hello.sh为执行权限
chmod +x hello.sh
将第1个Dockerfile的内容复制到Dockerfile.bas
,将第2个Dockerfile内容复制到新的Dockerfile文件。
在cow-test/
目录构建第1个镜像
$ docker build -t acme/my-base-image:1.0 -f Dockerfile.base .
Sending build context to Docker daemon 4.096kB
Step 1/2 : FROM ubuntu:16.10
---> 31005225a745
Step 2/2 : COPY . /app
---> Using cache
---> bd09118bcef6
Successfully built bd09118bcef6
Successfully tagged acme/my-base-image:1.0
构建第2个镜像
$ docker build -t acme/my-final-image:1.0 -f Dockerfile .
Sending build context to Docker daemon 4.096kB
Step 1/2 : FROM acme/my-base-image:1.0
---> bd09118bcef6
Step 2/2 : CMD /app/hello.sh
---> Running in a07b694759ba
---> dbf995fc07ff
Removing intermediate container a07b694759ba
Successfully built dbf995fc07ff
Successfully tagged acme/my-final-image:1.0
查看镜像
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
acme/my-final-image 1.0 dbf995fc07ff 58 seconds ago 103MB
acme/my-base-image 1.0 bd09118bcef6 3 minutes ago 103MB
查看镜像每个layer的构成
$ docker history bd09118bcef6
IMAGE CREATED CREATED BY SIZE COMMENT
bd09118bcef6 4 minutes ago /bin/sh -c #(nop) COPY dir:35a7eb158c1504e... 100B
31005225a745 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 3 months ago /bin/sh -c mkdir -p /run/systemd && echo '... 7B
<missing> 3 months ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\... 2.78kB
<missing> 3 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B
<missing> 3 months ago /bin/sh -c set -xe && echo '#!/bin/sh' >... 745B
<missing> 3 months ago /bin/sh -c #(nop) ADD file:eef57983bd66e3a... 103MB
$ docker history dbf995fc07ff
IMAGE CREATED CREATED BY SIZE COMMENT
dbf995fc07ff 3 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/a... 0B
bd09118bcef6 5 minutes ago /bin/sh -c #(nop) COPY dir:35a7eb158c1504e... 100B
31005225a745 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 3 months ago /bin/sh -c mkdir -p /run/systemd && echo '... 7B
<missing> 3 months ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\... 2.78kB
<missing> 3 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B
<missing> 3 months ago /bin/sh -c set -xe && echo '#!/bin/sh' >... 745B
<missing> 3 months ago /bin/sh -c #(nop) ADD file:eef57983bd66e3a... 103MB
由上可知,除了第2个镜像的top layer不同之外,其他layer会在两个镜像间共享,但只会在/var/lib/docker
保存一次。
而top layer并不会占用空间,因为它不会更改任何文件,而只是运行命令。
docker history中的<missing>行,表示layer是在其他system构建,而在本地不可获取。
copy-on-write
当启动容器时,会在其他layer的顶层增加可写的container layer。当容器中的文件修改时,storage driver会执行copy-on-write操作,对于aufs、overlay、overlay2,copy-on-write操作的过程大致是:
在image layers搜索文件,当搜索到之后,它会加入cache
当发现file的第一个copy时,执行
copy_up
操作,将其拷贝到容器layer任何对文件的修改都是对文件副本的修改。
Btrfs,ZFS和其他driver在处理copy-on-write时并不相同。
对于write-heavey的应用,不应该在container存储数据,而是使用Docker volumes。
启动多个容器
$ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_2 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_3 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_4 acme/my-final-image:1.0 bash \
&& docker run -dit --name my_container_5 acme/my-final-image:1.0 bash
c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513
1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c
38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544
1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765
查看运行的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a174fc216cc acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_5
38fa94212a41 acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_4
1e7264576d78 acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_3
dcad7101795e acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_2
c36785c423ec acme/my-final-image:1.0 "bash" About a minute ago Up About a minute my_container_1
local storage的列表
$ sudo ls /var/lib/docker/containers
1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765
1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c
38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544
c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513
容器的大小
$ sudo du -sh /var/lib/docker/containers/*
32K /var/lib/docker/containers/1a174fc216cccf18ec7d4fe14e008e30130b11ede0f0f94a87982e310cf2e765
32K /var/lib/docker/containers/1e7264576d78a3134fbaf7829bc24b1d96017cf2bc046b7cd8b08b5775c33d0c
32K /var/lib/docker/containers/38fa94212a419a082e6a6b87a8e2ec4a44dd327d7069b85892a707e3fc818544
32K /var/lib/docker/containers/c36785c423ec7e0422b2af7364a7ba4da6146cbba7981a0951fcc3fa0430c409
32K /var/lib/docker/containers/dcad7101795e4206e637d9358a818e5c32e13b349e62b00bf05cd5a4343ea513