Skip to content

Docker 镜像构建

本章将介绍如何使用 Dockerfile 构建自定义 Docker 镜像,包括构建流程、多阶段构建和优化技巧。

镜像构建基础

docker build 命令

bash
# 基本构建
docker build -t myapp:v1.0 .

# 指定 Dockerfile 路径
docker build -t myapp:v1.0 -f Dockerfile.prod .

# 不使用缓存构建
docker build --no-cache -t myapp:v1.0 .

# 构建时传递参数
docker build --build-arg VERSION=1.0 -t myapp:v1.0 .

构建上下文

. 表示构建上下文目录,Docker 会将该目录下的所有文件发送给 Docker Daemon。

使用 .dockerignore 排除不需要的文件:

# .dockerignore
node_modules
.git
*.md
.env
dist

构建实例

Node.js 应用

dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Python 应用

dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]

Go 应用

dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o main .

FROM alpine:3.19
COPY --from=builder /app/main /main
EXPOSE 8080
CMD ["/main"]

Java 应用

dockerfile
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

FROM eclipse-temurin:21-jre-alpine
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]

多阶段构建

多阶段构建可以显著减小最终镜像体积,将构建环境和运行环境分离:

dockerfile
# 阶段一:构建
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 阶段二:运行
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

对比效果:

构建方式镜像大小
单阶段(包含 Node.js)~1.2 GB
多阶段(仅 Nginx + 静态文件)~30 MB

镜像优化技巧

1. 选择合适的基础镜像

dockerfile
# ❌ 完整镜像(约 900MB)
FROM node:20

# ✅ Alpine 版本(约 130MB)
FROM node:20-alpine

# ✅ Slim 版本(约 200MB)
FROM node:20-slim

2. 合并 RUN 指令减少层数

dockerfile
# ❌ 多个 RUN 指令,产生多个层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# ✅ 合并为一个 RUN 指令
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

3. 利用构建缓存

将变化频率低的指令放在前面:

dockerfile
FROM node:20-alpine
WORKDIR /app

# 先复制依赖文件(变化少)
COPY package*.json ./
RUN npm ci

# 再复制源代码(变化多)
COPY . .
RUN npm run build

4. 使用非 root 用户

dockerfile
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci

# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

CMD ["node", "server.js"]

构建缓存管理

bash
# 查看构建缓存
docker builder prune --all

# 清理构建缓存
docker builder prune

# 使用 BuildKit 构建(更高效的缓存)
DOCKER_BUILDKIT=1 docker build -t myapp .

镜像标签管理

bash
# 构建时打标签
docker build -t myapp:v1.0 -t myapp:latest .

# 给已有镜像打标签
docker tag myapp:v1.0 myregistry.com/myapp:v1.0

# 推送到仓库
docker push myregistry.com/myapp:v1.0

本章小结

镜像构建是 Docker 的核心技能之一。通过合理编写 Dockerfile、使用多阶段构建和优化技巧,可以构建出体积小、安全性高、构建速度快的镜像。

关键要点:

  • 使用 .dockerignore 排除不必要的文件
  • 多阶段构建分离构建环境和运行环境
  • 选择 Alpine 或 Slim 基础镜像减小体积
  • 合理利用构建缓存加速构建
  • 使用非 root 用户提升安全性

延伸阅读