<返回目录     Powered by claude/xia兄

第10课: 镜像优化

为什么要优化镜像?

使用轻量级基础镜像

# 对比不同基础镜像大小
FROM ubuntu:20.04        # ~72MB
FROM debian:11-slim      # ~80MB
FROM python:3.9          # ~915MB
FROM python:3.9-slim     # ~125MB
FROM python:3.9-alpine   # ~47MB
FROM alpine:3.18         # ~7MB

# 推荐使用alpine或slim版本
FROM python:3.9-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
Alpine注意事项:

多阶段构建

# 优化前:包含编译工具和源代码(1.2GB)
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
CMD ["npm", "start"]

# 优化后:只包含运行时文件(150MB)
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
CMD ["npm", "start"]

Go应用极致优化

# 从1GB优化到10MB
FROM golang:1.19 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags="-w -s" -o main .

FROM scratch
COPY --from=builder /app/main /main
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/main"]

合并RUN指令

# 优化前:每个RUN创建一层
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y curl
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*

# 优化后:合并为一层
FROM ubuntu:20.04
RUN apt-get update && \
    apt-get install -y nginx curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

清理缓存和临时文件

# Python
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt && \
    rm -rf ~/.cache/pip

# Node.js
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && \
    npm cache clean --force

# Alpine Linux
FROM alpine:3.18
RUN apk add --no-cache nginx && \
    rm -rf /var/cache/apk/*

# Ubuntu/Debian
FROM ubuntu:20.04
RUN apt-get update && \
    apt-get install -y nginx && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

优化层缓存

# 优化前:代码变化导致依赖重新安装
FROM python:3.9-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt

# 优化后:依赖文件不变时使用缓存
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

使用.dockerignore

# .dockerignore
# 版本控制
.git
.gitignore
.svn

# 依赖目录
node_modules
venv
__pycache__
*.pyc

# 构建产物
dist
build
*.egg-info

# 日志和临时文件
*.log
*.tmp
*.swp
.DS_Store

# 文档和测试
README.md
docs/
tests/
*.test.js

# IDE配置
.vscode
.idea
*.iml

# 环境变量
.env
.env.local

减少镜像层数

# 使用COPY合并多个文件
COPY package.json package-lock.json ./

# 使用通配符
COPY *.conf /etc/nginx/

# 一次性复制整个目录
COPY src/ /app/src/

使用构建参数优化

FROM python:3.9-slim

ARG DEBIAN_FRONTEND=noninteractive
ARG PIP_NO_CACHE_DIR=1
ARG PIP_DISABLE_PIP_VERSION_CHECK=1

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "app.py"]

压缩和优化文件

# 压缩静态资源
FROM node:16 AS builder
WORKDIR /app
COPY . .
RUN npm run build && \
    find dist -type f -name "*.js" -exec gzip -k {} \; && \
    find dist -type f -name "*.css" -exec gzip -k {} \;

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

分析镜像大小

# 查看镜像层大小
docker history myapp:latest

# 查看详细信息
docker history --no-trunc myapp:latest

# 使用dive工具分析镜像
docker run --rm -it \
  -v /var/run/docker.sock:/var/run/docker.sock \
  wagoodman/dive:latest myapp:latest

# 导出镜像并查看内容
docker save myapp:latest -o myapp.tar
tar -xf myapp.tar
ls -lh

实战对比

# 优化前的Python应用(915MB)
FROM python:3.9
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]

# 优化后的Python应用(50MB)
FROM python:3.9-alpine AS builder
WORKDIR /app
COPY requirements.txt .
RUN apk add --no-cache gcc musl-dev && \
    pip install --no-cache-dir -r requirements.txt

FROM python:3.9-alpine
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY app.py .
CMD ["python", "app.py"]

使用distroless镜像

# Google的distroless镜像(只包含运行时)
FROM golang:1.19 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o main .

FROM gcr.io/distroless/static-debian11
COPY --from=builder /app/main /
EXPOSE 8080
ENTRYPOINT ["/main"]

优化检查清单

最佳实践

实践练习

  1. 对比ubuntu和alpine基础镜像的大小差异
  2. 使用多阶段构建优化一个Node.js应用
  3. 使用dive工具分析镜像各层大小
  4. 编写.dockerignore排除不必要的文件
  5. 将一个1GB的镜像优化到100MB以下