目录
一、docker镜像分层
1、docker三要素
2、创建容器的几种方式
3、镜像所包含的部分
4、镜像的分层原理
二、dockerfile介绍
1、dockerfile结构四部分
2、dockerfile操作指令
3、dockerfile镜像分层特点
三、dockerfile分层原理
1、涉及技术
2、docker存储引擎overlay分层结构
四、基于dockerfile构建镜像
1、Dockerfile结构四部分
2、编写dockerfile标准格式(构建nginx镜像)
3、优化dockerfile制作镜像
总结
一、docker镜像分层
1、docker三要素
镜像:容器的一种静态模板(一组资源的集合,分层的方式一层层累加,组成了完整的镜像
容器:是一种应用/环境的运行时状态/运行时环境
仓库:存放镜像
2、创建容器的几种方式
①基于已有的模板文件进行创建
②基于已有的镜像进行创建
③基于dockerfile创建
3、镜像所包含的部分
①基础镜像——操作系统centos 7等
②应用服务软件包——nginx等服务
③依赖环境——gcc gcc-C++ make jdk jre gd 等
④编译安装——./confugure
⑤应用服务的相关配置文件——.conf
⑥启动方式/容器开启时运行的脚本/命令/指令
4、镜像的分层原理
二、dockerfile介绍
dockerfile是由一组指令组成的文件。Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释。
1、dockerfile结构四部分
◆基础镜像信息
◆维护者信息
◆镜像操作指令
◆容器启动时执行指令
2、dockerfile操作指令
| 指令 | 含义 |
| FROM [镜像] | 指定新镜像所基于的镜像,第一条指令必须为FROM指令,每创建一个镜像就需要一条FROM指令 |
| MAINTAINER [名字] | 说明新镜像的维护人信息 |
| RUN [命令] | 在所基于的镜像执行命令,并提交到新的镜像中 |
| CMD [“要运行的程序”,“参数1”、“参数2”] | 指令启动容器时要运行的命令或者脚本,Dockerfile只能有一条CMD命令,如果指定多条则只能执行最后一条 |
| EXPOSE [端口号] | 指定新镜像加载到Docker时要开启的端口 |
| ENV [环境变量] [变量值] | 设置一个环境变量的值,会被后面的RUN使用 |
| ADD [源文件/目录] [目标文件/目录] | 将源文件复制到目标文件,源文件要与Dockerfile位于相同目录中,或者是一个URL,若源文件是压缩包则会将其解压缩 |
| COPY [源文件/目录] [目标文件/目录] | 将本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile在相同的目录中 |
| VOLUME [“目录”] | 在容器中创建一个挂载点 |
| USER [用户名/UID] | 指定运行容器时的用户 |
| WORKDIR [路径] | 为后续的RUN、CMD、ENTRYPOINT指定工作目录,相当于是一个临时的"CD",否则需要使用绝对路径 |
| onBUILD [命令] | 指定所生成的镜像作为一个基础镜像时所要运行的命令(是一种优化) |
| HEALTHCHECK | 健康检查 |
注:
①、ADD和copy区别
◆Dockerfile中的COPY指令和ADD指令都可以将主机上的资源复制或加入到容器镜像中,都是在构
建镜像的过程中完成的。
◆copy = cp复制,将宿主机指定的文件复制到image层中(节省资源)
◆ADD可以复制,同时兼有了解压的功能add nginx-1.12.tar.gz /root/nginx(消耗资源),在复制进
去的同时会对压缩包进行解压到容器内部就是 nginx-1.12/,◆COPY指令和ADD指令的唯一区别在
于是否支持从远程URL获取资源。COPY指令只能从执行docker build所在的主机上读取资源并复
制到镜像中。而ADD指令还支持通过URL从远程服务器读取资源并复制到镜像中add复制的对象可
以是URL,跨节点的数据(URL)。
注意:满足同等功能的情况下,推荐使用COPY指令。ADD指令更擅长读取本地tar文件并解压缩。
②、CMD和entrypoint的区别、shell模式与exec模式的区别
它们都是容器启动时要加载的命令。cmd是容器环境启动时默认加载的命令;entrypoint是容器环
境启动时第一个加载的命令程序/脚本程序init。
◎如果 ENTRYPOINT使用了shell模式,CMD指令会被忽略。
entrypoint ["sh","-c", "echo $HOME"]
cmd [ "restart" ] #CMD会被忽略
◎如果 ENTRYPOINT使用了exec模式,CMD指定的内容被追加为ENTRYPOINT 指定命令的参
数。
entrypoint ["/etc/init.d/nginx"]
cmd [ "restart"] #CMD作为entrypoint的参数
◎如果 ENTRYPOINT使用了exec模式,CMD也应该使用exec模式。
同一个dockerfile中有多个cmd指令的话,哪个生效?最后一个生效。
◎如果dockerfile中同时有多个cmd命令,docker build -t nginx:new
/bin/bash 哪个生效?docker build指定的生效。
◎如果dockerfile中cmd和entrypoint同时存在哪个生效呢?看情况,如果都是默认加载的类型。
cmd:默认加载的命令
entrypoint:第一个加载的环境
◎exec方式启动的话,那么entrypoint会覆盖,或将cmd做为entrypoint传入参数;shell 方式启动的话,直接就是entrypoint生效。
◎exec模式与shell模式:
exec:容器加载时使用的启动的第一个任务进程
shell:容器加载时使用的第一个bash
3、dockerfile镜像分层特点
◆Dockerfile中的每个指令都会创建一个新的镜像层;
◆镜像层将被缓存和复用;
◆当Dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;
◆某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效;
◆镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件。
三、dockerfile分层原理
docker容器是基于AUFS构建,而AUFS是一种可叠加的文件系统。Docker镜像位于bootfs之
上;每一层镜像的下一层成为父镜像;第一层镜像成为base image(操作系统环境镜像);最后
为容器层(可读可写),在最顶层( writable);容器层以下都是readonly。
1、涉及技术
①、bootfs (boot file system)内核空间
主要包含bootloader和kernel。bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件
系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot
加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交
给内核,此时系统也会卸载bootfs。
在linux操作系统中(不同版本的linux发行版本),linux.加载bootfs时会将rootfs设置为read-only,
系统自检后会将只读改为读写,让我们可以在操作系统中进行操作。
②、rootfs (root file system)内核空间
rootfs即根文件系统
在bootfs之上 (base images,例如centos 、 ubuntu)。包含的就是典型 Linux系统中
的/dev,/proc,/bin,/etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如
Ubuntu,Centos等等。
③、AUFS与overlay / overlay2 (docker 高版本)
AUFS是一种联合文件系统。内核默认使用的就是AUFS,它使用同一个Linux host上的多个目录,
逐个堆叠起来,对外呈现出一个统一的文件系统。一种可叠加式的文件系统,主要功能是把多个文
件夹的内容合并到一起,提供一个统一的视图, 主要用于各个Linux发行版的livecd中,以及
docker里面用来组织image,使用AUFS该特性,实现了docker镜像的分层。
而docker使用了overlay/overlay2存储引擎/驱动来支持分层结构。OverlayFs将单个Linux主机上的
两个目录合并成一个目录。这些目录被称为层,统一过程被称为联合挂载
④、LXC(内核容器技术)
LXC内核中容器技术,早期docker在没有将资源容器化的功能时,就是靠内核中LXC来完成容器虛
拟化的;现在docker拥有了自己的docker libcontainer库文件,这个库文件可以做到将资源容器化
的操作,所以对LXC的依赖性大大降低。
LXC内核中容器技术/驱动:将资源容器化(虚拟化);是早期docker的依赖组件;目前docker拥有自
己的libcontianer库,可以实现容器虚拟化的功能,对LXC的依赖性降低。
⑤、注意:为什么docker的centos镜像只有200M多一点?
bootfs + rootfs:作用是加载、引导内核程序,以及挂载使用linux操作系统(centos ubantu)等等一
些关键的目录文件。
docker实现了将内核中的bootfs和rootfs进行了简单分离,而对于不同的linux发行版,bootfs基本是
一致的,rootfs会有差别,因此不同的发行版可以公用bootfs;对于一个精简的OS,rootfs可以很
小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,docker自
己只需要提供rootfs 就行了。
因为各linux发行版本公用一套bootfs引导、加载文件系统(是由宿主机内核提供的),同时vm虚拟
机的操作系统需要完整的模拟出来,所以容器的操作系统比vm虚拟机的操作系统更为轻量级(区
别在于容器是共享宿主机内核的)。
2、docker存储引擎overlay分层结构
docker使用了overlay/overlay2存储引擎/驱动来支持分层结构。OverlayFs将单个Linux主机上的两
个目录合并成一个目录。这些目录被称为层,统一过程被称为联合挂载。
overlayfs在linux主机上只有两层,一个目录在下层,用来保存镜像;另外一个目录在上层,用来存
储容器信息。
Ⅰ、rootfs 基础镜像
Ⅱ、lower 下层信息(为镜像层,容器)
Ⅲ、upper 上层目录(容器信息,可写)
Ⅳ、worker 运行的工作目录( copy-on-write写时复制,准备容器环境)
Ⅴ、mergod "视图层”(容器视图)
注:可以使用命令docker inspect 容器id 查看里面的一些分层。
注:在修改时,若upper层没有,则会将lower层有的文件复制到upper层进行修改并保存结果。
四、基于dockerfile构建镜像
dockerfile自动生成镜像,Dockerfile是由一组指令组成的文件,其中每条指令对应 Linux 中的一条
命令,Docker 程序将读取 Dockerfile 中的指令生成指定镜像。
1、Dockerfile结构四部分
①基础镜像信息(指定操作系统镜像是什么镜像、什么版本)
②维护者信息
③镜像操作指令
④容器启动时执行指令(启动容器的时候,执行的脚本/命令参数等等)
注:Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以"#"号开头的注释。
2、编写dockerfile标准格式(构建nginx镜像)
①、建立工作目录
[root@docker ~]# mkdir daemo #作为生成镜像的工作目录
[root@docker ~]# cd daemo/
②、创建并编写dockerfile文件
[root@docker nginx]# vim dockerfile ##第一行必须指明基于的基础镜像 FROM centos:7 ##维护该镜像的用户信息 MAINTAINER the centos progect##以下写镜像操作指令 RUN yum -y update RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make RUN useradd -M -s /sbin/nologin nginx ADD nginx-1.12.2.tar.gz /usr/local/src VOLUME ["/usr/local/nginx/html"] ##为后续的操作指令指定工作目录(相当于cd) WORKDIR /usr/local/src/nginx-1.12.2 RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make && make install ENV PATH /usr/local/nginx/sbin:$PATH ##开启80端口 EXPOSE 80 RUN echo "daemon off;">>/usr/local/nginx/conf/nginx.conf ##启动容器时执行指令脚本 CMD nginx ##查看我们制作的镜像,我们制作的标签为v的镜像大小为716MB,而docker仓库中的相同版本nginx1.12.0大小仅为107MB [root@docker ~]# docker images nginx v cfeb40a7b94d 2 hours ago 716MB nginx 1.12.0 313ec0a602bc 4 years ago 107MB
◆◆◆构建nginx镜像
①创建一个对应的目录( mkdir nginx)
②编写Dockerfile文件(最简单的方式,nginx部署脚本放进去,每条命令用RUN执行,环境变量使
用ENV,移动到对应目录使用workdir,EXPOSE暴露端口,最后使用CMD 进行启动设置)
③在nginx目录中上传nginx-1.12.2.tar.gz软件包等文件
④docker build 创建
⑤docker run运行容器
⑥检验
◆◆◆镜像构建过程中
①每一层镜像会临时产生一层新的镜像层,并且会运行为临时容器。
②每一层临时容器会基于前一层镜像的缓存层(容器)进行运行。
③如果该镜像层的临时容器在运行时报错,会exited (非0值)退出,并且在docker ps -a中会保存下
来,同时,docker build构建过程, 会中止。
④在基于同一个dockerfile修改时,修改的指令对应的image镜像缓存会失效,但该镜像层之前的
image层的缓存会保留。
3、优化dockerfile制作镜像
前面看到我们在未进行优化前的nginx:v大小未716MB,可以说很大了,下面我们就对其进行优
化。
①、优化1:不需要输出的指令丢入/dev/null (需要确定命令执行的是正确的)。
[root@docker nginx]# vim dockerfile FROM centos:7 RUN yum -y update &> /dev/null RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make &> /dev/null && yum clean all RUN useradd -M -s /sbin/nologin nginx ADD nginx-1.12.2.tar.gz /usr/local/src VOLUME ["/usr/local/nginx/html"] WORKDIR /usr/local/src/nginx-1.12.2 RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make && make install &> /dev/null ENV PATH /usr/local/nginx/sbin:$PATH EXPOSE 80 RUN echo "daemon off;">>/usr/local/nginx/conf/nginx.conf CMD nginx [root@docker nginx]# docker build -t "nginx:v1" . #构建为镜像优化1版本为nginx:v1 [root@docker nginx]# docker images #查看镜像大小 nginx v1 c63eab10ae17 about a minute ago 597MB nginx v cfeb40a7b94d 3 hours ago 716MB
注:结论:明显看到镜像大小减小了。
②、优化2:减少RUN指令的使用
[root@docker nginx]# vim dockerfile FROM centos:7 RUN yum -y update && yum -y install pcre-devel zlib-devel gcc gcc-c++ make &> /dev/null && yum clean all && useradd -M -s /sbin/nologin nginx ADD nginx-1.12.2.tar.gz /usr/local/src VOLUME ["/usr/local/nginx/html"] WORKDIR /usr/local/src/nginx-1.12.2 RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make && make install &> /dev/null && echo "daemon off;">>/usr/local/nginx/conf/nginx.conf ENV PATH /usr/local/nginx/sbin:$PATH EXPOSE 80 CMD nginx [root@docker nginx]# docker build -t "nginx:v2" . #构建为镜像优化2版本为nginx:v2 [root@docker nginx]# docker images #查看镜像大小 nginx v1 c63eab10ae17 about a minute ago 597MB nginx v cfeb40a7b94d 3 hours ago 716MB nginx v2 e7ab54678277 26 minutes ago 453MB
③、优化3:多阶段构建(使用FROM命令生成多个镜像,将指定的镜像做为其他镜像的基础镜像环
境来构建)。
[root@docker nginx]# vim dockerfile FROM centos:7 as build #as build 用于构建的基础镜像 RUN yum -y update && yum -y install pcre-devel zlib-devel gcc gcc-c++ make &> /dev/null && yum clean all && useradd -M -s /sbin/nologin nginx &> /dev/null ADD nginx-1.12.2.tar.gz /usr/local/src WORKDIR /usr/local/src/nginx-1.12.2 RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make && make install &> /dev/null && echo "daemon off;">>/usr/local/nginx/conf/nginx.conf &> /dev/null && rm -rf /usr/local/src/nginx-1.12.2 ENV PATH /usr/local/nginx/sbin:$PATH FROM centos:7 #以上一个镜像运行的结果为基础镜像环境来构建 VOLUME ["/usr/local/nginx/html"] COPY --from=build /usr/local/nginx /usr/local/nginx EXPOSE 80 CMD nginx [root@docker nginx]# docker build -t "nginx:v3" . #构建为镜像优化3版本为nginx:v3 [root@docker nginx]# docker images #查看镜像大小 nginx v1 c63eab10ae17 about a minute ago 597MB nginx v cfeb40a7b94d 3 hours ago 716MB nginx v2 e7ab54678277 26 minutes ago 453MB nginx v3 1a79abf73ac9 19 seconds ago 208MB
注:结论:可以看到经过三次优化,镜像大小明显小了。
④、优化:4 使用更为轻量级的linux 发行版本
如debian、alpine、apt add等轻量级本版。
总结
1、docker镜像层次结构小结
①base image :基础镜像
②image:固化了一个标准运行环境,镜像本身的功能-封装一组功能性的文件,通过统一的方式,
文件格式提供出来(只读)
③container:容器层(读写)
④docker-server端
⑤呈现给docker-client(视图)
2、镜像分层简洁概述:
本从顶层到底层顺序
container 容器层
image (s) 镜像层(应用的像层——》上层镜像层)
image (s) 镜像层(依赖环境的镜像层——》下层镜像层)
base image 基础镜像层(linux发行版本操作系统rootfs)
kernel 内核层(aufs + bootfs )
3、优化dockerfile镜像
优化1:不需要输出的指令丢入/dev/null (需要确定命令执行的是正确的)
优化2:减少RUN构建
优化3:多阶段构建(使用FROM命令生成多个镜像,将指定的镜像做为其他镜像的基础镜像环境来
构建)
优化4 :使用更为轻量级的linux 发行版本



