Docker性能优化
嘿!长安来教你榨干Docker的性能!让你的容器快如闪电!⚡
🎯 优化目标
- 镜像更小:减少存储和传输时间
- 构建更快:缩短开发周期
- 启动更快:快速响应
- 运行更快:提高吞吐量
📦 镜像优化
1. 选择合适的基础镜像
# ❌ 不好:太大
FROM ubuntu:22.04 # 77MB
RUN apt-get update && apt-get install -y python3
# ✅ 好:使用官方Python镜像
FROM python:3.11-slim # 125MB,包含Python
# ✅ 更好:使用Alpine
FROM python:3.11-alpine # 50MB,最小化
对比:
| 基础镜像 | 大小 | 特点 |
|---|---|---|
| ubuntu:22.04 | 77MB | 完整系统 |
| python:3.11 | 1GB | 完整工具链 |
| python:3.11-slim | 125MB | 精简版 |
| python:3.11-alpine | 50MB | 最小化 |
| scratch | 0MB | 空镜像 |
💡 长安建议:开发用完整版,生产用slim或alpine
2. 减少镜像层数
# ❌ 不好:多层
FROM python:3.11-slim
RUN apt-get update
RUN apt-get install -y gcc
RUN apt-get install -y make
RUN apt-get clean
# ✅ 好:合并成一层
FROM python:3.11-slim
RUN apt-get update && \
apt-get install -y gcc make && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
3. 利用构建缓存
# ✅ 好:先复制依赖文件
FROM node:18-alpine
WORKDIR /app
# 1. 先复制依赖文件
COPY package*.json ./
RUN npm install # 依赖不变时,这层会被缓存
# 2. 再复制源代码
COPY . . # 代码改了,只重新执行这一层
RUN npm run build
效果:
# 第一次构建:2分钟
docker build -t myapp .
# 代码改了,再次构建:10秒(利用缓存)
docker build -t myapp .
4. 使用.dockerignore
# .dockerignore
node_modules
npm-debug.log
.git
.env
*.md
.DS_Store
dist
build
coverage
.vscode
.idea
效果:
# 没有.dockerignore
COPY . . # 复制1GB文件,耗时30秒
# 有.dockerignore
COPY . . # 复制50MB文件,耗时2秒
5. 多阶段构建
# 阶段1:构建
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 阶段2:运行(只复制必要文件)
FROM nginx:alpine
COPY /app/dist /usr/share/nginx/html
# 从1.5GB降到25MB!
6. 清理临时文件
# Node.js
RUN npm install && npm cache clean --force
# Python
RUN pip install -r requirements.txt --no-cache-dir
# Apt
RUN apt-get update && \
apt-get install -y package && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Alpine
RUN apk add --no-cache package
🚀 构建优化
1. 使用BuildKit
# 启用BuildKit(更快的构建引擎)
export DOCKER_BUILDKIT=1
# 或者在构建时
DOCKER_BUILDKIT=1 docker build -t myapp .
好处:
- 并行构建
- 更好的缓存
- 跳过未使用的阶段
2. 使用缓存挂载
# Python
RUN \
pip install -r requirements.txt
# Go
RUN \
go mod download
# Node.js
RUN \
npm install
效果:依赖包缓存在宿主机,不用每次重新下载
3. 并行构建
FROM alpine AS base
RUN apk add --no-cache ca-certificates
# 可以并行构建
FROM base AS build1
RUN some-long-operation-1
FROM base AS build2
RUN some-long-operation-2
# 最终阶段
FROM base
COPY /output1 /
COPY /output2 /
4. 使用本地registry缓存
# 启动本地registry
docker run -d -p 5000:5000 registry:2
# 配置镜像加速器
{
"registry-mirrors": [
"http://localhost:5000"
]
}
⚡ 运行时优化
1. 资源限制
# 限制内存
docker run -m 512m my-app
# 限制CPU
docker run --cpus="1.5" my-app
# 限制CPU份额
docker run --cpu-shares=512 my-app
# 综合限制
docker run \
-m 1g \
--cpus="2" \
--memory-swap="2g" \
my-app
docker-compose.yml:
services:
app:
image: my-app
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
2. 使用host网络(性能最好)
# 默认bridge网络
docker run -p 8080:8080 my-app # 有NAT开销
# host网络(无NAT)
docker run --network host my-app # 性能最好,但失去隔离
适用场景:
- 对性能要求极高
- 不关心网络隔离
- 大量网络IO
3. 优化日志
# 限制日志大小
docker run \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
my-app
4. 使用volume而不是bind mount
# ❌ 慢:bind mount(尤其在Mac/Windows)
docker run -v /host/path:/container/path my-app
# ✅ 快:volume
docker run -v my-volume:/data my-app
性能对比(Mac/Windows):
- Volume:100%
- Bind Mount:30%-50%
5. 调整ulimit
docker run \
--ulimit nofile=65536:65536 \
--ulimit nproc=4096:4096 \
my-app
🎨 应用层面优化
1. Node.js优化
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
# 使用npm ci而不是npm install(更快)
RUN npm ci --only=production
COPY . .
RUN npm run build
FROM node:18-alpine
WORKDIR /app
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
# 生产模式
ENV NODE_ENV=production
# 使用非root用户
USER node
CMD ["node", "dist/index.js"]
package.json优化:
{
"scripts": {
"start": "node --max-old-space-size=512 dist/index.js"
}
}
2. Python优化
FROM python:3.11-slim AS builder
WORKDIR /app
# 安装依赖
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
# 复制Python包
COPY /root/.local /root/.local
COPY . .
# 环境变量优化
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH=/root/.local/bin:$PATH
CMD ["gunicorn", "--workers", "4", "--bind", "0.0.0.0:8000", "app:app"]
3. Go优化
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build \
-ldflags="-w -s" \ # 减小二进制大小
-o main .
FROM scratch
COPY /app/main /main
COPY /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
CMD ["/main"]
# 最终镜像:10MB
🔍 监控和分析
1. 分析镜像层
# 查看镜像历史
docker history my-app
# 分析镜像层大小
docker history my-app --no-trunc --format "{{.Size}}\t{{.CreatedBy}}"
2. 使用dive工具
# 安装dive
brew install dive
# 分析镜像
dive my-app
dive会显示:
- 每层的大小
- 每层的内容
- 浪费的空间
3. 查看容器资源使用
# 实时监控
docker stats
# 查看容器进程
docker top my-app
# 查看容器详情
docker inspect my-app
💡 性能测试
镜像大小对比
#!/bin/bash
echo "测试不同优化级别的镜像大小"
# 未优化
docker build -f Dockerfile.normal -t test:normal .
echo "未优化: $(docker images test:normal --format '{{.Size}}')"
# 使用alpine
docker build -f Dockerfile.alpine -t test:alpine .
echo "Alpine: $(docker images test:alpine --format '{{.Size}}')"
# 多阶段构建
docker build -f Dockerfile.multi -t test:multi .
echo "多阶段: $(docker images test:multi --format '{{.Size}}')"
启动时间对比
#!/bin/bash
echo "测试容器启动时间"
for i in {1..10}; do
start=$(date +%s%N)
docker run --rm my-app echo "ready"
end=$(date +%s%N)
duration=$((($end - $start) / 1000000))
echo "第${i}次: ${duration}ms"
done
📊 优化效果对比
长安给你做了个对比测试:
| 优化项 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 镜像大小 | 1.2GB | 150MB | 87% |
| 构建时间 | 5分钟 | 30秒 | 90% |
| 启动时间 | 10秒 | 2秒 | 80% |
| 内存占用 | 500MB | 200MB | 60% |
| 响应时间 | 100ms | 50ms | 50% |
💡 优化检查清单
镜像优化
- [ ] 使用alpine或slim基础镜像
- [ ] 使用多阶段构建
- [ ] 合并RUN指令
- [ ] 创建.dockerignore文件
- [ ] 清理构建缓存和临时文件
- [ ] 使用明确的版本号
构建优化
- [ ] 启用BuildKit
- [ ] 利用构建缓存
- [ ] 先复制依赖文件,再复制代码
- [ ] 使用缓存挂载
运行优化
- [ ] 设置资源限制
- [ ] 配置重启策略
- [ ] 限制日志大小
- [ ] 使用volume而非bind mount
- [ ] 使用非root用户
应用优化
- [ ] 生产模式配置
- [ ] 合理的并发设置
- [ ] 启用应用级缓存
- [ ] 健康检查配置
🚀 终极优化示例
Dockerfile:
# 构建参数
ARG NODE_VERSION=18
# 阶段1:依赖
FROM node:${NODE_VERSION}-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN \
npm ci --only=production
# 阶段2:构建
FROM node:${NODE_VERSION}-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN \
npm ci
COPY . .
RUN npm run build
# 阶段3:运行
FROM node:${NODE_VERSION}-alpine
WORKDIR /app
# 安全:使用非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 只复制必要文件
COPY /app/node_modules ./node_modules
COPY /app/dist ./dist
COPY package.json ./
USER nodejs
# 环境变量
ENV NODE_ENV=production \
PORT=3000
EXPOSE 3000
# 健康检查
HEALTHCHECK \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
CMD ["node", "dist/index.js"]
docker-compose.yml:
version: '3.8'
services:
app:
build:
context: .
args:
NODE_VERSION: 18
restart: unless-stopped
ports:
- "3000:3000"
environment:
NODE_ENV: production
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health')"]
interval: 30s
timeout: 3s
retries: 3
💡 小结
今天长安教你榨干Docker性能:
优化方向
- 镜像优化:减小体积,加快传输
- 构建优化:利用缓存,并行构建
- 运行优化:资源限制,网络优化
- 应用优化:生产配置,健康检查
关键技巧
- 使用alpine基础镜像
- 多阶段构建
- BuildKit + 缓存挂载
- 资源限制
- 日志管理
检查清单
使用上面的优化检查清单,逐项检查你的Docker配置!
🚀 下一步
性能优化学完了!下一章长安总结 Docker最佳实践,让你成为Docker专家!
💬 长安的优化心得:
优化是个持续的过程,不要一开始就追求完美。
我的经验是:
- 先让功能跑起来
- 再逐步优化
- 用数据说话,不要瞎优化
记住:过早优化是万恶之源!
但该优化的时候也别偷懒,镜像1GB和100MB,差别是巨大的!
下一章见!💪
