1. 为什么Docker会吞噬你的磁盘空间?

每次看到 df -h 命令显示根目录爆红时,作为运维老手的我都会心头一紧。上周生产环境又出现了磁盘告警,排查发现某个容器的日志卷占用了47GB空间。这让我想起三年前第一次被Docker存储问题暴击的经历——当时整个CI/CD流水线瘫痪,仅仅是因为 /var/lib/docker 撑满了宿主机的磁盘。

Docker的存储机制就像个贪吃的仓鼠:

  • 镜像层叠 :每个 FROM 指令都生成新层,即使只修改1MB文件也会产生完整镜像层
  • 缓存陷阱 :构建过程中的 RUN apt-get update 等中间层会被保留
  • 幽灵容器 :停止的容器仍占用磁盘( docker ps -a 可见)
  • 悬空镜像 : <none>:<none> 标签的中间镜像
  • 日志膨胀 :容器STDOUT/STERR输出默认无限增长

重要提示:Docker默认不会自动清理任何资源,这是为了避免误删正在使用的数据。但这也意味着磁盘占用会随时间持续增长。

2. 手动清理的七种武器与局限

2.1 基础清理命令

# 删除所有停止的容器
docker container prune

# 删除所有未被使用的镜像(非悬空)
docker image prune -a

# 删除构建缓存
docker builder prune

# 删除悬空镜像
docker image prune

这些命令能解决80%的日常问题,但存在明显缺陷:

  • 需要人工定期执行
  • 无法处理正在运行的容器日志
  • 不会清理卷(volume)数据
  • 无法设置保留策略(如"保留最近3个版本")

2.2 高级空间分析工具

使用 docker system df 查看详细占用:

TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          15        10        5.3GB     1.2GB (23%)
Containers      12        6         1.1GB     620MB (56%)
Local Volumes   5         3         2.5GB     750MB (30%)
Build Cache     45        0         890MB     890MB (100%)

结合 du -sh /var/lib/docker/* 定位具体目录:

12G    /var/lib/docker/containers
4.8G   /var/lib/docker/overlay2
1.2G   /var/lib/docker/volumes

3. 自动化清理方案设计与实现

3.1 基于Cron的定时任务

创建 /etc/cron.weekly/docker-clean :

#!/bin/bash
# 保留最近3个版本的镜像
docker image prune -a --force --filter "until=72h"

# 清理所有停止容器和悬空镜像
docker system prune -f

# 限制日志文件大小(全局配置)
echo '{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}' > /etc/docker/daemon.json

systemctl restart docker

给脚本添加执行权限:

chmod +x /etc/cron.weekly/docker-clean

3.2 日志轮转的高级配置

对于关键容器单独配置日志策略:

# docker-compose.yml示例
version: '3'
services:
  app:
    image: nginx
    logging:
      driver: "json-file"
      options:
        max-size: "50m"
        max-file: "5"

3.3 基于Prometheus的智能清理

当磁盘使用率超过85%时自动触发清理:

# alertmanager.yml配置
groups:
- name: docker.alerts
  rules:
  - alert: DockerDiskPressure
    expr: (node_filesystem_avail_bytes{mountpoint="/"} * 100) / node_filesystem_size_bytes{mountpoint="/"} < 15
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "Docker 磁盘空间不足 (instance {{ $labels.instance }})"

配套的清理脚本:

#!/usr/bin/env python3
import docker
import shutil

client = docker.from_env()

def auto_clean():
    # 优先清理非生产环境容器
    for container in client.containers.list(filters={"status": "exited"}):
        if 'prod' not in container.labels.get('env', ''):
            container.remove(v=True)
    
    # 保留最近5个版本的镜像
    images = client.images.list(filters={"dangling": False})
    sorted_images = sorted(images, key=lambda x: x.attrs['Created'], reverse=True)
    for img in sorted_images[5:]:
        if not any('prod' in tag for tag in img.tags):
            client.images.remove(img.id)

4. 生产环境最佳实践与避坑指南

4.1 分层构建优化技巧

错误的Dockerfile:

FROM ubuntu
RUN apt-get update
RUN apt-get install -y python3  # 产生冗余层
RUN pip install -r requirements.txt

优化后的版本:

FROM ubuntu
RUN apt-get update && \
    apt-get install -y python3 && \
    rm -rf /var/lib/apt/lists/*  # 清理apt缓存

COPY requirements.txt .
RUN pip install -r requirements.txt && \
    rm -rf ~/.cache/pip  # 清理pip缓存

4.2 存储驱动选择策略

根据文件系统类型选择存储驱动:

文件系统 推荐驱动 特点
ext4/xfs overlay2 性能最佳,支持分层
btrfs btrfs 原生支持快照
zfs zfs 压缩去重能力强
aufs aufs 老系统兼容

检查当前驱动:

docker info | grep "Storage Driver"

4.3 卷(volume)管理黄金法则

  1. 避免使用 --mount type=bind 绑定主机目录,优先使用命名卷
  2. 定期检查卷使用情况:
    docker system df -v
    
  3. 对数据库等有状态服务,设置自动备份后再清理:
    # PostgreSQL示例
    docker exec postgres pg_dump -U user dbname > backup.sql
    docker volume rm postgres_data
    

5. 终极解决方案:分布式存储集成

对于大型K8s集群,建议:

  1. 配置CSI驱动对接Ceph/GlusterFS等分布式存储
  2. 设置存储类(StorageClass)的回收策略为 Delete
  3. 使用LocalPV时添加节点污点容忍

示例StorageClass配置:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ceph-rbd
provisioner: rbd.csi.ceph.com
parameters:
  clusterID: ceph-cluster
  pool: rbd
reclaimPolicy: Delete
volumeBindingMode: Immediate

我最后悔的是曾经在周五下午执行了 docker system prune -a --volumes ,结果删除了未备份的测试数据库。现在我的自动化脚本都会先检查容器标签,对带有 backup=false 的容器会跳过清理并发送告警。记住:自动化不是万能的,关键数据永远要有双重保护。

更多推荐