Docker Build 概述
Docker Build 是 Docker 的核心功能之一,用于从 Dockerfile 构建容器镜像。本文将介绍 Docker Build 的基本概念、工作流程和主要特性。
目录
构建系统演进
1.1 传统构建器
Docker 早期版本使用传统的构建器:
传统构建器架构:
┌─────────────────────────────────────────┐
│ Docker Client │
└─────────────┬───────────────────────────┘
│ 发送构建上下文
▼
┌─────────────────────────────────────────┐
│ Docker Daemon │
│ ┌─────────────────────────────────┐ │
│ │ Legacy Builder │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Parser │ │ Executor│ │ │
│ │ │(Dockerfile│ │(Sequential│ │ │
│ │ │ parsing)│ │ execution)│ │ │
│ │ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘特点:
- 顺序执行指令
- 有限的缓存机制
- 不支持并行构建
- 功能相对简单
1.2 BuildKit 构建器
BuildKit 是新一代构建工具,从 Docker 18.09 开始引入:
BuildKit 架构:
┌─────────────────────────────────────────┐
│ Docker Client │
└─────────────┬───────────────────────────┘
│ gRPC / LLB
▼
┌─────────────────────────────────────────┐
│ BuildKit Daemon │
│ ┌─────────────────────────────────┐ │
│ │ Frontend (Dockerfile) │ │
│ │ - 解析 Dockerfile │ │
│ │ - 生成 LLB (Low Level Builder) │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Solver (DAG Executor) │ │
│ │ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Parallel│ │ Cache │ │ │
│ │ │Execution│ │ Manager │ │ │
│ │ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ Worker (Snapshotter) │ │
│ │ - overlay2 / btrfs / zfs │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘BuildKit 优势:
| 特性 | 传统构建器 | BuildKit |
|---|---|---|
| 并发执行 | ❌ | ✅ |
| 高级缓存 | 有限 | 完整 |
| 多平台构建 | ❌ | ✅ |
| 秘密挂载 | ❌ | ✅ |
| SSH 转发 | ❌ | ✅ |
| 缓存导出 | ❌ | ✅ |
| 分布式构建 | ❌ | ✅ |
1.3 启用 BuildKit
bash
# 方法 1: 环境变量
export DOCKER_BUILDKIT=1
# 方法 2: daemon.json 配置
{
"features": {
"buildkit": true
}
}
# 方法 3: 构建命令
DOCKER_BUILDKIT=1 docker build .
# Docker 23.0+ BuildKit 默认启用构建流程
2.1 标准构建流程
构建流程:
1. 发送构建上下文
├─ 读取 .dockerignore
├─ 打包上下文目录
└─ 发送到 Docker Daemon
│
▼
2. 解析 Dockerfile
├─ 词法分析
├─ 语法分析
└─ 生成指令序列
│
▼
3. 执行构建指令
├─ FROM: 拉取基础镜像
├─ RUN: 创建容器执行命令
├─ COPY/ADD: 复制文件
├─ 提交层
└─ 重复直到完成
│
▼
4. 输出镜像
├─ 创建镜像配置
├─ 计算 digest
└─ 存储到本地2.2 BuildKit 构建流程
BuildKit 构建流程:
1. 前端解析
├─ Dockerfile 解析
├─ 生成 LLB 定义
└─ 创建 DAG(有向无环图)
│
▼
2. 求解器执行
├─ 分析依赖关系
├─ 并行执行独立节点
├─ 缓存查询
└─ 懒加载(需要时拉取)
│
▼
3. 工作器执行
├─ 执行具体操作
├─ 管理快照
└─ 内容寻址存储
│
▼
4. 导出结果
├─ 合并层
├─ 压缩
└─ 输出到目标2.3 构建命令详解
bash
# 基本构建
docker build -t myapp:1.0 .
# 指定 Dockerfile
docker build -f Dockerfile.prod -t myapp:1.0 .
# 指定构建上下文
docker build -t myapp:1.0 /path/to/context
# 从 URL 构建
docker build -t myapp:1.0 https://github.com/user/repo.git
# 从 tar 归档构建
docker build -t myapp:1.0 - < context.tar.gz
# 使用 stdin 构建
docker build -t myapp:1.0 -f- . < Dockerfile2.4 构建选项
bash
docker build [选项] 路径 | URL | -
-t, --tag list # 镜像名称和标签
-f, --file string # Dockerfile 名称
--build-arg list # 构建参数
--target string # 构建目标(多阶段)
--platform string # 目标平台
--no-cache # 不使用缓存
--pull # 始终拉取最新基础镜像
--squash # 压缩层(实验性)
--label list # 设置镜像标签
--secret stringArray # 秘密文件(BuildKit)
--ssh stringArray # SSH 代理(BuildKit)
--output stringArray # 输出目的地(BuildKit)
--cache-from string # 缓存源
--cache-to string # 缓存导出(BuildKit)
--progress string # 进度输出类型
--quiet, -q # 静默模式构建上下文
3.1 什么是构建上下文
构建上下文是传递给 Docker 引擎的文件集合,用于构建镜像:
构建上下文:
项目目录/
├── .dockerignore # 排除文件
├── Dockerfile # 构建指令
├── package.json # 依赖
├── src/ # 源代码
│ ├── index.js
│ └── utils.js
├── tests/ # 测试文件
└── docs/ # 文档
构建上下文大小 = 所有文件(除 .dockerignore 排除)3.2 优化构建上下文
dockerignore
# .dockerignore 示例
# 忽略所有
**
# 允许必要文件
!package*.json
!src/
!public/
!tsconfig.json
!vite.config.ts
# 但忽略 src 中的测试文件
src/**/*.test.ts
src/**/*.spec.ts
src/**/__tests__/
src/**/__mocks__/
# 忽略开发文件
.git
.gitignore
.env
.env.local
README.md
CHANGELOG.md
# 忽略 IDE
.vscode
.idea
*.swp
*.swo
# 忽略依赖和构建产物
node_modules
dist
build
coverage
.nyc_output3.3 构建上下文大小对比
| 项目类型 | 无 .dockerignore | 有 .dockerignore | 减小比例 |
|---|---|---|---|
| Node.js | 500 MB | 50 MB | 90% |
| Python | 300 MB | 30 MB | 90% |
| Go | 200 MB | 20 MB | 90% |
| Java | 1 GB | 100 MB | 90% |
3.4 远程构建上下文
bash
# Git 仓库
docker build https://github.com/user/repo.git
# Git 仓库特定分支
docker build https://github.com/user/repo.git#develop
# Git 仓库子目录
docker build https://github.com/user/repo.git#main:docker
# 压缩归档
docker build http://server/context.tar.gz
# 纯文本 Dockerfile
docker build -f- . <<EOF
FROM alpine
RUN echo "Hello"
EOF构建缓存
4.1 缓存机制
缓存工作原理:
Dockerfile 指令:
FROM node:18-alpine ←─ 检查镜像是否存在
WORKDIR /app ←─ 检查层缓存
COPY package*.json . ←─ 检查文件内容哈希
RUN npm ci ←─ 检查 RUN 命令和输入层
COPY . . ←─ 检查文件内容哈希
RUN npm run build ←─ 检查 RUN 命令和输入层
缓存键计算:
- 指令字符串
- 父层哈希
- 输入文件哈希(COPY/ADD)4.2 缓存优化策略
dockerfile
# 策略 1: 将不经常变化的指令放在前面
FROM node:18-alpine
WORKDIR /app
# 先复制依赖文件(变化频率低)
COPY package*.json ./
RUN npm ci --only=production
# 后复制代码(变化频率高)
COPY . .
# 策略 2: 合并相关命令
RUN apt-get update && apt-get install -y \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
# 策略 3: 使用特定版本
FROM node:18.17.1-alpine3.18
# 策略 4: 多阶段构建
FROM node:18-alpine AS builder
# ... 构建步骤
FROM node:18-alpine AS production
COPY --from=builder /app/dist ./dist4.3 BuildKit 高级缓存
dockerfile
# syntax=docker/dockerfile:1
# 使用外部缓存
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
# 使用持久缓存
RUN --mount=type=cache,target=/root/.npm \
npm ci构建命令:
bash
# 导出缓存
docker buildx build \
--cache-to type=local,dest=/tmp/.buildx-cache \
-t myapp:latest .
# 导入缓存
docker buildx build \
--cache-from type=local,src=/tmp/.buildx-cache \
-t myapp:latest .
# 推送到仓库的缓存
docker buildx build \
--cache-to type=registry,ref=myregistry/myapp:cache \
--cache-from type=registry,ref=myregistry/myapp:cache \
-t myregistry/myapp:latest \
--push .多平台构建
4.1 多平台构建概述
多平台构建:
单一 Dockerfile ──► 多平台镜像
├── linux/amd64
├── linux/arm64
├── linux/arm/v7
└── windows/amd644.2 启用 Buildx
bash
# 创建 Buildx 构建器
docker buildx create --name mybuilder --use
docker buildx inspect --bootstrap
# 查看可用平台
docker buildx ls
# 输出示例:
# NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
# mybuilder * docker-container
# mybuilder0 unix:///var/run/docker.sock running linux/amd64, linux/arm64, linux/riscv64, ...4.3 多平台构建示例
dockerfile
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o app
FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/app .
CMD ["./app"]构建命令:
bash
# 构建多平台镜像
docker buildx build \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
-t myapp:latest \
--push .
# 构建并加载到本地(单平台)
docker buildx build \
--platform linux/amd64 \
-t myapp:latest \
--load .
# 构建并导出为 OCI 目录
docker buildx build \
--platform linux/amd64,linux/arm64 \
-o type=oci,dest=./image.tar \
.4.4 平台变量
| 变量 | 说明 | 示例 |
|---|---|---|
BUILDPLATFORM | 构建平台 | linux/amd64 |
TARGETPLATFORM | 目标平台 | linux/arm64 |
TARGETOS | 目标操作系统 | linux |
TARGETARCH | 目标架构 | arm64 |
TARGETVARIANT | 目标变体 | v8 |
导出选项
5.1 输出类型
bash
# 导出到 Docker 镜像(默认)
docker buildx build -t myapp:latest --load .
# 推送到仓库
docker buildx build -t myregistry/myapp:latest --push .
# 导出为 Docker tar 归档
docker buildx build -o type=docker,dest=./image.tar .
# 导出为 OCI tar 归档
docker buildx build -o type=oci,dest=./image.tar .
# 导出为本地目录
docker buildx build -o type=local,dest=./output .
# 导出为 tar(包含所有层)
docker buildx build -o type=tar,dest=./image.tar .5.2 高级导出
bash
# 多镜像导出
docker buildx build \
--target production \
-t myapp:prod \
--output type=image,name=myapp:prod,push=true \
.
# 同时导出镜像和缓存
docker buildx build \
-t myapp:latest \
--cache-to type=inline \
--output type=image,name=myapp:latest,push-by-digest=true \
.
# 导出为 Provenance 证明
docker buildx build \
--provenance=true \
-t myapp:latest \
--push .
# 导出 SBOM
docker buildx build \
--sbom=true \
-t myapp:latest \
--push .下一步
- 深入学习 BuildKit 详解
- 了解 构建优化技巧
- 掌握 构建缓存详解
- 学习 Dockerfile 完整参考