写点什么

编写 Dockerfile,让你的程序一键部署

作者:技术小生
  • 2022 年 7 月 08 日
  • 本文字数:2116 字

    阅读完需:约 7 分钟

编写Dockerfile,让你的程序一键部署

容器的出现让我们的应用可以屏蔽环境,实现处处可运行。但是,应用服务修改就需要同步修改应用的镜像(Docker Image),让服务变更的成本增大。所以,在实践中一定要使用 Dockerfile 构建镜像。

Dockerfile 常用命令

  • FROM Dockerfile 除了注释第一行必须是 FROM。FROM 后面跟镜像名称,代表我们要基于哪个基础镜像构建我们的容器。

  • RUN 后面跟一个具体的命令,类似于 Linux 命令行执行命令。

  • ADD 拷贝本机文件或者远程文件到镜像内 ---不建议使用

  • COPY 拷贝本机文件到镜像内

  • USER 指定容器启动的用户

  • ENTRYPOINT 容器的启动命令

  • CMD 为 ENTRYPOINT 指令提供默认参数,也可以单独使用 CMD 指定容器启动参数

  • ENV 指定容器运行时的环境变量,格式为 key=value

  • ARG 定义外部变量,构建镜像时可以使用 build-arg = 的格式传递参数用于构建

  • EXPOSE 指定容器监听的端口,格式为 [port]/tcp 或者 [port]/udp

  • WORKDIR 为 Dockerfile 中跟在其后的所有 RUN、CMD、ENTRYPOINT、COPY 和 ADD 命令设置工作目录。


使用 Dockerfile 的好处

使用 Dockerfile 构建镜像有许多好处:

  • 易于版本管理,Dockerfile 本身就是个文件,方便存放在 Git 仓库座版本车型管理,可以方便地实现找到各个版本之间的变更历史。

  • 过程可追溯,Dockerfile 的每一行指令代表一个镜像层。根据 Dockerfile 的内容即可很明确地知道镜像完整的构建过程。

  • 屏蔽构建环境异构,使用 Dokcerfile 构建镜像无需考虑构建环境,基于相同的 Dockerfile 无论在哪里运行,构建结果都一致。


Dockerfile 编写原则

Dockerfile 有诸多好处,但使用不当也会引发许多问题。如镜像构建时间过长,甚至镜像构建失败;镜像层数过多,导致镜像文件过大。所以编写 Dockerfile 也要尽量遵循一定的原则。

  • 单一职责

由于容器的本质是进程,一个容器代表一个进程,因此不同功能的应用应该尽量拆分为不同的容器,每个容器只负责单一业务进程。

  • 提供注释

Dockerfile 也是代码,应该保持良好的编码习惯,尽量为每一行代码添加注释。让协助者可以一目了然地知道每一行代码的作用,方便扩展和使用。

  • 保持容器最小化

避免安装无用的软件包,不仅可以加快容器构建速度,还可以避免镜像体积过大。

  • 合理使用基础镜像

容器的核心是应用,因此只要基础镜像能够满足应用的运行环境即可。

  • 使用 .dockerignore 文件

忽略不需要参与构建的文件

  • 尽量使用构建缓存

Docker 构建过程中,每一条 Dockerfile 指令都会提交为一个镜像层,下一条指令都是基于上一个指令构建的。如果构建时,发现要构建的镜像层的父镜像层已经存在,并且下一条命令使用了相同的指令,即可命中构建缓存。


  • 正确设置时区

DockerHub 拉取的官方镜像多数使用的 UTC 时间。如果使用东八区,需要修改相应的时区信息。

  • 使用国内镜像源加快镜像构建速度

  • 最小化镜像层数


Dockerfile 注意事项

  • RUN 指令

RUN 指令在构建时将会生成一个新的镜像层并且执行 RUN 指令后面的内容。所以,指令尽量使用一条。

  • CMD 指令和 ENTRYPOINT 指令

这两个指令都是容器运行的命令入口。

这两个指令的相同之处,CMD 和 ENTRYPOINT 的基本使用格式分为两种。

  • 第一种为 CMD/ENTRYPOINT["command" , "param"]。这种格式是使用 Linux 的 exec 实现的, 一般称为 exec 模式,这种书写格式为 CMD/ENTRYPOINT 后面跟 json 数组,也是 Docker 推荐的使用格式。

  • 另外一种格式为 CMD/ENTRYPOINT command param ,这种格式是基于 shell 实现的, 通常称为 shell 模式。当使用 shell 模式时,Docker 会以 /bin/sh -c command 的方式执行命令。

使用 exec 模式启动容器时,容器的 1 号进程就是 CMD/ENTRYPOINT 中指定的命令,而使用 shell 模式启动容器时相当于我们把启动命令放在了 shell 进程中执行,等效于执行 /bin/sh -c "task command" 命令。因此 shell 模式启动的进程在容器中实际上并不是 1 号进程。

这两个指令的区别:

  • Dockerfile 中如果使用了 ENTRYPOINT 指令,启动 Docker 容器时需要使用 --entrypoint 参数才能覆盖 Dockerfile 中的 ENTRYPOINT 指令,而使用 CMD 设置的命令则可以被 docker run 后面的参数直接覆盖。

  • ENTRYPOINT 指令可以结合 CMD 指令使用,也可以单独使用,而 CMD 指令只能单独使用。


看到这里你也许会问,我什么时候应该使用 ENTRYPOINT,什么时候使用 CMD 呢?

如果你希望你的镜像足够灵活,推荐使用 CMD 指令。如果你的镜像只执行单一的具体程序,并且不希望用户在执行 docker run 时覆盖默认程序,建议使用 ENTRYPOINT。无论使用 CMD 还是 ENTRYPOINT,都尽量使用 exec 模式。

  • ADD 指令和 COPY 指令

ADD 和 COPY 指令功能类似,都是从外部往容器内添加文件。但是 COPY 指令只支持基本的文件和文件夹拷贝功能,ADD 则支持更多文件来源类型,比如自动提取 tar 包,并且可以支持源文件为 URL 格式。

那么在日常应用中,我们应该使用哪个命令向容器里添加文件呢?你可能在想,既然 ADD 指令支持的功能更多,当然应该使用 ADD 指令了。然而事实恰恰相反,我更推荐你使用 COPY 指令,因为 COPY 指令更加透明,仅支持本地文件向容器拷贝,而且使用 COPY 指令可以更好地利用构建缓存,有效减小镜像体积。

  • WORKDIR 指令

为了使构建过程更加清晰明了,推荐使用 WORKDIR 来指定容器的工作路径,应该尽量避免使用 RUN cd /work/path && do some work 这样的指令。

发布于: 刚刚阅读数: 3
用户头像

技术小生

关注

还未添加个人签名 2019.10.08 加入

还未添加个人简介

评论

发布
暂无评论
编写Dockerfile,让你的程序一键部署_Dockerfile_技术小生_InfoQ写作社区