dockerfile原理、创建及优化

一、基于Dockerfile创建

Dockerfile是由一组指令组成的文件 ,用来写镜像的
Dockerfile结构四部分
●基础镜像信息
●维护者信息
●镜像操作指令
●容器启动时执行指令 (cmd/ENTRYPOINT)
Dockerfile每行支持一条指令,每条指令可携带多个参数(支持&&),支持使用以“#“号开头的注释
(jason文件不支持#注释)

二、Dockerfile操作指令

指令含义
FROM镜像指定新镜像所基于的镜像,第一条指令必须为FROM指令,每创建一个镜像就需要一条FROM指l令
①开启一个新的镜像②必须写的一行指令
MAINTAINER名字说明新镜像的维护人信息
RUN命令在所基于的镜像上执行命令,并提交到新的镜像中
CMD[“要运行的程序“,”参数1,“参数2“]指定启动容器时要运行的命令或者脚本Dockerfile只能有—条CMD命令,如果指定多条则只能最后一条被执行
EXPOSE端口号指定新镜像加载到Docker时要开启的端口
ENV环境变量变量值设置一个环境变量的值,会被后面的RUN使用
ADD源文件/目录目标文件/目录将源文件复制到目标文件,源文件要与Dockerfile位于相同目录中,或者是一个URL,如果复制的是压缩包,复制进去时解压
COPY源文件/目录目标文件/目录将本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile在相同的目录中
vOLUME[“目录“]在容器中创建一个挂载点
USER用户名/UID指定运行容器时的用户
WORKDIR路径为后续的RUN、CMD、ENTRYPOINT指定工作目录
ONBUILD命令指定所生成的镜像作为一个基础镜像时所要运行的命令
HEALTHCHECK健康检查

1.FROM

格式为 FROM 或FROM :。
第一条指令必须为 FROM 指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令(每个镜像一次)。

2 MAINTAINER

格式为 MAINTAINER ,指定维护者信息。

3 RUN

格式为 RUN 或 RUN [“executable”, “param1”, “param2”]。
前者将在 shell 终端中运行命令,即 /bin/sh -c;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", “-c”, “echo hello”]。
每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。

4 CMD

支持三种格式
CMD [“executable”,“param1”,“param2”] 使用 exec 执行,推荐方式;
CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;
CMD [“param1”,“param2”] 提供给 ENTRYPOINT 的默认参数;
指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。
如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令。

CMD 与entrypoint:区别

都是容器启动时要加载的命令/启动程序exec模式与shell模式
exec:容器加载时使用的启动的第一个任务进程
shell:容器加载时使用的第一个bash ( /bin/bash /bin/sh /bin/init)

[root@localhost ~]# mkdir test
[root@localhost ~]# cd test
[root@localhost test]# docker pull centos:7
[root@localhost ~]# cd test
[root@localhost test]# mkdir test01
[root@localhost test]# cd test01
[root@localhost test01]# vim dockerfile

在这里插入图片描述

[root@localhost test01]# docker build -t centos:v1 .

在这里插入图片描述

[root@localhost test01]# docker run -itd --name test centos:v1

在这里插入图片描述

[root@localhost test01]# docker run -itd --name test01 centos:v1 /bin/bash

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
EXEC不能传变量

[root@localhost test01]# echo $HOME
/root

在这里插入图片描述

[root@localhost test01]# docker build -t cengtos:v2 .
[root@localhost test01]# docker run --rm cengtos:v2                  创建执行一次后删除
$HOME                                                                显示的只是原字符

在这里插入图片描述

[root@localhost test01]# docker build -t centos:v3 .
[root@localhost test01]# docker run --rm centos:v3
/root                                                 可以看见exec不能传变量,shell模式可以

/bin/sh -c nginx shell模式
nginx exec模式
cmd是容器环境启动时默认加载的命令
entrypoint是容器环境启动时第一个加载的命令程序/脚本程序 init

小结:
如果ENTRYPOINT使用了shell模式,CMD指令会被忽略。
如果ENTRYPOINT使用了exec模式,CMD 指定的内容被追加为ENTRYPOINT 指定命令的参数。
如果ENTRYPOINT使用了exec模式,CMD也应该使用exec模式。

5 EXPOSE

格式为 EXPOSE […]。
告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P,Docker 主机会自动分配一个端口转发到指定的端口。

6 ENV

格式为 ENV 。 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。

7 ADD

格式为 ADD 。
该命令将复制指定的 到容器中的 。 其中 可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。

8 COPY

格式为 COPY 。
复制本地主机的 (为 Dockerfile 所在目录的相对路径)到容器中的 。
当使用本地目录为源目录时,推荐使用 COPY。
ENTRYPOINT
两种格式:
ENTRYPOINT [“executable”, “param1”, “param2”]
ENTRYPOINT command param1 param2(shell中执行)。
配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。
每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。

9 VOLUME

格式为 VOLUME ["/data"]。
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。

10 USER

格式为 USER daemon。
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。
当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres。要临时获取管理员权限可以使用 gosu,而不推荐 sudo。

11 WORKDIR

格式为 WORKDIR /path/to/workdir。
为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。
可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

12 ONBUILD命令

指定所生成的镜像作为一个基础镜像时所要运行的命令。
当在一个Dockerfile 文件中加上ONBUILD指令, 该指令对利用该Dockerfile构建镜像 (比如为A镜像) 不会产生实质性影响。
但是当编写一个新的Dockerfile文件来基于A镜像构建一个镜像 ( 比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行0NBUILD指令指定的指令,然后才会执行其它指令。

三、镜像层次

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
Dockerfile中的每个指令都会创建一个新的镜像层
镜像层将被缓存和复用(相当于套娃)
当Dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效
某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效
镜像层是不可变的,如果在某层中添加一个文件,然后在下—层中删除它,则镜像中依然会包含该文件.

在这里插入图片描述
这时创建时,添加命令前的语句因为没有变化直接调用原缓存,而因为添加命令影响到的语句则重新新建缓存
在这里插入图片描述

四、Docker镜像原理

1、原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS(AUFS)。
bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

Docker镜像层是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

在这里插入图片描述
Docker境像位于bootfs之上
每一层镜像的下一层成为父镜像
第一层镜像成为base image(操作系统环境镜像>容器层(町读可写),在最顶层(writable)
容器层以下都是readonly

contaier读写层
images (只读)base image
bootfs + rootfs + aufs +LxC (kernel)

2、涉及技术:

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,系统自检后会将只读改为读写,让我们可以在操作系统中进行操作

2)rootfs ( root file system)内核空间

在bootfs之上 (base images,例如centos 、 ubuntu)
包含的就是典型 Linux系统中的/dev,/proc,/bin,/etc 等标准目录和文件
rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等

3)AUFS与overlay/overlay2 . (docker高版本)

AUFS是一种联合文件系统。它使用同一个Linux
host上的多个目录,逐个堆叠起来,对外呈现出一个统一的文件系统。AUFS使用该特性,实现了Docker镜像的分层而docker使用了overlay/overlay2存储驱动来支持分层结构
overlayFs将单个Linux主机上的两个目录合并成一个目录。这些目录被称为层,
统一过程被称为联合挂载
overlay结构:
overlayfs在linux主机上只有两层,一个目录在下层,用来保存镜像(docker);
另外一个目录在上层,用来存储容器信息
1、rootfs基础镜像
2、lower下层信息(为镜像层,可读)
3、upper上层目录(容器信息,可写)
4、worker运行的工作目录(copy-on-write写时复制-》准备容器环境)
5、merged"视图层”(容器视图)

五、创建镜像

构建镜像命令(ps:可在构建镜像时指定资源限制)示例:
docker build -t nginx:test .
-t : tag 打标签
-f :指定dockerfile目录
.(点):指构建镜像时使用的环境(当前)目录,构建镜像时使用的上下文环境

构建tomcat
首先下载
jdk-8u201-linux-x64.tar.gz
apache-tomcat-9.0.16.tar.gz

[root@localhost zy]# vim dockerfile
FROM centos:7
ADD jdk-8u201-linux-x64.tar.gz /opt/                                    传入压缩包
ADD apache-tomcat-9.0.16.tar.gz /opt/
ENV JAVA_HOME /opt/jdk1.8.0_201                                         编辑环境,文件夹名即你宿主机解压后的名称
ENV CATALINA_HOME /opt/apache-tomcat-9.0.16
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
#暴露8080端口
EXPOSE 8080
CMD ["/opt/apache-tomcat-9.0.16/bin/catalina.sh","run"]            #启动时运行tomcat

如果只有一个镜像用"."表示本地 如果多个文件要用“-f”指定

[root@localhost zy]# docker build -t "tomcat:test" .                      打包并添上标签

在这里插入图片描述
在这里插入图片描述
出现以上提示证明创建并且标签添加成功

[root@localhost zy]# docker run -d -P  tomcat:test                     这里要注意后面不能加任何的cmd命令,否则会执行这一条会把文件里的cmd替代
82602deec5dbf5a1a19c30fbd20c056208478f335890b0f5ad9988487ce46b02
[root@localhost zy]# docker ps -a
CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS                                         NAMES
82602deec5db   tomcat:test   "/opt/apache-tomcat-…"   2 seconds ago   Up 2 seconds   0.0.0.0:49159->8080/tcp, :::49159->8080/tcp   jovial_tharp

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

六、镜像优化

未优化前

[root@localhost ~]# mkdir test
[root@localhost ~]# cd test
[root@localhost test]# mkdir nginx
[root@localhost test]# cd nginx/
[root@localhost nginx]# mkdir v1
[root@localhost nginx]# cd v1
[root@localhost v1]# vim dockerfile
FROM centos:7
RUN yum install -y gcc pcre pcre-devel devel zlib-devel make
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
#关闭debug日志
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/ cc/gccRUN ./configure --prefix=/usr/ local/nginx
RUN make
RUN make install
EXPOSE 80
VOLUME [ "/usr/ local/nginx/html"]
CMD [ "/usr/local/nginx/sbin/nginx" , "-g " , "daemon off; "]
[root@localhost v1]# docker build -t nginx:v1 .

在这里插入图片描述
这种情况下就有436M了

[root@localhost v1]# docker run -itd --name nginx_v1 -p 333:80 nginx:v1

在这里插入图片描述

优化1:不需要输出的指令丢入/dev/null(需要确定命令执行的是正确的)

减少不必要的缓存(丢到黑洞)删除不必要的缓存文件、磁盘文件

FROM centos:7
RUN yum install -y gcc pcre pcre-devel devel zlib-devel make &>/dev/null && yum clean all
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
#关闭debug日志
RUN sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc
RUN ./configure --prefix=/usr/local/nginx &>/dev/null
RUN make &>/dev/null
RUN make install &>/dev/null
RUN rm -rf /mnt/nginx-1.15.9
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

在这里插入图片描述

[root@localhost v2]# docker build -t nginx:v2 .

在这里插入图片描述

优化2:减少RUN构建

把RUN语句尽量合并成一句,因为每一句RUN就会多生成一个镜像层,会占用不必要的空间,所以合并RUN的指令也是我们优化考虑的方向

[root@localhost v3]# vim dockerfile
FROM centos:7
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
#关闭debug日志
RUN yum install -y gcc pcre pcre-devel devel zlib-devel make &>/dev/null && \
yum clean all \
sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && \
./configure --prefix=/usr/local/nginx &>/dev/null && \
make &>/dev/null && make install &>/dev/null && \
rm -rf /mnt/nginx-1.15.9 
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

在这里插入图片描述

[root@localhost v3]# docker images

在这里插入图片描述

优化3:多阶段构建(使用FROM命令生成多个镜像,将指定的镜像做为其他镜像的基础镜像环境来构建)

进一步压缩镜像环境的大小和镜像层

[root@localhost v4]# vim dockerfile                                                                                                    
FROM centos:7 as build
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
#关闭debug日志
RUN yum install -y gcc pcre pcre-devel devel zlib-devel make &>/dev/null && \
yum clean all && \
sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && \
./configure --prefix=/usr/local/nginx &>/dev/null && \
make &>/dev/null && make install &>/dev/null && \
rm -rf /mnt/nginx-1.15.9

FROM centos:7
EXPOSE 80
VOLUME ["/usr/local/nginx/html"]
COPY --from=build /usr/local/nginx /usr/local/nginx
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]

在这里插入图片描述

[root@localhost v4]# docker build -t nginx:v4 .

在这里插入图片描述

优化4使用更为轻量级的linux 发行版本

debian
alpine
apt add

[root@localhost v4]# docker pull nginx:1.15.9

在这里插入图片描述


版权声明:本文为yan_0916原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。