五、Docker镜像
Base镜像
-
不依赖其他镜像,从scratch构建(从0开始)
-
其他镜像可以在此基础上进行扩展
常见的的base镜像
各种Linux发行版的Docker镜像,比如Ubuntu(桌面应用为主的Linux操作系统)、Debian(精简的 Linux 发行版)、CentOS等
rootfs
Linux操作系统由内核空间和用户空间组成
内核空间是kernel,Linux刚启动时会加载bootfs文件系统,之后bootfs会被卸载掉。
用户空间的文件系统是rootfs,包含熟悉的/dev、/proc、/bin等目录。
base镜像,底层直接用Host的kernel,自己只需要提供rootfs即可。
一个精简的OS,rootfs可以很小,只需要包括最基本的命令,工具、程序库即可。对比其他的Linux发行版,CentOS的rootfs已经很臃肿了。
不同Linux发行版的区别主要是rootfs
Ubuntu使用upstart管理服务,apt管理软件包
CentOS使用systemd和yum
各Linux发行版的内核差别不大
镜像分层结构
Docker支持通过扩展现有镜像,创建新的镜像。
采用分层结构可以进行共享资源,有多个镜像都从相同的base镜像构建而来,那么Docker Host只需在磁盘上保存一份base镜像,同时内存中也只需要加载一份base镜像,就可为所有容器服务了,而且镜像的每一层都可以被共享。
当容器启动后,一个新的可写层被加载到镜像的顶层,这一层通常被称为容器层,容器层之下的都叫镜像层。
容器层
对容器的改动都只会发生在容器中,只有容器层是可写的,容器层下面的所有镜像层都是只读的。
所有镜像层会联合在一起组成一个统一的文件系统,如果不同层中有一个相同路径的文件,比如/a,上层的/a会覆盖下层的/a,用户只能访问到上层的文件/a。
文件操作流程
添加文件:在容器中创建文件时,新文件被添加到容器层中
读取文件:在容器中读取某个文件时,Docker会从上往下依次在各镜像层中查找此文件,一旦找到,打开并读入内存
修改文件:在容器中修改已存在的文件时,Docker会从上往下一次在各镜像层中找到此文件,一旦找到,立即将其复制到容器层,然后修改
删除文件:在容器中删除文件时,Docker也是从上往下依次在镜像层中查找此文件,找到后,会在容器层中记录下此删除操作
Copy-on-Write特性
当需要修改时才复制一份数据,容器层保存的是镜像变化部分,不会对容器本身进行任何修改。
容器层记录对容器的修改,所有镜像层都是只读的,不会被容器修改,所有镜像可以被多个容器共享。
构建镜像
分为Commit和Dockerfile文件创建镜像
Docker Commit方式创建镜像
创建centos容器
docker run -it centos
安装vim
vim 1.txt
yum install vim
创建带有vim功能的centos新镜像
docker commit infallible_galois centos-with-vim
特点
-
这种方式创建镜像,容易出错,而且效率低、可重复性弱
-
使用者不知道镜像是如何创建的,里面是否有恶意程序,无法对精选进行审计,存在安全隐患
Dockerfile构建镜像的底层也是docker commit一层一层的构建新镜像。
Dockerfile方式创建镜像
Dockerfile是一个文本文件,记录了镜像构建的所有步骤
Dockerfile的常用命令
FROM
指定base镜像
MAINTAINER(maintainer,维护者)
设置镜像的作者
COPY
将文件从build context(build上下文目录)复制到镜像
COPY src dest、COPY [“src”, “dest”]
scr: 用于指定build context中的文件或目录
dest:用于指定容器中的文件或目录
ADD
与COPY类似
从build context复制文件到镜像,使用COPY时,如果src是归档文件(tar、zip、tgz等)时,文件会被自动解压到dest,COPY命令不会解压
ENV
设置环境变量,环境变量可被后面的指令使用
ENV JAVA_HOME /docker/local/jdk1.8.0_241
EXPOSE
指定容器中的进程会监听某个端口,Docker可以将该端口暴露出来
VOLUME
将文件或目录声明为volume,挂载目录
WORKDIR
为后面的RUN、CMD、ENTRYPOINT、ADD、COPY指令设置镜像中的当前工作目录
RUN
在构建镜像时需要运行的命令
CMD
容器启动时运行指定的命令
一个Dockerfile可以有多个CMD指令,但只有最后一个生效,CMD可以被docker run之后的参数替换
ENTRYPOINT
设置容器启动时运行的命令
Dockerfile中可以有多个ENTRYPOINT指令,但只有最后一个生效。CMD或docker run之后的参数会被当做参数传递给ENTRYPOINT
Shell和Exec格式
Shell
CMD echo “Hello World”
当指令执行时,shell格式底层会调用 /bin/sh -c [command]
Exec
CMD ["/bin/echo", “Hello World”]
当执行执行时,会直接调用 [command],不会被shell解析
CMD和ENTRYPOINT推荐使用Exec格式,因为指令可读性更强,更容易理解
tag
版本号
docker tag imagename imagename:版本号