如何使用dockerfile定制镜像

  • DockerFile的使用及其概念
  • 尝试使用DockerFile定制一个镜像
  • CMD 容器启动命令
  • ENTRYPOINT入口点
  • ENV 设置环境变量
  • ARG 构建参数
  • VOLUME定义匿名卷
  • EXPOST 声明端口
  • WORKDIR 指定工作目录
  • USER 指定当前用户
  • HEALTHCHECK 健康检查
  • ONBUILD 指令
  • DockerFile 构建的几种方式
  • 全部放入一个DockerFile
  • 分散多个DockerFile
  • 多阶段构建(Docker 17.05之后推荐的构建方式)


DockerFile的使用及其概念

注:本文基于《Docker-从入门到实践》的学习

尝试使用DockerFile定制一个镜像

接着在上篇的基础上学习其他的指令。

CMD 容器启动命令

之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程
既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。
CMD 指令就是用于指定默认的容器主进程的启动命令的。

CMD 命令和RUN命令的相似,也是两种方式,

  • CMD 命令的方式
  • CMD 可执行文件 参数....的方式进行执行
    需要注意的是,里面的参数是需要双引号括住,不能用单引号。

注:RUN 和 CMD 指令的区别是,RUN是参与容器的构建的,而CMD只是指启动时运行,构建时并不执行

ENTRYPOINT入口点

ENTRYPOINT 的格式和 RUN 指令格式是一样的。
ENTRYPOINT 的目的和 CMD 一样,都是在指定容器启动程序及参数。
ENTRYPOINT 在运行时也可以替代,不过比 CMD 要略显繁琐,需要通过 docker run 的参数 --entrypoint 来指定。

对比:

  • CMD 指令虽然可以启动时执行,但是无法指定参数,要么就是完全覆盖了CMD 的指令。
  • ENTRYPOINT 当存在 ENTRYPOINT 后, CMD 的内容将会作为参数传给ENTRYPOINT。

ENV 设置环境变量

这个指令就是设置环境变量,无论是后面的其它指令,如 RUN ,还是运行时的应用,都可以直接使用这里定义的环境变量

  • EVN key value的形式设置
  • EVN key1=value1 key2=value2

ARG 构建参数

构建参数和 ENV 的效果一样,都是设置环境变量。

ARG  参数名[=默认值]

所不同的是, ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。
Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令docker build 中用 --build-arg 参数名=值 来覆盖

VOLUME定义匿名卷

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

  • VOLUME 路径
  • VOLUME ["路径1","路径2"....]

EXPOST 声明端口

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
要将 EXPOSE 和在运行时使用 -p <宿主端口>:<容器端口> 区分开来。 -p ,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

WORKDIR 指定工作目录

使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改
为指定的目录,如该目录不存在, WORKDIR 会帮你建立目录。

WORKDIR 工作目录路径

在 Dockerfile 中,不同行的 RUN 命令的执行环境根本不同,是两个完全不同的容器。
每一个 RUN 都是启动一个容器、执行命令、然后提交存储层文件变更。假设第一层执行 RUN cd /app 执,这仅仅是当前进程的工作目录变更,一个内存上的变化而已,其结果不会造成任何文件变更。而到如果第二层的时候,启动的是一个全新的容器,跟第一层的容器更完全没关系,自然不可能继承前一层构建过程中的内存变化。
因此如果需要改变以后各层的工作目录的位置,那么应该使用 WORKDIR 指令

USER 指定当前用户

USER 指令和 WORKDIR 相似,都是改变环境状态并影响以后的层。 WORKDIR 是改变工作目
录, USER 则是改变之后层的执行 RUN , CMD 以及 ENTRYPOINT 这类命令的身份。

USER 用户名

当然,和 WORKDIR 一样, USER 只是帮助你切换到指定用户而已,这个用户必须是事先建立
好的,否则无法切换。

如果以 root 执行的脚本,在执行期间希望改变身份,比如希望以某个已经建立好的用户来
运行某个服务进程,不要使用 su 或者 sudo ,这些都需要比较麻烦的配置,而且在 TTY 缺
失的环境下经常出错。建议使用 gosu 。

HEALTHCHECK 健康检查

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12
引入的新指令。

  • HEALTHECHECK 选项 CMD 命令:设置检查容器健康状况的命令
  • HEALTHCHECK NONE:如果基础镜像有健康检查指令,这行合一屏蔽其检查指令

HEALTHCHECK 支持下列选项:
–interval=<间隔> :两次健康检查的间隔,默认为 30 秒;
–timeout=<时长> :健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
–retries=<次数> :当连续失败指定次数后,则将容器状态视为 unhealthy ,默认 3次。

CMD, ENTRYPOINT一样, HEALTHCHECK只可以出现一次,如果写了多个,只有最后一个生效。
HEALTHCHECK [选项] CMD后面的命令,格式和 ENTRYPOINT一样,分为 shell 格式,和exec 格式。命令的返回值决定了该次健康检查的成功与否: 0 :成功; 1 :失败; 2 :保留,不要使用这个值

ONBUILD 指令

ONBUILD是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行
ONBUILD 其他指令 使用场景:目前感觉是为了封装一些通用的操作命令作为基本镜像,方便日后变更和维护。
比如多个项目的以基本镜像定义镜像时,有变动只需要改动基本镜像就好,不用逐个改动。

DockerFile 构建的几种方式

全部放入一个DockerFile

一种方式是将所有的构建过程编包含在一个 Dockerfile 中,包括项目及其依赖库的编译、测试、打包等流程,这里可能会带来的一些问题:

  • Dockerfile 特别长,可维护性降低
  • 镜像层次多,镜像体积较大,部署时间变长
  • 源代码存在泄露的风险

分散多个DockerFile

另一种方式,就是我们事先在一个 Dockerfile 将项目及其依赖库编译测试打包好后,再将其拷贝到运行环境中,这种方式需要我们编写两个 Dockerfile 和一些编译脚本才能将其两个阶段自动整合起来,这种方式虽然可以很好地规避第一种方式存在的风险,但明显部署过程较复杂。

多阶段构建(Docker 17.05之后推荐的构建方式)

使用多阶段构建就可以很容易解决前面提到的问题,并且只需要编写一个 Dockerfile 。
使用多个from指令,只会以最后一个镜像作为基础,好处就是会将之前的操作完毕的文件拷贝到下一次的镜像中,这样有时候使用完一些软件后,又不需要打包进镜像,就可以用这种操作,打出来的镜像也会少很多。

以上就是基本的使用和一些概念,有些地方理解的一知半解,后面的实际操作还是需要多多练习。