Docker进阶技巧

前面我们已经学习了Docker的基础知识和实战项目,今天我们深入探讨镜像优化、安全加固、性能调优等高级话题。

1. 镜像体积优化

多阶段构建

问题:传统构建方式镜像体积大(包含构建工具)

# 不好:镜像包含gcc、make等构建工具
FROM python:3.11
RUN apt-get update && apt-get install -y gcc
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
# 镜像大小:900MB

解决方案:多阶段构建

# 好:分离构建和运行环境
FROM python:3.11-slim AS builder
RUN apt-get update && apt-get install -y gcc
COPY requirements.txt .
RUN pip install --user -r requirements.txt

FROM python:3.11-slim
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
# 镜像大小:150MB

使用alpine基础镜像

对比:

  • python:3.11:900MB(完整版)
  • python:3.11-slim:120MB(瘦身版)
  • python:3.11-alpine:50MB(Alpine版)
# 使用alpine
FROM python:3.11-alpine

# 注意:alpine使用musl libc,某些C扩展可能不兼容
# 如果遇到兼容性问题,用slim版本

合并RUN指令

不好:

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN apt-get clean
# 创建4层,每层都有缓存

好:

RUN apt-get update && \
    apt-get install -y curl wget && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# 只创建1层

清理缓存

# Python:使用--no-cache-dir
RUN pip install --no-cache-dir -r requirements.txt

# apt:清理apt缓存
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# npm:清理npm缓存
RUN npm install && npm cache clean --force

利用构建缓存

原理:如果Dockerfile指令和文件没变化,Docker复用缓存。

优化Dockerfile顺序:

# 不常变化的放前面(能复用缓存)
FROM python:3.11-slim
WORKDIR /app

# 依赖文件很少变化
COPY requirements.txt .
RUN pip install -r requirements.txt

# 源代码经常变化
COPY . .

使用.dockerignore

# .dockerignore
.git
.gitignore
__pycache__
*.pyc
*.pyo
venv
.venv
.env
tests/
docs/
*.md

效果:减少构建上下文大小,提高构建速度。

2. 安全加固

不以root用户运行

不好:

FROM python:3.11
# 默认以root运行

好:

FROM python:3.11-slim

# 创建非root用户
RUN groupadd -r appuser && useradd -r -g appuser appuser

# 切换用户
USER appuser

# 运行应用
CMD ["python", "app.py"]

使用特定版本标签

不好:

FROM python:latest
# latest标签可能随时变化

好:

FROM python:3.11.7
# 明确版本,避免意外更新

不存储密钥

不好:

COPY .env .
# 密钥进入镜像历史

好:

# 运行时注入
docker run -e API_KEY=xxx myapp

# 或使用secrets(Swarm)
docker service create --secret api_key myapp

只安装必要的包

不好:

RUN apt-get install -y vim emacs nano wget curl
# 安装太多不必要的工具

好:

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
# 只安装必要的

扫描镜像漏洞

# 使用Trivy扫描漏洞
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy image myapp:latest

# 使用Docker Scout(Docker内置)
docker scout quickview myapp:latest
docker scout cves myapp:latest

定期更新基础镜像

# 检查基础镜像更新
docker pull python:3.11-slim

# 重新构建镜像
docker build -t myapp:latest .

3. 性能优化

资源限制

services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

启用BuildKit

# 启用BuildKit(默认已启用)
export DOCKER_BUILDKIT=1

# BuildKit优化:
# - 并行构建
# - 更好的缓存
# - 更快的构建速度

使用缓存挂载

# 使用BuildKit缓存挂载
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

多阶段构建示例

# 构建阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app

# 运行阶段(最小化)
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app /app
ENTRYPOINT ["/app"]
# 最终镜像只有几MB

4. 最佳实践

1. 遵循单一职责原则

一个镜像只做一件事:

  • nginx:Web服务器
  • mysql:数据库
  • redis:缓存

2. 最小化层数

# 合并RUN指令
RUN apt-get update && \
    apt-get install -y curl wget && \
    apt-get clean

