Dockerfile 概述

Dockerfile

一切都从 Dockerfile 开始。

Docker 通过读取 Dockerfile 中的指令来构建镜像。Dockerfile 是一个包含用于构建源代码的指令的文本文件。Dockerfile 指令语法由 Dockerfile 参考 中的规范定义。

以下是最常见的指令类型

指令描述
FROM <image>定义镜像的基础。
RUN <command>在当前镜像之上新建一层并执行任何命令,然后提交结果。RUN 也有用于运行命令的 shell 格式。
WORKDIR <directory>设置 Dockerfile 中其后任何 RUNCMDENTRYPOINTCOPYADD 指令的工作目录。
COPY <src> <dest><src> 复制新文件或目录,并将其添加到容器文件系统中路径 <dest> 处。
CMD <command>允许定义基于此镜像启动容器时运行的默认程序。每个 Dockerfile 只有一个 CMD,当存在多个时,只有最后一个 CMD 实例有效。

Dockerfile 是镜像构建的关键输入,可以根据您独特的配置促进自动化、多层镜像构建。Dockerfile 可以从简单开始,并随您的需求增长以支持更复杂的场景。

文件名

Dockerfile 的默认文件名是 Dockerfile,没有文件扩展名。使用默认名称可以运行 docker build 命令,而无需指定额外的命令行标志。

有些项目可能需要针对特定目的使用不同的 Dockerfile。常见的约定是将其命名为 <something>.Dockerfile。可以使用 docker build 命令的 --file 标志指定 Dockerfile 文件名。请参阅 docker build CLI 参考 以了解 --file 标志。

注意

我们建议为项目的主要 Dockerfile 使用默认名称 (Dockerfile)。

Docker 镜像

Docker 镜像由层组成。每个层是 Dockerfile 中一条构建指令的结果。层按顺序堆叠,每个层代表对前一层应用的更改的增量。

示例

以下是使用 Docker 构建应用的典型工作流程。

以下示例代码展示了一个使用 Flask 框架用 Python 编写的小型“Hello World”应用。

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

为了在不使用 Docker Build 的情况下交付和部署此应用,您需要确保

  • 所需的运行时依赖项已安装在服务器上
  • Python 代码已上传到服务器的文件系统
  • 服务器使用必要的参数启动您的应用

以下 Dockerfile 创建了一个容器镜像,该镜像安装了所有依赖项,并自动启动您的应用。

# syntax=docker/dockerfile:1
FROM ubuntu:22.04

# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip install flask==3.0.*

# install app
COPY hello.py /

# final configuration
ENV FLASK_APP=hello
EXPOSE 8000
CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]

以下是此 Dockerfile 的作用分解

Dockerfile 语法

添加到 Dockerfile 的第一行是 # syntax 解析器指令。虽然可选,但此指令指示 Docker 构建器在解析 Dockerfile 时使用哪种语法,并允许启用了 BuildKit 的旧版 Docker 在开始构建之前使用特定的 Dockerfile 前端解析器指令 必须出现在 Dockerfile 中的任何其他注释、空格或 Dockerfile 指令之前,并且应该是 Dockerfile 中的第一行。

# syntax=docker/dockerfile:1

提示

我们建议使用 docker/dockerfile:1,它始终指向版本 1 语法的最新发布。BuildKit 在构建之前会自动检查语法的更新,确保您使用的是最新版本。

基础镜像

语法指令后的行定义了要使用的基础镜像

FROM ubuntu:22.04

FROM 指令 将您的基础镜像设置为 Ubuntu 的 22.04 版本。所有后续指令都在此基础镜像中执行:一个 Ubuntu 环境。符号 ubuntu:22.04 遵循 Docker 镜像命名中的 名称:标签 标准。构建镜像时,使用此符号命名您的镜像。您可以通过使用 Dockerfile FROM 指令将许多公共镜像导入构建步骤中,并在项目中利用它们。

Docker Hub 包含大量可用于此目的的官方镜像。

环境设置

以下行在基础镜像内执行构建命令。

# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip

RUN 指令 在 Ubuntu 中执行一个 shell,该 shell 更新 APT 包索引并在容器中安装 Python 工具。

注释

注意 # install app dependencies 行。这是一条注释。Dockerfile 中的注释以 # 符号开头。随着 Dockerfile 的演变,注释可以帮助记录 Dockerfile 的工作原理,以便未来的读者和编辑理解,包括未来的您自己!

注意

您可能已经注意到,注释使用的符号与文件第一行的 语法指令 相同。只有当模式匹配指令并出现在 Dockerfile 的开头时,该符号才被解释为指令。否则,它将被视为注释。

安装依赖项

第二个 RUN 指令安装 Python 应用所需的 flask 依赖项。

RUN pip install flask==3.0.*

此指令的前提是 pip 已安装到构建容器中。第一个 RUN 命令安装 pip,这确保了我们可以使用该命令安装 flask Web 框架。

复制文件

下一条指令使用 COPY 指令hello.py 文件从本地构建上下文复制到镜像的根目录。

COPY hello.py /

构建上下文 是您可以在 Dockerfile 指令(例如 COPYADD)中访问的文件集合。

执行 COPY 指令后,hello.py 文件将添加到构建容器的文件系统。

设置环境变量

如果您的应用使用环境变量,您可以使用 ENV 指令 在 Docker 构建中设置环境变量。

ENV FLASK_APP=hello

这设置了一个我们稍后需要的 Linux 环境变量。本示例中使用的 Flask 框架使用此变量来启动应用。没有它,flask 就不知道在哪里找到我们的应用来运行它。

暴露的端口

EXPOSE 指令 标记我们的最终镜像有一个服务正在侦听端口 8000

EXPOSE 8000

此指令不是必需的,但它是一个很好的实践,有助于工具和团队成员理解此应用正在做什么。

启动应用

最后,CMD 指令 设置了用户启动基于此镜像的容器时运行的命令。

CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]

此命令启动侦听端口 8000 上所有地址的 flask 开发服务器。此处的示例使用 CMD 的“exec 格式”版本。也可以使用“shell 格式”

CMD flask run --host 0.0.0.0 --port 8000

这两个版本之间存在一些微妙的差异,例如它们如何捕获 SIGTERMSIGKILL 等信号。有关这些差异的更多信息,请参阅 Shell 和 exec 格式

构建

要使用 上一节 中的 Dockerfile 示例构建容器镜像,请使用 docker build 命令

$ docker build -t test:latest .

-t test:latest 选项指定镜像的名称和标签。

命令末尾的单个点 (.) 将 构建上下文 设置为当前目录。这意味着构建过程期望在执行命令的目录中找到 Dockerfile 和 hello.py 文件。如果这些文件不存在,构建将失败。

镜像构建完成后,可以使用 docker run 命令将应用作为容器运行,并指定镜像名称

$ docker run -p 127.0.0.1:8000:8000 test:latest

这将容器的端口 8000 发布到 Docker 主机上的 http://localhost:8000

提示

想要在 VS Code 中获得更好的 Dockerfile 编辑体验?请查看 Docker VS Code 扩展 (测试版),用于代码检查、代码导航和漏洞扫描。

页面选项