Skip to content

Docker Build 概述

Docker Build 是 Docker 的核心功能之一,用于从 Dockerfile 构建容器镜像。本文将介绍 Docker Build 的基本概念、工作流程和主要特性。

目录

  1. 构建系统演进
  2. 构建流程
  3. 构建上下文
  4. 构建缓存
  5. 多平台构建
  6. 导出选项

构建系统演进

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- . < Dockerfile

2.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_output

3.3 构建上下文大小对比

项目类型无 .dockerignore有 .dockerignore减小比例
Node.js500 MB50 MB90%
Python300 MB30 MB90%
Go200 MB20 MB90%
Java1 GB100 MB90%

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 ./dist

4.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/amd64

4.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 .

下一步

基于 MIT 许可发布