# 第七章 Dockerfile 指令详解

## 什么是 Dockerfile

Dockerfile 是一个文本文件，其内包含了一条条的 **指令 (Instruction)**，每一条指令构建一层，因此每一条指令的内容，就是描述该层应当如何构建。

在[第四章](https://yeasy.gitbook.io/docker_practice/di-yi-bu-fen-ru-men-pian/04_image)中，我们通过 `docker commit` 学习了镜像的构成。但是，手动 `commit` 只能作为临时修补，并不适合作为生产环境镜像的构建方式。

使用 Dockerfile 构建镜像有以下优势：

* **自动化**：可以通过 `docker build` 命令自动构建镜像。
* **可重复性**：由于 Dockerfile 是文本文件，可以确保每次构建的结果一致。
* **版本控制**：Dockerfile 可以纳入版本控制系统 (如 Git)，便于追踪变更。
* **透明性**：任何人都可以通过阅读 Dockerfile 了解镜像的构建过程。

## Dockerfile 编写哲学

在深入每个指令的细节之前，笔者想强调一个至关重要的原则：**Dockerfile 不是脚本，而是镜像的"设计图"**。这个区别决定了你如何思考每条指令的作用。

相比编写 Bash 脚本的思维（"按顺序执行这些命令"），Dockerfile 的思维应该是（"这一层镜像应该如何构建，下一层如何分层"）。这个思维转变会影响你的决策：

* **合并命令**：一个 `RUN apt-get update && apt-get install ...` 应该写在一起，而不是分开成多个 `RUN` 指令，因为它们是同一个"层"的逻辑
* **选择合适的指令**：`COPY` vs `ADD`、`CMD` vs `ENTRYPOINT` 这些选择不是随意的，而是根据镜像分层的语义来决定的
* **优化镜像大小**：最后才清理缓存、删除临时文件，让这些"瘦身"操作在同一层完成

这个章节将详细介绍各个指令。在学习指令语法时，请始终思考："这个指令为什么要以这样的方式工作？如果我是 Docker，我应该如何设计它？"

## Dockerfile 基本结构

Dockerfile 一般分为四部分：基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

### 指令详解

本章将详细讲解 Dockerfile 中的各个指令：

* [RUN 执行命令](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.1_run)
* [COPY 复制文件](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.2_copy)
* [ADD 更高级的复制文件](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.3_add)
* [CMD 容器启动命令](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.4_cmd)
* [ENTRYPOINT 入口点](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.5_entrypoint)
* [ENV 设置环境变量](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.6_env)
* [ARG 构建参数](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.7_arg)
* [VOLUME 定义匿名卷](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.8_volume)
* [EXPOSE 暴露端口](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.9_expose)
* [WORKDIR 指定工作目录](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.10_workdir)
* [USER 指定当前用户](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.11_user)
* [HEALTHCHECK 健康检查](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.12_healthcheck)
* [ONBUILD 为他人作嫁衣裳](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.13_onbuild)
* [LABEL 为镜像添加元数据](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.14_label)
* [SHELL 指令](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.15_shell)

### 高级特性

本章还将介绍 Dockerfile 的高级特性：

* [多阶段构建](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.17_multistage_builds)
* [多阶段构建实战：Laravel 应用](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.18_multistage_builds_laravel)

### 参考与最佳实践

此外，我们还将介绍 Dockerfile 的最佳实践和常见问题。

* [参考文档](https://yeasy.gitbook.io/docker_practice/di-er-bu-fen-jin-jie-pian/07_dockerfile/7.16_references)

## 使用 Dockerfile 构建镜像

构建镜像的基本命令格式为：

```bash
docker build [选项] <上下文路径/URL/->
```

例如，在 Dockerfile 所在目录执行：

```bash
docker build -t my-image:v1 .
```

更多关于 `docker build` 的用法，我们在实战中会结合具体指令进行演示。
