Dockerfile自动构建镜像

作者: Dsir 分类: Server 发布时间: 2018年04月26日 16时38分

认识Dockerfile

Dockerfile是一个文本文件,其中包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。Dockerfile 的文件名并不要求必须为 Dockerfile,而且并不要求必须位于上下文目录中,比如可以用  -f ../Dockerfile.php  参数指定某个文件作为 Dockerfile当然,一般大家习惯性的会使用默认的文件名 Dockerfile,以及会将其置于镜像构建上下文目录中。

当我们根据业务需求定制容器时,我们可以通过Dockerfile来实现,通过命令规则把我们需要的内容写好,然后分发给团队成员,再通过docker命令执行该文件来构建我们所需的容器镜像,这样就保证了每个人的容器环境是完全一致的。

Dockerfile定制镜像示例

1、建立Dockerfile

mkdir Docker

cd Docker

touch Dockerfile


2、主要用到的指令有

  • FROM 所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。而 FROM 就是指定基础镜像(如果宿主机上存在此镜像就会在应用此镜像,否则就会从Docker Hub下载置顶镜像),因此一个Dockerfile中FROM是必备的指令,并且必须是第一条指令。除了选择现有的镜像为基础镜像外,Docker还存在一个特殊的镜像,名为 scratch 这个镜像是虚拟概念,并不实际存在,它表示一个空白的镜像。如果你以 scratch 为基础镜像的话,它意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。指定的基础镜像需要有版本号,比如 centos 就有很多不同的版本。不指定版本号就永远用的 latest ,这个会一直变。因为不同版本的系统和安装的软件有兼容性问题,所以不指定版本会使 Dockerfile 变得不稳定。

           格式:FROM <images> 或 FROM <image>:<tag>

  • RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其对格式有两种:

            shell格式:RUN <命令>,就像直接在命令行输入的命令一样。

            exec格式:RUN ["可执行文件","参数1","参数2"],这更像是函数调用中的格式。

既然 RUN 就像Shell脚本一样可以执行命令,那么是否就可以像Shell脚本一样把每一个命令对应一个 RUN 呢?比如这样:

FROM centos:centos7

RUN apt-get update

RUN apt-get install -y gcc libc6-dev make


之前说过,Dockerfile中每一个指令都会建立一层,RUN 也不例外。每天一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。

而上面这种写法,创建了2层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进镜像里,比如编译环境、更新软件等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。这是很多初学Docker的人常犯的错误。

正确写法应该使这样:

# 构建centos7基础镜像
FROM centos:centos7

# 安装构建所需软件
RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && apt-get purge -y --auto-remove $buildDeps


首先,之前所有命令都只是一个目的,就是编译、安装某个可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里 没有使用很多个 RUN 一一对应不同的命令,而是仅仅使用 RUN 指令,并用 && 将各个所需命令串联起来,将之前的 2 层,简化为 1 层,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层如何构建。并且这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以及每一层行首 # 进行注释格式。良好的格式,会让维护、排障更容易。

此外,还可以看到这一组命令最后添加了清理工作的命令,删除了为了编译构建所需的软件,清理了所有下载、展开的文件,并且还清理了 apt 缓存文件。这是很重要的一步,我们之前说过,镜像是多层存储,每一层的东西并不会在下一层删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层添加真正需要添加的东西,任何无关的东西都应该清理掉。

3、构建镜像

截图.png

从命令的输入结果中,我们可以清晰的看到 build Dockerfile 的构建过程。在 step 2 中,如同我们之前所说的那样,RUN 指令启动了一个容器 的 22277ad0f879,执行了所要求的命令,随后删除了所用到的这个容器 22277ad0f879 ,并最后提交了一层 f2f74ea7769b 。如果每条命令一个 RUN ,在 build Dockerfile 时就会各自产生一个容器,执行完成之后再删除,想一想就很害怕...

总结

本篇文章主要介绍如何通过Dockerfile来构建容器镜像,但几乎所有的容器都是这样的结构,多尝试几次,多报一些错就能融会贯通了。另外Dockerfile中还有一些其他指令,大家可以参考Docker中文文档


如果觉得我的文章对您有用,请随意打赏、分享。您的支持将鼓励我继续创作!

微博分享
1条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注