如何编写正确高效的Dockerfile

简介: 【2月更文挑战第17天】

镜像就是一个打包文件,里面包含了应用程序还有它运行所依赖的环境,例如文件系统、环境变量、配置参数等等。

环境变量、配置参数这些东西还是比较简单的,随便用一个 manifest 清单就可以管理,真正麻烦的是文件系统。为了保证容器运行环境的一致性,镜像必须把应用程序所在操作系统的根目录,也就是 rootfs,都包含进来。


容器镜像内部并不是一个平坦的结构,而是由许多的镜像层组成的,每层都是只读不可修改的一组文件,相同的层可以在镜像之间共享,然后多个层像搭积木一样堆叠起来,再使用一种叫“Union FS 联合文件系统”的技术把它们合并在一起,就形成了容器最终看到的文件系统。


docker inspect 来查看镜像的分层信息,比如 nginx:alpine 镜像。


通过这张截图就可以看到,nginx:alpine 镜像里一共有 6 个 Layer。


比起容器、镜像来说,Dockerfile 非常普通,它就是一个纯文本,里面记录了一系列的构建指令,比如选择基础镜像、拷贝文件、运行脚本等等,每个指令都会生成一个 Layer,而 Docker 顺序执行这个文件里的所有步骤,最后就会创建出一个新的镜像出来。


首先因为构建镜像的第一条指令必须是 FROM,所以基础镜像的选择非常关键。如果关注的是镜像的安全和大小,那么一般会选择 Alpine;如果关注的是应用的运行稳定性,那么可能会选择 Ubuntu、Debian、CentOS。

FROM alpine:3.15                # 选择Alpine镜像
FROM ubuntu:bionic              # 选择Ubuntu镜像

image.gif

RUN 通常会是 Dockerfile 里最复杂的指令,会包含很多的 Shell 命令,但 Dockerfile 里一条指令只能是一行,所以有的 RUN 指令会在每行的末尾使用续行符 \,命令之间也会用 && 来连接,这样保证在逻辑上是一行,就像下面这样:

RUN apt-get update \
    && apt-get install -y \
        build-essential \
        curl \
        make \
        unzip \
    && cd /tmp \
    && curl -fSL xxx.tar.gz -o xxx.tar.gz\
    && tar xzf xxx.tar.gz \
    && cd xxx \
    && ./config \
    && make \
    && make clean

image.gif

把这些 Shell 命令集中到一个脚本文件里,用 COPY 命令拷贝进去再用 RUN 来执行:

COPY setup.sh  /tmp/                # 拷贝脚本到/tmp目录
RUN cd /tmp && chmod +x setup.sh \  # 添加执行权限
    && ./setup.sh && rm setup.sh    # 运行脚本然后再删除

image.gif

Dockerfile 里也可以做到,需要使用两个指令 ARG 和 ENV。它们区别在于 ARG 创建的变量只在镜像构建过程中可见,容器运行时不可见,而 ENV 创建的变量不仅能够在构建镜像的过程中使用,在容器运行时也能够以环境变量的形式被应用程序使用。


因为命令行“docker”是一个简单的客户端,真正的镜像构建工作是由服务器端的“Docker daemon”来完成的,所以“docker”客户端就只能把“构建上下文”目录打包上传(显示信息 Sending build context to Docker daemon ),这样服务器才能够获取本地的这些文件。


如何编写 Dockerfile 内容?

  1. 创建镜像需要编写 Dockerfile,写清楚创建镜像的步骤,每个指令都会生成一个 Layer。
  2. Dockerfile 里,第一个指令必须是 FROM,用来选择基础镜像,常用的有 Alpine、Ubuntu 等。其他常用的指令有:COPY、RUN、EXPOSE,分别是拷贝文件,运行 Shell 命令,声明服务端口号。
  3. docker build 需要用 -f 来指定 Dockerfile,如果不指定就使用当前目录下名字是“Dockerfile”的文件。
  4. docker build 需要指定“构建上下文”,其中的文件会打包上传到 Docker daemon,所以尽量不要在“构建上下文”中存放多余的文件。
  5. 创建镜像的时候应当尽量使用 -t 参数,为镜像起一个有意义的名字,方便管理。
相关文章
|
6月前
|
Shell Docker 容器
dockerfile编写和构建运行
dockerfile编写和构建运行
|
8月前
|
存储 Docker 容器
Dockerfile 语法详解:构建定制化容器镜像的基石
Docker 已经成为现代应用程序开发和部署的关键工具之一。在 Docker 的世界中,Dockerfile 是一个至关重要的文件,它定义了如何构建容器镜像的步骤和配置。
146 2
Dockerfile 语法详解:构建定制化容器镜像的基石
|
6天前
|
安全 Java Maven
编写 Dockerfile 最佳实践
编写 Dockerfile 最佳实践
|
2月前
|
存储 Unix Shell
【简化Cmake编译过程 】编写通用的bash脚本:简化和构建cmake高效自动化任务
【简化Cmake编译过程 】编写通用的bash脚本:简化和构建cmake高效自动化任务
45 0
|
5月前
|
算法 Docker Python
Python【算法中心 04】Docker镜像制作的两种方式代码内置与代码挂载(部署简单和避免修改Docker内文件的权衡)
Python【算法中心 04】Docker镜像制作的两种方式代码内置与代码挂载(部署简单和避免修改Docker内文件的权衡)
56 0
|
12月前
|
存储 编译器 开发者
5个编写高效Makefile文件的最佳实践
在软件开发过程中,Makefile是一个非常重要的工具,它可以帮助我们自动化构建、编译、测试和部署。然而,编写高效的Makefile文件并不是一件容易的事情。在本文中,我们将讨论如何编写高效的Makefile文件,以提高我们的开发效率和产品质量
115 0
|
12月前
|
Linux 网络安全 Docker
2021最简洁的docker安装流程
2021最简洁的docker安装流程
106 0
|
存储 关系型数据库 MySQL
Dockerfile命令及实践构建一个网站
dockerfile用于构建docker镜像的,部署一个用于运行你所需的容器环境。相当一个脚本,通过dockerfile自己的指令,来构建软件依赖、文件依赖、存储、 定制docker镜像的方式有两种: 手动修改容器内容,导出新的镜像 基于Dockerfile自行编写指令,基于指令流程创建镜像。
108 0
|
运维 Java 数据安全/隐私保护
DockerFile 构建过程解析 | 学习笔记
快速学习 DockerFile 构建过程解析
72 0
DockerFile 构建过程解析 | 学习笔记
|
运维 Java Linux
DockerFile 构建过程解析|学习笔记
快速学习 DockerFile 构建过程解析
58 0
DockerFile 构建过程解析|学习笔记