# 合并ENV指令
ENV PATH=/usr/local/bin:$PATH \
    TZ=Asia/Shanghai \
    LANG=C.UTF-8

3. 使用健康检查

HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8000/health || exit 1

4. 使用信号处理

# app.py
import signal
import sys

def handle_signal(signum, frame):
    print("Received signal, shutting down...")
    sys.exit(0)

signal.signal(signal.SIGTERM, handle_signal)
# STOPSIGNAL设置停止信号
STOPSIGNAL SIGTERM

5. 日志处理

# 输出到stdout/stderr(Docker会自动收集)
CMD ["gunicorn", "--access-logfile", "-", "--error-logfile", "-", "app:app"]

6. 配置文件外部化

# docker-compose.yml
services:
  app:
    volumes:
      - ./config:/app/config:ro

5. 故障排查

1. 查看容器日志

# 实时查看
docker logs -f myapp

# 查看最近100行
docker logs --tail=100 myapp

# 查看最近10分钟
docker logs --since=10m myapp

2. 进入容器排查

# 进入容器
docker exec -it myapp bash

# 查看进程
docker exec myapp ps aux

# 查看网络
docker exec myapp netstat -tuln

# 查看文件
docker exec myapp ls -la /app

3. 检查资源使用

# 查看资源使用
docker stats myapp

# 查看容器详细信息
docker inspect myapp

4. 网络排查

# 检查网络连通性
docker exec myapp ping other-container

# 检查DNS解析
docker exec myapp nslookup other-container

# 检查端口
docker exec myapp nc -zv other-container 8000

5. 常见问题

问题1:容器无法启动

# 查看日志
docker logs myapp

# 检查端口冲突
docker ps | grep 8000

# 检查资源限制
docker inspect myapp | grep -A 10 HostConfig

问题2:容器内存溢出

# 增加内存限制
docker run -m 1g myapp

# 检查内存使用
docker stats --no-stream myapp

问题3:网络不通

# 检查网络
docker network ls
docker network inspect my-network

# 检查防火墙
sudo iptables -L -n

6. 监控和告警

Prometheus监控

services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana

  cadvisor:
    image: gcr.io/cadvisor/cadvisor
    ports:
      - "8080:8080"
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro

告警配置

# alerting.yml
groups:
  - name: docker_alerts
    rules:
      - alert: ContainerDown
        expr: up{job="docker"} == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Container {{ $labels.name }} is down"

      - alert: HighMemoryUsage
        expr: container_memory_usage_bytes / container_spec_memory_limit_bytes > 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Container {{ $labels.name }} high memory usage"

7. 生产环境检查清单

部署前检查

  • 镜像经过安全扫描
  • 不以root用户运行
  • 配置了健康检查
  • 设置了资源限制
  • 配置了日志收集
  • 数据持久化已配置
  • 网络隔离已配置
  • 环境变量外部化
  • 镜像版本已锁定
  • 备份策略已制定

运行时检查

  • 容器正常启动
  • 健康检查通过
  • 日志正常输出
  • 资源使用正常
  • 网络连通性正常
  • 数据读写正常
  • 监控告警正常

8. Docker vs Kubernetes

什么时候用Docker Compose?

  • 单机部署
  • 项目规模小
  • 服务数量少(<10)
  • 快速原型开发

什么时候用Kubernetes?

  • 多机集群
  • 大规模生产环境
  • 服务数量多(>10)
  • 需要自动扩缩容
  • 需要高级调度

迁移路径

Docker Compose → Docker Swarm → Kubernetes

本章小结

  • 镜像优化:多阶段构建、使用alpine、合并指令、清理缓存
  • 安全加固:非root用户、特定版本、不存储密钥、扫描漏洞
  • 性能优化:资源限制、BuildKit、缓存挂载、多阶段构建
  • 最佳实践:单一职责、健康检查、信号处理、日志处理
  • 故障排查:日志分析、资源监控、网络诊断
  • 监控告警:Prometheus、Grafana、Alertmanager

现在已经掌握了Docker的高级技巧,可以应对90%的应用场景了!

恭喜你完成Docker教程,继续实践和探索吧!