Docker——镜像管理
镜像概念
docker 镜像是一个只读的 docker 容器模板,含有启动 docker 容器所需的文件系统结构及其内容,因此是启动一个 docker 容器的基础。
rootfs(根文件系统)
rootfs 是 docker 容器在启动时内部进程可见的文件系统,即 docker 容器的根目录。rootfs 通常包含一个操作系统运行所需的文件系统,例如可能包含典型的类 Unix 操作系统中的目录系统,如 /dev、/proc、/bin、/etc、/lib、/usr、/tmp 及运行 docker 容器所需的配置文件、工具等.
- 传统Linux系统
传统Linux操作系统内核启动,首先挂载一个只读的 rootfs,当系统检测其完整性之后,再将其切换为读写模式。
- docker架构
当 docker daemon 为 docker 容器挂载 rootfs 时,沿用了 Linux 内核启动时的做法,即将 rootfs 设为只读模式。在挂载完毕之后,利用联合挂载(union mount)技术在已有的只读 rootfs 上再挂载一个读写层。
镜像的运行
如上图:
当由 ubuntu:14.04 镜像启动容器时,ubuntu:14.04 镜像的镜像层内容将作为容器的 rootfs;而 ubuntu:14.04 镜像的 json 文件,会由 docker daemon 解析,并提取出其中的容器执行入口 CMD 信息,以及容器进程的环境变量 ENV 信息,最终初始化容器进程。当然,容器进程的执行入口来源于镜像提供的 rootfs。
镜像的存储驱动(storage driver)
对于一个容器的数据新增,修改,都存储在可写层.当你删除一个容器的时候,可写层也将被删除(注意:可写层与数据卷的区别).然而镜像层是保持不变的.
上图展示了,多个容器共享一个镜像.镜像层是只读层,不变的.多个容器层在同一个镜像层之上,并且相互独立,互相不影响.
docker 存储驱动的职责就是将镜像层和可写容器层管理起来.不同的驱动实现管理的方式也不一致。
实现容器与镜像管理的两个关键技术就是可堆叠的镜像层和copy-on-write (CoW,写时复制).
docker目前支持的存储驱动有:OverlayFS,AUFS,Btrfs,Device Mapper,VFS,ZFS.
docker的存储驱动目前并没有一个通用的,完美的,适用于所有环境的存储驱动.所以需要根据自己的环境来有所选择。
存储驱动 | 特点 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
AUFS | 联合文件系统、未并入内核主线、文件级存储 | 作为docker的第一个存储驱动,已经有很长的历史,比较稳定,且在大量的生产中实践过,有较强的社区支持 | 有多层,在做写时复制操作时,如果文件比较大且存在比较低的层,可能会慢一些 | 大并发但少IO的场景 |
overlayFS | 联合文件系统、并入内核主线、文件级存储 | 只有两层 | 不管修改的内容大小都会复制整个文件,对大文件进行修改显示要比小文件消耗更多的时间 | 大并发但少IO的场景 |
Devicemapper | 并入内核主线、块级存储 | 块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件 | 不支持共享存储,当有多个容器读同一个文件时,需要生成多个复本,在很多容器启停的情况下可能会导致磁盘溢出 | 适合io密集的场景 |
Docker镜像制作
多数情况下,我们做镜像是基于别人已存在的某个基础镜像来实现的,我们把它称为base image。比如一个纯净版的最小化的centos、ubuntu或debian。
Docker镜像制作实例一:
- 选取base image镜像,这里以busybox为例
[root@localhost boot]# docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
Digest: sha256:49dae530fd5fee674a6b0d3da89a380fc93746095e7eca0f1b70188a95fd5d71
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest a77dce18d0ec 6 days ago 1.24MB
httpd latest dd85cdbb9987 3 weeks ago 138MB
nginx stable 05f64a802c26 3 weeks ago 133MB
- 以busybox镜像为模板,创建test1容器
[root@localhost boot]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
## 运行此容器,并以交互方式进入容器内部
[root@localhost boot]# docker run -it --name 'test1' busybox
/ # ls
bin dev etc home proc root sys tmp usr var
- 修改容器内部文件数据(这里以创建新文件为例)
/ # mkdir data
/ # echo 'hello world' > /data/abc
/ # cat /data/abc
hello world
- 保持容器运行,另开一个host终端,并将此容器保存为新的镜像
[root@localhost ~]# docker commit -p test1
sha256:c3b1c27be67af7f805b222d1bfd21f9c7752ae955563290dd4930173f17a7720
## 查看目前docker本地的所有镜像
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> c3b1c27be67a 6 seconds ago 1.24MB
busybox latest a77dce18d0ec 6 days ago 1.24MB
httpd latest dd85cdbb9987 3 weeks ago 138MB
nginx stable 05f64a802c26 3 weeks ago 133MB
- 重命名新生成的镜像以及定义版本号
[root@localhost ~]# docker tag c3b1c27be67a sawyer1995/test1:l0.1
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sawyer1995/busybox l0.1 c3b1c27be67a 2 minutes ago 1.24MB
busybox latest a77dce18d0ec 6 days ago 1.24MB
httpd latest dd85cdbb9987 3 weeks ago 138MB
nginx stable 05f64a802c26 3 weeks ago 133MB
-
将此作为个人镜像push到docker_hub上
- 在个人主页上创建新的仓库
- 输入仓库名字并创建
- 将本地镜像推送到个人主页上
### 登录个人主页 [root@localhost ~]# docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: sawyer1995 Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [root@localhost ~]# docker push sawyer1995/test1:l01 The push refers to repository [docker.io/sawyer1995/test1] l01: digest: sha256:fe03120da795790cc0058077c8a3ff375756c553e9e8be5ae4d2b76eaa5f7726 size: 734
- 查看个人主页是否push成功
- 在个人主页上创建新的仓库
-
验证push的镜像是否为修改过的镜像
## 删掉此前所有busybox的相关镜像
docker rmi 63c827625ddc
Untagged: sawyer1995/test1:l01
Untagged: sawyer1995/test1@sha256:fe03120da795790cc0058077c8a3ff375756c553e9e8be5ae4d2b76eaa5f7726
Deleted: sha256:63c827625ddc3b50c9e874dd040a0af6a7eead34847ce2521d41592e220c57ef
Deleted: sha256:f80271bcb88be88ba27c2f1c7e7bdc109ebaa8aeda8dc7fb128d4f5218b304d0
......
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest dd85cdbb9987 3 weeks ago 138MB
nginx stable 05f64a802c26 3 weeks ago 133MB
## 将此前push的镜像pull到本地,创建容器并执行
[root@localhost ~]# docker run --name 'ver1' -it sawyer1995/test1:l01
Unable to find image 'sawyer1995/test1:l01' locally
l01: Pulling from sawyer1995/test1
d60bca25ef07: Already exists
ca88adcce56d: Pull complete
Digest: sha256:fe03120da795790cc0058077c8a3ff375756c553e9e8be5ae4d2b76eaa5f7726
Status: Downloaded newer image for sawyer1995/test1:l01
/ #
## 成功进入到容器内,查看此前新建的文件,看是否存在
/ # cd data/
/data # ls
123
/data # cat 123
hello world
/data #
Docker镜像制作实例二(修改CMD):
- 还是以busybox为base images 创建并交互进入test2容器
[root@localhost ~]# docker run --name test2 --rm -it busybox
/ # ls
bin dev etc home proc root sys tmp usr var
## 另开终端,查看test2容器的默认CMD
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"sh" ## 默认进程为sh
],
- 生成index.html文件,作为http的主页文件
/ # mkdir data
/ # cd data/
/data # echo 'Test Web' > index.html
/data # cat index.html
Test Web
- 提交为新镜像
注意:这里要修改CMD,也就是默认进程,使得此容器启动时,以httpd的进程来访问index.html文件,从而实现web服务的效果
[root@localhost ~]# docker commit -c 'CMD ["/bin/httpd","-f","-h","/data"]' test2 sawyer1995/test1:l02
sha256:256055b555089b665850ac032f6da3d1295bbbbc0ba07e7533b161feb8bf0001
参数说明:
-f : httpd 命令已前台执行不退出
-h :指定家目录,默认当前目录
## 查看新的image
[root@localhost ~]# docker images sawyer1995/test2
REPOSITORY TAG IMAGE ID CREATED SIZE
sawyer1995/test2 l02 256055b55508 8 minutes ago 1.24MB
- 查看此image的默认CMD
[root@localhost ~]# docker inspect 256055b55508
......
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/httpd",
"-f",
"-h",
"/data"
],
- 将此image push到个人主页仓库中
[root@localhost ~]# docker push sawyer1995/test1:l02
[root@localhost ~]# docker push sawyer1995/test1:l02
The push refers to repository [docker.io/sawyer1995/test1]
387feb2e9433: Layer already exists
1dad141bdb55: Layer already exists
l02: digest: sha256:948a1d0b8558e0e815d4f1bc883142feb839beb704d38e9df5a25998fad8f68e size: 734
- 测试将此镜像Pull本地,并访问
[root@localhost ~]# docker run --rm -d sawyer1995/test1:l02
Unable to find image 'sawyer1995/test1:l02' locally
l02: Pulling from sawyer1995/test1
d60bca25ef07: Already exists
f91f934e1579: Pull complete
Digest: sha256:948a1d0b8558e0e815d4f1bc883142feb839beb704d38e9df5a25998fad8f68e
Status: Downloaded newer image for sawyer1995/test1:l02
e8aee14c4fd03286734001eaf50f791a9d6f722bc78eeb8fd8f13ad0cc874e26
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e8aee14c4fd0 sawyer1995/test1:l02 "/bin/httpd -f -h /d…" 13 seconds ago Up 12 seconds pensive_diffie
## curl测试访问网页
[root@localhost ~]# curl 172.17.0.2
Test Web