大家好,本文是对 Docker 自定义镜像进行讲解,讲解如何进行构建自己的 Docker 镜像以及 Dockerfile 的操作指令。希望对大家有所帮助
镜像的定制实际上就是定制每一层所添加的配置、文件。我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile
。
Dockerfile
是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层
,因此每一条指令的内容,就是描述该层应当如何构建。
DockerFile分为四部分组成:基础镜像信、维护者信息、镜像操作指令和容器启动时执行指令。
如下步骤以构建nginx镜像为例讲解构建镜像的所使用的参数
一、镜像构建
构建所需的文件
[root@ecs dockerfile]# ll
total 6984
-rw-r--r-- 1 root root 143 Oct 13 15:07 Dockerfile
-rw-r--r-- 1 root root 7147520 Oct 13 14:45 nginx.tar
[root@ecs dockerfile]#
文件内容如下:
###########
###########
FROM centos:7 ##基础镜像
ADD nginx.tar /usr/local ##使用的tar包以及解压之后的路径
WORKDIR / ###工作目录
ENV PATH /usr/local/nginx/sbin/:$PATH ###环境变量
EXPOSE 80 ###声明端口
ENTRYPOINT ["nginx"] ##执行的命令
CMD ["-g" , "daemon off;"] ###上述命令执行所需要的参数
############
############
运行命令开始构建镜像
[root@ecs dockerfile]# docker build -t nginx:v4 .
Sending build context to Docker daemon 7.15MB
Step 1/7 : FROM centos:7
---> eeb6ee3f44bd
Step 2/7 : ADD nginx.tar /usr/local
---> Using cache
---> 4a88a896da74
Step 3/7 : WORKDIR /
---> Using cache
---> 6e8c279cc694
Step 4/7 : ENV PATH /usr/local/nginx/sbin/:$PATH
---> Using cache
---> 49a1327c8c18
Step 5/7 : EXPOSE 80
---> Using cache
---> add82ef1f24a
Step 6/7 : ENTRYPOINT ["nginx"] ###会启动容器,id为7ccec9f9eac6
---> Running in 7ccec9f9eac6
Removing intermediate container 7ccec9f9eac6
---> 13ab8a5f416c
Step 7/7 : CMD ["-g" , "daemon off;"] ######会启动容器,id为557b4c5e2b47
---> Running in 557b4c5e2b47
Removing intermediate container 557b4c5e2b47
---> 9a5f6f70e7ce
Successfully built 9a5f6f70e7ce
Successfully tagged nginx:v4
[root@ecs dockerfile]#
######################
######################
使用构建的镜像启动容器测试
[root@ecs ~]# docker run -d --name test -p 81:80 nginx:v4
cf3a492f465feae38839a7c37fd21260e874d9d1444332cbe4be7e6d7e3d3188
####运行curl命令测试镜像
[root@ecs ~]# curl 127.0.0.1:81
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@ecs ~]#
二、参数解释
- FROM 指定基础镜像
以一个镜像为基础,在其上进行定制。上面的用例就是以centos:7为基础,在其基础之上进行修改,定制nginx镜像。基础镜像是必须指定的。而 FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM是必备的指令,并且必须是第一条指令。
####
FROM centos:7
#####################
除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
FROM scratch
如果你以 scratch 为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
- RUN
RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一.
其运行格式有以下两种
1:shell格式,
RUN yum install nginx
RUN mkdir /etc/test
Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。
上面的这种写法,创建了 2 层镜像。会产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。
Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不能超过 42 层,现在是不能超过 127 层。
正确写法如下:
RUN yum install nginx \
&& mkdir /etc/test
2: exec格式,
RUN ["nginx", "-c", "daemon off;"] ###这种格式基本很少用,后面讲到exec的使用方式
- CMD
CMD命令和RUN命令很相似,格式也是一样的,有shell和exec两种格式,还多个个参数传递的功能
参数列表格式:CMD ["参数1", "参数2"...]。在指定了 ENTRYPOINT指令后,用 CMD 指定具体的参数。
ENTRYPOINT ["nginx"] ##执行的命令
CMD ["-g" , "daemon off;"] ###上述命令执行所需要的参数
注释:
Docker 不是虚拟机,容器中的应用都应该以前台执行,而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念。不能使用systemd的方式启动。
- COPY
拷贝文件到容器中,同ADD,只是不支持自动下载和自动解压
COPY ./start.sh /start.sh ###/start.sh为绝对路径
使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。
- ADD
ADD 指令和 COPY 的格式和性质基本一致。
ADD nginx.tar.gz / ###如果是url,会自动下载并解压
在 Docker 官方的 Dockerfile 最佳实践文档 中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。
ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。
- ENTERPOINT
ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。
当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令,如下:
ENTRYPOINT ["nginx"] ##执行的命令
CMD ["-g" , "daemon off;"] ###上述命令执行所需要的参数
- ENV
设置环境变量,当RUN或者CMD运行命令是,可以调用$ENV进行调用,如下:
ENV PATH /usr/local/nginx/sbin/:$PATH ###此处增加了nginx命令的环境标量,
ENTRYPOINT ["nginx"] ##此处可以直接使用nginx的命令否则只能使用/usr/local/nginx/sbin/nginx
CMD ["-g" , "daemon off;"] ###上述命令执行所需要的参数
也可以设置多个变量
ENV key1=value1 key2=value2
- EXPOSE
声明容器运行的服务端口,如下:
EXPOSE 80 443 ###只是用于声明,并不是因为这个声明而开启这个端口
这样写有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口
- ARG
在构建镜像时,指定一些参数,例如:
FROM centos:7
ARG user # ARG user=root
USER $user
###############
这时,我们在docker build时可以带上自定义参数user了,如下所示:
docker build --build-arg user=jiushini .
########################
arg与env的区别
ARG 定义的变量只会存在于镜像构建过程,启动容器后并不保留这些变量
ENV 定义的变量在启动容器后仍然保留
- WORKDIR
为RUN、CMD、ENTRYPOINT以及COPY和AND设置工作目录
使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
WORKDIR /
- LABEL
指明镜像的维护者及其联系方式
MAINTAINER 11111111118@163.com
不过,MAINTAINER并不推荐使用,更推荐使用LABEL来指定镜像作者,例如:
LABEL maintainer="jiushini.cn"
- HEATHCHECK
告诉Docker如何测试容器以检查它是否仍在工作,即健康检查,如下:
HEALTHCHECK --interval=5m --timeout=3s --retries=3 \
CMD curl -f http:/localhost/ || exit 1
其中,一些选项的说明:
--interval=DURATION (default: 30s):每隔多长时间探测一次,默认30秒
-- timeout= DURATION (default: 30s):服务响应超时时长,默认30秒
--start-period= DURATION (default: 0s):服务启动多久后开始探测,默认0秒
--retries=N (default: 3):认为检测失败几次为宕机,默认3次
一些返回值的说明:
0:容器成功是健康的,随时可以使用
1:不健康的容器无法正常工作
2:保留不使用此退出代码