一、核心概念
-
Dockerfile
定义镜像构建步骤的文本文件,包含一系列指令和配置,用于自动化创建镜像。
-
镜像层(Layer)
Docker 镜像由多层只读层叠加而成,每个指令(如
RUN
、COPY
)会生成一个新的层。层可缓存,加速重复构建。 -
构建上下文(Build Context)
发送给 Docker 守护进程的文件集合,用于构建镜像。默认是 Dockerfile 所在目录。
二、Dockerfile 基础指令
1. FROM
-
用途 :指定基础镜像,所有 Dockerfile 必须以
FROM
开头。 -
示例 :
dockerfileFROM nginx:latest # 基于官方 Nginx 镜像
2. RUN
-
用途:执行 shell 命令,生成新的镜像层。
-
示例 :
dockerfileRUN apt-get update && apt-get install -y curl # 安装依赖
3. COPY
-
用途:将本地文件或目录复制到镜像中。
-
示例 :
dockerfileCOPY ./src /app/src # 复制宿主机的 src 目录到镜像的 /app/src
4. ADD
-
用途 :类似
COPY
,但支持自动解压压缩文件(如.tar.gz
)和远程 URL。 -
示例 :
dockerfileADD https://example.com/file.tar.gz /app/ # 下载并解压文件
5. WORKDIR
-
用途 :设置工作目录,后续指令(如
RUN
、COPY
)将在此目录执行。 -
示例 :
dockerfileWORKDIR /app # 切换到 /app 目录
6. CMD
-
用途:定义容器启动时默认执行的命令(可被覆盖)。
-
示例 :
dockerfileCMD ["node", "server.js"] # 启动 Node.js 服务
7. ENTRYPOINT
-
用途 :定义容器启动时执行的命令(不可被覆盖,但可通过
--entrypoint
修改)。 -
示例 :
dockerfileENTRYPOINT ["python", "app.py"] # 固定执行 Python 脚本
8. EXPOSE
-
用途 :声明容器监听的端口(仅文档作用,实际需通过
-p
映射)。 -
示例 :
dockerfileEXPOSE 8080 # 声明应用使用 8080 端口
9. ENV
-
用途:设置环境变量。
-
示例 :
dockerfileENV API_URL=https://api.example.com # 定义 API 地址
三、docker build
命令详解
基本语法:
bash
docker build [OPTIONS] PATH | URL | -
常用选项:
-t, --tag
:指定镜像名称和标签(格式:name:tag
)。-f, --file
:指定 Dockerfile 路径(默认为PATH/Dockerfile
)。--no-cache
:禁用缓存,强制重新执行所有步骤。--build-arg
:传递构建参数(需在 Dockerfile 中用ARG
定义)。
示例:
-
构建并标记镜像:
bashdocker build -t my_app:v1 . # 当前目录为构建上下文
-
指定 Dockerfile 路径:
bashdocker build -t my_app:v1 -f Dockerfile.prod .
-
传递构建参数:
bashdocker build --build-arg ENV=prod -t my_app:prod .
四、构建流程示例
目标:构建一个 Node.js 应用镜像。
步骤 1:创建项目结构
bash
mkdir -p node-app/{src,public}
touch node-app/server.js node-app/package.json
步骤 2:编写 Dockerfile
dockerfile
# 使用官方 Node.js 18 镜像作为基础
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm install
# 复制应用源码
COPY . .
# 暴露端口 3000
EXPOSE 3000
# 启动应用
CMD ["node", "server.js"]
步骤 3:构建镜像
bash
docker build -t node-app:latest .
步骤 4:运行容器
bash
docker run -p 3000:3000 node-app:latest
五、最佳实践
-
减少镜像层数
合并相关指令(如
RUN apt-get update && apt-get install -y ...
),避免生成过多无用层。 -
使用
.dockerignore
排除构建上下文中的无关文件(如
node_modules
、.git
),减少传输大小。plaintext.git node_modules *.log
-
多阶段构建(Multi-Stage Builds)
分离构建环境和运行环境,减小最终镜像体积。
dockerfile# 阶段 1:构建应用 FROM node:18 AS builder WORKDIR /app COPY . . RUN npm install && npm run build # 阶段 2:运行应用 FROM node:18-alpine WORKDIR /app COPY --from=builder /app/dist ./dist CMD ["node", "dist/server.js"]
-
使用轻量级基础镜像
优先选择 Alpine Linux 或
distroless
镜像,减少镜像体积和安全风险。dockerfileFROM node:18-alpine # 体积约 100MB,远小于默认的 Ubuntu 镜像
-
避免以 root 用户运行
创建非 root 用户,提升容器安全性。
dockerfileRUN adduser -D app_user USER app_user
六、调试与优化
-
查看构建日志
bashdocker build --progress=plain -t my_app:debug . # 显示详细日志
-
跳过缓存
bashdocker build --no-cache -t my_app:nocache .
-
分析镜像层
bashdocker history my_app:latest # 查看各层大小和命令
-
扫描镜像漏洞
使用
docker scan
或第三方工具(如 Trivy)检查安全风险。bashdocker scan my_app:latest
七、常见问题
-
构建失败:文件未找到
- 原因:
COPY
或ADD
指令路径错误。 - 解决:检查文件是否在构建上下文中,使用绝对路径或正确相对路径。
- 原因:
-
权限拒绝(Permission Denied)
- 原因:容器内进程以非 root 用户运行,但文件权限不足。
- 解决:在 Dockerfile 中使用
RUN chown
修改文件所有者。
-
缓存未生效
- 原因:构建上下文文件变更导致缓存失效。
- 解决:尽量保持静态文件(如依赖包)不变,或合理拆分指令。
-
端口无法访问
- 原因:未通过
-p
映射端口。 - 解决:运行容器时添加
-p 主机端口:容器端口
,如docker run -p 8080:80 nginx
。
- 原因:未通过
八、总结
- Dockerfile 是镜像构建的核心,需合理设计指令顺序和层结构。
docker build
命令通过参数控制镜像名称、上下文和缓存策略。- 遵循最佳实践(如多阶段构建、轻量级镜像)可显著优化构建效率和安全性。