Dockerfile介绍和指令

xiaohai 2020-01-05 14:58:39 989人围观 标签: Docker 
简介在使用Docker的过程中,如果我们需要自己来定制镜像那么就会用到Dockerfile。本文主要是记录Dockerfile的说明和相关指令。

  当我们需要根据某个基础镜像来定制我们镜像,我们其实可以运行的镜像中去安装我们的相关服务,然后通过docker commit来生成一个新的镜像,这种方式我们不推崇的。那么如果要定制进行,Docker提供了Dockerfile来处理。

首先我们来介绍一种简单的Dockerfile,也就是在自己的项目目录下创建一个Dockerfile文件,文件内容如下:

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

这里出现了两个指令,FROM和RUN,简单介绍下,FROM就是我们需要的基础镜像,RUN就是执行命令。有了这样一个文件后,我们就可以重新生成一个镜像,命令如下:

docker build -t nginx:v1 .

这样我们就通过Dockerfile构建了一个新的镜像,docker build命令还有很多操作方式,这里不进行一一列举了,需要深入的读者可以自行学习。下面我们将开始介绍Dockerfile的相关指令。

1、指令:FROM

【说明】:FROM指令就是指定基础镜像。在Docker Hub上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 node、openjdk、python、ruby、golang 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。

【使用】:

FROM nginx

2、指令:RUN

【说明】:执行命令,其实就是将我们平时在shell中的命令放到这里来进行执行。RUN命令可以指定很多次,每次运行一个RUN命令,镜像就会多一层,所以大家一定要注意RUN指令不能很多,否在镜像就会很臃肿,一般我们将多个执行命令写在同一个RUN指令中。Union FS是有最大层数限制的,比如AUFS,曾经是最大不得超过42层,现在是不得超过127层。还有一个需要注意,当我们在自定一个镜像过程中,会拷贝一些文件进入镜像,那么在处理完成后,最好将这些没有用的文件清理掉。
RUN指令提供了两种方式:

  • shell方式:RUN <命令>,就像直接在命令行中输入的命令一样
  • exec方式:RUN [“可执行文件”, “参数1”, “参数2”],这更像是函数调用中的格式
    【使用】:
RUN echo "hello world!" > /tmp/index.html

2、指令:COPY

【说明】:复制文件指令,就是将构建上下文的文件复制到目标位置中去,这里支持正则和指定文件的用户和用户组。这里一定要清楚,COPY指令只能复制构建上下文中的文件去目标位置,那么如果想复制其他地方的文件怎么办呢?请参考ADD命令。
【使用】:

COPY app.py /tmp/

4、指令:ADD

【说明】:ADD命令其实跟COPY命令一样,都是复制文件,基本操作一致,但是ADD还有更强大功能,那就是源目标可以是一个URL地址,如果URL地址,那么ADD会自动解压到目标位置中去,其实也就这点好处。那么一般情况下复制文件我们还是用COPY指令,如果是压缩文件(tar、gzip、bzip2等),那么我们就可以用ADD指令。
【使用】:

add nginx-1.13.1.tar.gz /tmp #压缩文件
add index.php /tmp/ #普通文件

5、指令:CMD

【说明】:启动容器命令,CMD与RUN指令用法差不多,都有两个格式。这里需要提醒一下:Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。CMD指令有多个时,只会执行最后一个。
CMD指令提供了两种方式:

  • shell方式:CMD <命令>
  • exec方式:CMD [“可执行文件”, “参数1”, “参数2”…]

shell方式执行命令

CMD echo $HOME

会将命令转换为:

CMD [ "sh", "-c", "echo $HOME" ]

在指令格式上,一般推荐使用 exec 格式,这类格式在解析时会被解析为数组,因此一定要使用双引号,而不要使用单引号。

【使用】:

CMD ["nginx", "-g", "daemon off;"]

6、指令:ENTRYPOINT

【说明】:入口点,这个命令跟CMD命令功能一致,使用方式也有两种,这个命令比CMD多的功能就是能在启动容器时指定参数,这里启动容器不是ENTRYPOINT命令后的参数,而是docker命令后指定参数。ENTRYPOINT指令有多个时,只会执行最后一个。
【使用】:

ENTRYPOINT [ "curl", "-s", "https://www.baidu.com" ]

运行:

docker run 容器名称 -i

这样的话,其实整个命令就是curl -s https://www.baidu.com -i

7、指令:ENV

【说明】:环境变量,无论是后面的其它指令,如RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
格式有两种:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

【使用】:

ENV VERSION=1.0 DEBUG=true \
    NAME="Golang App"

8、指令:ARG

【说明】:跟ENV一样,都是设置环境变量。但是跟ENV不一致的在于,ENV设置的环境变量在后续的应用中都可以使用,但是ARG设置的环境变量只能用在构建的时候,将来容器运行时是不会存在这些环境变量的。
【使用】:

ARG VERSION=1.0

9、指令:VOLUME

【说明】:匿名卷。为了防止运行时用户忘记将动态文件所保存目录挂载为卷,在Dockerfile中,我们可以事先指定某些目录挂载为匿名卷,这样在运行时如果用户不指定挂载,其应用也可以正常运行,不会向容器存储层写入大量数据。

VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

【使用】:

VOLUME /data

10、指令:EXPOSE

【说明】:声明端口。EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
【使用】:

EXPOSE 8000 5555

11、指令:WORKDIR

【说明】:指定工作目录
【使用】:

12、指令:WORKDIR

【说明】:使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令。
【使用】:

WORKDIR /tmp

13、指令:USER

【说明】:当前用户,USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。格式:USER <用户名>[:<用户组>]
【使用】:

USER mysql

14、指令:HEALTHCHECK

【说明】:HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常

  • HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
  • HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
    在 HEALTHCHECK [选项] CMD 后面的命令,格式和 ENTRYPOINT 一样,分为 shell 格式,和 exec 格式。命令的返回值决定了该次健康检查的成功与否:0:成功;1:失败;2:保留,不要使用这个值。
    【使用】:
HEALTHCHECK --interval=5s --timeout=3s \
  CMD curl -fs http://localhost/ || exit 1

设置了每 5 秒检查一次(这里为了试验所以间隔非常短,实际应该相对较长),如果健康检查命令超过 3 秒没响应就视为失败,并且使用 curl -fs http://localhost/ || exit 1 作为健康检查命令

15、指令:ONBUILD

【说明】:可以为镜像添加触发器。其参数是任意一个Dockerfile 指令。而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
【使用】:

ONBUILD COPY app.py /tmp