Docker 构建文件
Dockerfile 本质上是一组指令,以简单的文本格式编写,Docker 基于这些指令来构建 Docker image。例如,它包含必须开始使用的 base image、安装软件、库、依赖项的指令、复制文件以及在应用程序环境中运行必要命令的指令。
可以将它想象成容器的“食谱”,列出所需原料和烹饪步骤,最终生成一个可直接运行的 Docker image,就像一道美味的菜肴。
阅读本章以了解 Dockerfile 以及如何构建它们来创建和运行 Docker Image。
Dockerfile 指令
Dockerfile 指令是在 Docker image 构建过程中使用的一组命令。添加到 Dockerfile 中的每个指令都会为最终运行应用程序的 container 描述一个环境和行为。
以下列出了 10 个基本的 Dockerfile 指令 及其示例,展示如何使用它们 −
| 指令 | 描述 |
|---|---|
| FROM | 指定要构建的 base image |
| RUN | 在当前 image 的新层上运行命令并提交 |
| COPY | 将主机文件系统中的文件或目录复制到 image 文件系统中 |
| WORKDIR | 设置后续指令的工作目录 |
| ENV | 设置环境变量 |
| EXPOSE | 告知 Docker 该 container 在运行时对特定网络端口感兴趣 |
| CMD | 为 Container 提供默认命令和/或参数 |
| ENTRYPOINT | 配置 container 作为可执行文件运行 |
| VOLUME | 创建指定路径的挂载点,并标记其为持有外部挂载的 volume |
| USER | 设置运行 image 时使用的用户名或 UID |
示例
让我们为一个简单的 Node.js 应用程序创建一个 Dockerfile −
# 使用官方 Node.js image 作为 base FROM node:14 # 设置工作目录 WORKDIR /app # 将 package.json 和 package-lock.json 复制到工作目录 COPY package*.json ./ # 安装依赖项 RUN npm install # 复制应用程序代码的其余部分 COPY . . # 向外部暴露 3000 端口 EXPOSE 3000 # 设置环境变量 ENV NODE_ENV=production # container 启动时运行的默认命令 CMD ["node", "index.js"]
这个 Dockerfile 为 Node.js 应用程序构建 image,设置环境,安装依赖项,暴露端口,并定义应用程序的启动方式。
如何从 Dockerfile 构建 Image?
您可以使用 Docker 的命令行界面(CLI)中的一些重要 Docker 命令从 Dockerfile 构建 Docker image。
让我们查看基于上述示例 Dockerfile 的逐步指南,使用基本 Docker 命令来构建、标记和运行 image。
构建 Docker Image
要从 Dockerfile 构建 Docker image,请使用 docker build 命令 −
$ docker build -t my-node-app:v1 .
- -t my-node-app:v1 − 要构建的 image 将具有名称 "my-node-app" 和标签 "v1"。
- . (dot) − 指定构建上下文,即包含 Dockerfile 的当前目录。
列出 Docker Images
此命令将列出系统上当前的所有 Docker images。
$ docker images
这将显示所有 images 的列表,包括它们的标签、大小和创建日期。
标记 Image
您可以使用 docker tag 命令将现有 image 标记为另一个标签或仓库名称。
$ docker tag my-node-app:v1 my-registry/my-node-app:v1
- my-node-app:v1 − image 名称和当前标签。
- my-registry/my-node-app:v1 − 新仓库名称和标签。
运行 Docker Container
要基于特定 image 运行 container,请使用 docker run 命令 −
$ docker run -p 3000:3000 my-node-app:v1
- -p 3000:3000 − 这将把主机的 3000 端口映射到 container 内部的 3000 端口(端口绑定)。
- my-node-app:v1 − 这是您要运行的 image 名称及其特定标签。
列出运行中的 Containers
要查看当前运行的 containers,您可以使用 docker ps 命令 −
$ docker ps
这将返回运行中 containers 的列表,包括它们的 ID、状态、端口和名称。
停止运行中的 Container
要停止运行中的 container,请使用 docker stop 命令后跟 container ID 或名称 −
$ docker stop <container-id or container-name>
您可以将 "<container-id or container-name>" 替换为要停止的 container 的实际 ID 或名称。
删除 Image
要从系统中删除 image,您可以使用 docker rmi 命令。该命令接受 image ID 或标签作为参数。
$ docker rmi my-node-app:v1
什么是 .dockerignore 文件?
.dockerignore 文件的功能与 .gitignore 相同,用于定义在 Docker 构建上下文中应忽略的文件和目录模式。
在 Docker 构建 image 时,它会将整个上下文目录(通过 docker build 命令指定)发送到 Docker daemon。这意味着,使用 ".dockerignore" 排除不必要的文件和目录可以加速构建并减小最终 image 的大小。
语法和用法
- 在 Docker 构建上下文的根目录中创建一个 ".dockerignore" 文件。
- 列出您希望 Docker 在构建过程中忽略的文件和目录(每行一个)。
.dockerignore 文件示例
以下是一个 Node.js 应用的 ".dockerignore" 文件示例 −
node_modules npm-debug.log Dockerfile .dockerignore .git
解释
- node_modules − 由于您希望在构建过程中使用 npm install,此设置会排除 node_modules 目录,避免将所有不需要的依赖项复制到 Docker image 中。
- npm-debug.log − 忽略 npm 调试日志,这些在 Docker image 中是不必要的。
- Dockerfile − 这可以防止实际的 Dockerfile 本身被复制到 Docker image 中。
- .dockerignore − 帮助防止 .dockerignore 文件本身被包含在构建上下文中。
- .git − 排除 .git 目录,避免复制不必要的 Git 仓库信息。
最佳实践
- 仅包含特定文件 − 只在 container 中包含构建和运行应用所需的那些文件和目录。
- 使用通配符 − 可以使用星号 (*) 和双星号 (**) 在通配符模式中匹配文件和目录。
- 保持最小化 − ".dockerignore" 文件本身应尽可能简洁,以防止意外删除文件。
Dockerfile 中 COPY 和 ADD 指令的区别
COPY 和 ADD 都用于将文件从主机复制到 Docker image 中。然而,在大多数情况下,COPY 是更优的选择;它更加透明。如果你只需要将文件从源复制到 image 中的目标位置,应该使用 COPY 指令。
ADD 具有额外功能,例如自动解压压缩文件以及从远程 URL 获取文件的能力,但这会引入潜在的意外行为和安全风险。如果你不需要这些功能,COPY 是更优的指令,有助于提高 Docker 文件的清晰度和可维护性。
结论
在本章中,我们讨论了 Dockerfile 的复杂性、它们的使用原因,以及构建 Docker image 所需的重要 Dockerfile 指令。
然后我们了解了一个创建 NodeJs Docker Image 的 Dockerfile 示例,以及用于构建和标记 image、运行 container、列出 image 和 container 等的不同命令。
最后,我们讨论了为什么在构建上下文中使用 .dockerignore 文件是必要的。你现在已经具备了从 Dockerfile 创建和构建 image 的能力。