Dockerfile 是定义镜像构建过程的脚本。掌握常用指令,你可以将任何应用打包成可复用的镜像。本文从最基础的 FROM、RUN、COPY、ADD 开始,详细讲解每个指令的语法、最佳实践和常见陷阱。
一、Dockerfile 基础概念
Dockerfile 是一个文本文件,包含一系列指令,每条指令构建镜像的一层。Docker 会按顺序执行这些指令,并缓存中间层以加速后续构建。
构建命令:
bash
docker build -t myimage:tag .
-t:指定镜像名称和标签。
.:构建上下文(当前目录),Docker 会将此目录下的文件发送给 Docker 守护进程。
二、FROM:指定基础镜像
语法:
dockerfile
FROM --platform= : AS
作用:所有 Dockerfile 必须以 FROM 开头(除了 ARG 指令)。它定义了构建起点。
最佳实践:
优先选择官方镜像,如 alpine、ubuntu、node:18-alpine。
明确指定 tag,避免 latest(不可预测)。
多阶段构建时使用 AS 命名阶段。
示例:
dockerfile
FROM alpine:3.18
FROM node:18-alpine AS builder
FROM scratch # 用于构建极简镜像
三、RUN:执行命令
语法:
dockerfile
shell 形式(默认 /bin/sh -c)
RUN
exec 形式(推荐,避免 shell 解析问题)
RUN "executable", "param1", "param2"
作用:在构建过程中运行命令,通常用于安装软件包、编译代码、设置权限等。每一条 RUN 会创建新的一层。
最佳实践:
将多个 RUN 命令合并为一条,使用 && 连接,减少镜像层数。
清理临时文件(如 apt-get clean、rm -rf /var/lib/apt/lists/*)在同一层进行,避免残留。
示例:
dockerfile
不推荐:多层
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
推荐:合并
RUN apt-get update && apt-get install -y curl
&& rm -rf /var/lib/apt/lists/*
四、COPY:复制文件
语法:
dockerfile
COPY --chown=: <源路径>... <目标路径>
COPY --chown=: "\<源路径\>",... "\<目标路径\>" # 路径含空格时使用
作用:将构建上下文中的文件/目录复制到镜像中。
特点:
源路径必须是构建上下文内的相对路径。
目标路径可以是绝对路径或相对于 WORKDIR 的相对路径。
支持通配符(*、?)。
自动创建目标路径中不存在的目录。
最佳实践:
优先使用 COPY,除非需要自动解压(ADD 的特权)。
指定 --chown 以设置正确的文件所有者,避免权限问题。
复制时注意 .dockerignore 文件,排除无用内容。
示例:
dockerfile
COPY . /app # 复制所有文件到 /app
COPY --chown=node:node package.json /app/
COPY *.txt /app/data/
五、ADD:增强版 COPY
语法:同 COPY,但额外支持:
源路径可以是 URL(自动下载)。
源路径若是 tar 压缩包(.tar、.tar.gz 等),自动解压到目标路径。
示例:
dockerfile
ADD https://example.com/file.tar.gz /tmp/ # 下载并解压
ADD app.tar.gz /usr/local/ # 自动解压
注意:
官方建议:除非需要自动解压,否则使用 COPY。因为 ADD 的 URL 下载和自动解压行为不够透明,且无法利用缓存。
从 URL 下载的文件不会被缓存(除非文件内容和 URL 完全不变),可能影响构建速度。
六、构建上下文与 .dockerignore
构建上下文:执行 docker build 时,指定路径下的所有文件都会被压缩发送给 Docker 守护进程。如果目录很大,构建会变慢。
.dockerignore:类似 .gitignore,用于排除不需要的文件,例如:
text
node_modules/
*.log
.git/
.DS_Store
七、综合示例:构建一个 Node.js 应用镜像
dockerfile
使用 Node.js 18 Alpine 作为基础镜像
FROM node:18-alpine AS builder
设置工作目录
WORKDIR /app
复制 package.json 和 package-lock.json(先复制依赖文件,利用缓存)
COPY package*.json ./
安装依赖
RUN npm ci --only=production
复制应用代码
COPY . .
多阶段构建:运行时镜像
FROM node:18-alpine
WORKDIR /app
从 builder 阶段复制依赖和代码
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app /app
暴露端口
EXPOSE 3000
启动应用
CMD "node", "server.js"
构建命令:
bash
docker build -t my-node-app .
八、常见问题与解决

九、小结
FROM 定义基础镜像,RUN 执行构建命令,COPY 和 ADD 复制文件。熟练掌握这些指令,你已经能编写大多数应用的 Dockerfile。核心优化原则:
选择合适的基础镜像(Alpine 优先)。
合并 RUN 命令以减少层数。
利用构建缓存:将变动频率低的指令前置。
使用 .dockerignore 排除无关文件。