Dockerfile 概述
Dockerfile
一切始于Dockerfile。
Docker通过读取Dockerfile中的指令来构建镜像。Dockerfile是一个文本文件,其中包含构建源代码的指令。Dockerfile指令语法由Dockerfile参考中的规范参考定义。
以下是最常见的指令类型
指令 | 描述 |
---|---|
FROM <image> | 定义镜像的基础。 |
RUN <command> | 在当前镜像之上新的一层执行任何命令,并提交结果。RUN 也有一种shell形式来运行命令。 |
WORKDIR <directory> | 设置Dockerfile中其后的任何RUN 、CMD 、ENTRYPOINT 、COPY 和ADD 指令的工作目录。 |
COPY <src> <dest> | 复制来自<src> 的新文件或目录,并将它们添加到容器文件系统中的路径<dest> 。 |
CMD <command> | 允许您定义基于此镜像启动容器后运行的默认程序。每个Dockerfile只有一个CMD ,当存在多个CMD 时,只有最后一个CMD 实例会被尊重。 |
Dockerfile是镜像构建的关键输入,可以根据您的独特配置促进自动化的多层镜像构建。Dockerfile可以从简单开始,并随着您的需求增长以支持更复杂的场景。
文件名
Dockerfile的默认文件名是Dockerfile
,没有文件扩展名。使用默认名称允许您运行docker build
命令而无需指定其他命令标志。
某些项目可能需要针对特定目的使用不同的Dockerfile。一个常见的约定是将这些文件命名为<something>.Dockerfile
。您可以使用docker build
命令的--file
标志指定Dockerfile文件名。请参阅docker build
CLI参考以了解--file
标志。
注意
我们建议为项目的primary Dockerfile使用默认值 (
Dockerfile
)。
Docker镜像
Docker镜像由多层组成。每一层都是Dockerfile中构建指令的结果。各层按顺序堆叠,每一层都是表示应用于前一层的更改的增量。
示例
以下是使用Docker构建应用程序的典型工作流程。
以下示例代码展示了一个用Python编写的使用Flask框架的小型“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 镜像命名的 name:tag
标准。构建镜像时,使用此表示法为镜像命名。您可以利用许多公共镜像在您的项目中,通过在 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 指令(如 COPY
和 ADD
)中访问的文件集。
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"]
此命令启动 Flask 开发服务器,在端口 8000
上的所有地址上侦听。此处的示例使用 CMD
的“exec 形式”版本。也可以使用“shell 形式”。
CMD flask run --host 0.0.0.0 --port 8000
这两个版本之间存在细微差别,例如它们捕获 SIGTERM
和 SIGKILL
等信号的方式。有关这些差异的更多信息,请参阅 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 主机的 https://127.0.0.1:8000
。