18 - 最佳实践
18 - 最佳实践
镜像瘦身、安全扫描、生产环境部署规范,以及 Kubernetes 入门导引。
18.1 镜像瘦身
选择最小基础镜像
| 基础镜像 | 大小 | 包含内容 |
|---|
ubuntu:22.04 | ~77MB | 完整 Ubuntu 系统 |
debian:bookworm-slim | ~75MB | 精简 Debian |
alpine:3.19 | ~7MB | 最小 Linux 发行版 |
python:3.11 | ~1GB | Python + 完整系统 |
python:3.11-slim | ~125MB | Python + 精简系统 |
python:3.11-alpine | ~50MB | Python + Alpine |
golang:1.22 | ~800MB | Go + 完整系统 |
gcr.io/distroless/static | ~2MB | 仅 CA 证书和时区数据 |
多阶段构建
# ---- 构建阶段 ----
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /server .
# ---- 最终阶段 ----
FROM gcr.io/distroless/static-debian12
COPY --from=builder /server /server
ENTRYPOINT ["/server"]
# 对比镜像大小
docker images my-app
# REPOSITORY TAG SIZE
# my-app single-stage 1.2GB ← 单阶段
# my-app multi-stage 15MB ← 多阶段
减少镜像层数
# ❌ 多个 RUN 产生多层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN rm -rf /var/lib/apt/lists/*
# ✅ 合并为一层,最后清理
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
wget \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
使用 .dockerignore
# .dockerignore
.git
node_modules
__pycache__
*.pyc
.env
*.md
Dockerfile
docker-compose*.yml
dist
build
coverage
.vscode
.idea
镜像瘦身技巧汇总
| 技巧 | 效果 | 说明 |
|---|
| 多阶段构建 | ⭐⭐⭐⭐⭐ | 分离构建和运行环境 |
| Alpine 基础镜像 | ⭐⭐⭐⭐ | 从 77MB 降到 7MB |
| Distroless 镜像 | ⭐⭐⭐⭐ | 仅包含运行时,无 shell |
| 合并 RUN 层 | ⭐⭐⭐ | 减少镜像层数 |
| 清理缓存 | ⭐⭐⭐ | 删除包管理器缓存 |
.dockerignore | ⭐⭐⭐ | 避免发送无关文件 |
--no-install-recommends | ⭐⭐ | 不安装推荐包 |
| Go 静态编译 | ⭐⭐⭐⭐⭐ | CGO_ENABLED=0 无依赖 |
使用 dive 分析镜像
# 安装 dive
# https://github.com/wagoodman/dive
# 分析镜像层
dive nginx:alpine
# dive 界面:
# 左侧: 镜像层列表
# 右侧上: 选中层的文件变更
# 右侧下: 最终文件系统
# 底部: 镜像效率评分
18.2 安全扫描
Docker Scout
# 快速概览
docker scout quickview nginx:alpine
# 详细漏洞报告
docker scout cves nginx:alpine
# 仅查看高危漏洞
docker scout cves --only-severity critical,high nginx:alpine
# 比较两个镜像
docker scout compare nginx:1.25-alpine nginx:1.24-alpine
# 推荐修复版本
docker scout recommendations nginx:alpine
# SBOM(软件物料清单)
docker scout sbom nginx:alpine
Trivy
# 扫描镜像漏洞
trivy image nginx:alpine
# 仅扫描高危和严重漏洞
trivy image --severity HIGH,CRITICAL nginx:alpine
# 以 JSON 格式输出
trivy image --format json --output results.json nginx:alpine
# 扫描 Dockerfile
trivy config Dockerfile
# 扫描文件系统
trivy fs --security-checks vuln,config .
# 作为 CI/CD 中的门禁
trivy image --exit-code 1 --severity CRITICAL my-app:latest
漏洞管理策略
漏洞严重等级:
CRITICAL (严重) → 必须立即修复,阻断部署
HIGH (高危) → 24 小时内修复
MEDIUM (中危) → 1 周内修复
LOW (低危) → 下次版本修复
处理流程:
1. CI/CD 中自动扫描
2. CRITICAL/HIGH 阻断部署
3. 查看修复建议(升级基础镜像/依赖)
4. 修复后重新构建和扫描
5. 记录已知漏洞的例外(accepted risk)
18.3 生产环境规范
Dockerfile 规范
# ✅ 生产环境 Dockerfile 规范
# 1. 使用官方最小基础镜像
FROM python:3.11-slim-bookworm
# 2. 设置元数据
LABEL maintainer="[email protected]"
LABEL version="1.0.0"
LABEL description="My application"
# 3. 设置工作目录
WORKDIR /app
# 4. 安装系统依赖(合并层 + 清理缓存)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libpq-dev \
curl && \
rm -rf /var/lib/apt/lists/*
# 5. 复制依赖文件(利用缓存)
COPY requirements.txt .
# 6. 安装 Python 依赖
RUN pip install --no-cache-dir -r requirements.txt
# 7. 创建非 root 用户
RUN addgroup --system appgroup && \
adduser --system --ingroup appgroup appuser
# 8. 复制应用代码
COPY --chown=appuser:appgroup . .
# 9. 切换到非 root 用户
USER appuser
# 10. 声明端口
EXPOSE 8000
# 11. 健康检查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=10s \
CMD curl -f http://localhost:8000/health || exit 1
# 12. 设置停止信号
STOPSIGNAL SIGTERM
# 13. 启动命令(exec 格式)
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "app:app"]
运行时安全规范
# ✅ 生产环境容器运行规范
docker run -d \
--name my-app \
--user 1000:1000 \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges \
--security-opt seccomp=default.json \
--memory 512m \
--memory-reservation 256m \
--cpus 1.0 \
--pids-limit 100 \
--restart unless-stopped \
--health-cmd "curl -f http://localhost:8000/health || exit 1" \
--health-interval 30s \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
-p 8000:8000 \
my-app:1.0.0
Compose 生产配置
services:
app:
image: my-app:1.0.0 # 使用具体版本,不要用 latest
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=100m
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
cpus: "0.25"
memory: 128M
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- app-net
networks:
app-net:
driver: bridge
18.4 镜像标签策略
# 语义化版本 (SemVer)
docker build -t my-app:1.0.0 -t my-app:1.0 -t my-app:1 -t my-app:latest .
# Git commit hash
GIT_SHA=$(git rev-parse --short HEAD)
docker build -t my-app:sha-${GIT_SHA} .
# CI/CD 构建
BUILD_DATE=$(date +%Y%m%d)
BUILD_NUM=${BUILD_NUMBER:-local}
docker build -t my-app:${BUILD_DATE}-${BUILD_NUM} .
| 标签 | 用途 | 是否推荐用于生产 |
|---|
1.0.0 | 正式发布版本 | ✅ |
1.0 | 次版本(会更新) | ✅ |
sha-abc1234 | CI/CD 构建标识 | ✅ |
latest | 开发/测试 | ❌ |
develop | 开发分支 | ❌ |
stable | 稳定版(可变) | ⚠️ 谨慎使用 |
18.5 日志规范
// 结构化日志(JSON 格式)
{
"timestamp": "2024-01-01T12:00:00.000Z",
"level": "info",
"message": "User login successful",
"service": "auth-service",
"request_id": "abc-123",
"user_id": "42",
"duration_ms": 150
}
| 字段 | 说明 |
|---|
timestamp | ISO 8601 时间戳 |
level | 日志级别:debug, info, warn, error |
message | 日志消息 |
service | 服务名称 |
request_id | 请求追踪 ID |
error | 错误详情(仅 error 级别) |
18.6 监控规范
必要监控指标
| 类别 | 指标 | 告警阈值 |
|---|
| 容器 | CPU 使用率 | > 80% 持续 5 分钟 |
| 容器 | 内存使用率 | > 85% |
| 容器 | 重启次数 | > 3 次/小时 |
| 容器 | 健康检查失败 | 连续 3 次 |
| 宿主机 | 磁盘使用率 | > 85% |
| 宿主机 | 磁盘 I/O 等待 | > 20% |
| 应用 | 请求延迟 P99 | > 1 秒 |
| 应用 | 错误率 | > 1% |
18.7 备份策略
#!/bin/bash
# docker-backup.sh — Docker 数据备份脚本
BACKUP_DIR="/backup/$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# 备份所有命名卷
for volume in $(docker volume ls -q); do
echo "Backing up volume: $volume"
docker run --rm \
-v "$volume":/source:ro \
-v "$BACKUP_DIR":/backup \
alpine:latest \
tar czf "/backup/volume-${volume}.tar.gz" -C /source .
done
# 备份 compose 配置
cp /opt/myapp/docker-compose.yml "$BACKUP_DIR/"
cp /opt/myapp/.env "$BACKUP_DIR/" 2>/dev/null
# 保留最近 7 天的备份
find /backup -maxdepth 1 -mtime +7 -exec rm -rf {} \;
echo "Backup completed: $BACKUP_DIR"
18.8 Kubernetes 入门导引
为什么需要 Kubernetes
| 场景 | Docker Compose | Docker Swarm | Kubernetes |
|---|
| 单机开发 | ✅ | ❌ | ❌ |
| 小型生产 | ✅ | ✅ | ⚠️ |
| 中型生产 | ❌ | ✅ | ✅ |
| 大型生产 | ❌ | ❌ | ✅ |
| 多云混合 | ❌ | ❌ | ✅ |
| 自动扩缩容 | ❌ | ❌ | ✅ |
| 学习曲线 | 低 | 低 | 高 |
K8s 核心概念
Kubernetes 资源模型:
┌────── Cluster ──────┐
│ │
│ ┌──── Node ────┐ │
│ │ │ │
│ │ ┌─── Pod ───┐│ │
│ │ │ Container ││ │
│ │ │ Container ││ │
│ │ └───────────┘│ │
│ │ │ │
│ │ ┌─── Pod ───┐│ │
│ │ │ Container ││ │
│ │ └───────────┘│ │
│ └───────────────┘ │
│ │
│ ┌──── Node ────┐ │
│ │ ┌─── Pod ───┐│ │
│ │ │ Container ││ │
│ │ └───────────┘│ │
│ └───────────────┘ │
└──────────────────────┘
核心资源:
Pod → 最小部署单元(1+ 容器)
Deployment → 管理 Pod 副本和滚动更新
Service → 网络服务发现和负载均衡
ConfigMap → 配置数据
Secret → 敏感数据
Ingress → HTTP(S) 路由
PV/PVC → 持久化存储
Namespace → 资源隔离
Docker Compose → Kubernetes 迁移
# docker-compose.yaml
services:
web:
image: nginx:alpine
ports:
- "80:80"
environment:
- NODE_ENV=production
depends_on:
- api
api:
image: my-api:v1
ports:
- "8080:3000"
environment:
- DB_HOST=db
# 等效的 Kubernetes 配置
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: my-api:v1
ports:
- containerPort: 3000
env:
- name: DB_HOST
value: "db"
Kompose:自动转换工具
# 安装 kompose
# https://kompose.io/
# 将 docker-compose.yaml 转换为 Kubernetes 资源
kompose convert
# 直接部署到 K8s 集群
kompose up
# 清理
kompose down
本地 K8s 学习环境
| 工具 | 说明 | 适用场景 |
|---|
| Minikube | 单节点 K8s 集群 | 本地开发学习 |
| kind | Docker 中运行 K8s | CI/CD 测试 |
| k3s | 轻量级 K8s | 边缘计算、IoT |
| Docker Desktop | 内置 K8s | macOS/Windows 开发 |
# 使用 kind 创建本地集群
kind create cluster --name my-cluster
# 使用 kubectl 操作
kubectl get nodes
kubectl get pods -A
# 部署应用
kubectl apply -f deployment.yaml
kubectl get pods
kubectl logs -f <pod-name>
# 删除集群
kind delete cluster --name my-cluster
18.9 综合检查清单
镜像检查清单
运行时检查清单
CI/CD 检查清单
生产环境检查清单
18.10 学习路线图
Docker 学习路线:
初级 (1-2 周):
├── 理解容器概念
├── 掌握 Docker 基本命令
├── 编写简单 Dockerfile
└── 使用 Docker Compose
中级 (2-4 周):
├── 深入理解镜像分层和缓存
├── 多阶段构建优化
├── 网络模型和存储方案
├── CI/CD 集成
└── 基本安全加固
高级 (4-8 周):
├── 生产环境部署规范
├── 监控和日志方案
├── 安全扫描和合规
├── Swarm 集群管理
└── Kubernetes 入门
专家:
├── Kubernetes 深入
├── 服务网格 (Istio)
├── GitOps (ArgoCD)
├── 平台工程
└── 成本优化
要点回顾
| 要点 | 核心内容 |
|---|
| 镜像瘦身 | 多阶段构建 + Alpine/distroless + .dockerignore |
| 安全扫描 | Docker Scout / Trivy 集成到 CI/CD |
| 生产规范 | 非 root 运行、资源限制、只读文件系统、日志轮转 |
| 标签策略 | 语义化版本,避免 latest 用于生产 |
| K8s 导引 | Kompose 转换、本地集群学习、核心资源理解 |
注意事项
持续优化: Docker 最佳实践是演进的。定期回顾和更新 Dockerfile、Compose 配置和安全策略。
不要过度优化: 开发环境优先考虑效率,生产环境才需要严格执行安全和性能规范。
社区资源: 关注 Docker 官方博客、CNCF 项目和安全公告,保持知识更新。
恭喜完成!
🎉 你已经完成了 Docker 完全指南的全部 18 章学习。
回顾你的学习成果:
✅ 理解容器技术原理和 OCI 标准
✅ 掌握 Docker 安装、配置和镜像管理
✅ 熟练编写 Dockerfile 和多阶段构建
✅ 掌握网络模型和数据持久化
✅ 使用 Compose 编排多容器应用
✅ 了解 Swarm 集群和服务编排
✅ 实施安全加固和监控方案
✅ 集成 CI/CD 自动化流水线
✅ 具备故障排查能力
✅ 了解 Kubernetes 入门知识
下一步建议:
1. 实战: 将自己的项目容器化
2. 深入: 学习 Kubernetes
3. 认证: 考取 Docker DCA 认证
4. 社区: 参与开源项目贡献