强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 13 章:Docker 与 Btrfs

第 13 章:Docker 与 Btrfs

13.1 Docker 存储驱动概述

13.1.1 Docker 存储驱动对比

驱动文件系统支持性能稳定性推荐
overlay2所有✅ 生产推荐✅ 默认
btrfsBtrfs✅ 稳定Btrfs 用户
devicemapper块设备中等⚠️ 已弃用
zfsZFSZFS 用户
vfs所有测试用

13.1.2 选择 Btrfs 驱动的理由

优势说明
COW 快照容器创建/复制瞬间完成
透明压缩减少存储占用
配额管理限制容器空间使用
增量备份通过快照发送/接收
子卷隔离每个容器独立子卷
劣势说明
碎片化大量小写入导致碎片
配额开销启用配额有性能影响
兼容性部分 Docker 功能可能不完全兼容

13.2 配置 Docker 使用 Btrfs

13.2.1 Docker 守护进程配置

// /etc/docker/daemon.json
{
  "storage-driver": "btrfs",
  "storage-opts": [
    "btrfs.min_space=1G"
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
# 配置后重启 Docker
sudo systemctl restart docker

# 验证存储驱动
docker info | grep "Storage Driver"
# Storage Driver: btrfs

13.2.2 Btrfs 数据目录

# Docker 默认数据目录:/var/lib/docker
# 确保该目录在 Btrfs 文件系统上

# 方法 1:将整个 /var 放在 Btrfs 上
mount -o compress=zstd:3,ssd /dev/sdb1 /var

# 方法 2:为 Docker 创建专用子卷
btrfs subvolume create /data/@docker
mount -o subvol=/@docker,compress=zstd:3 /dev/sdb1 /var/lib/docker

# 方法 3:修改 Docker 数据目录
# daemon.json 中添加:
# "data-root": "/data/docker"

13.2.3 Docker 数据目录子卷布局

# 查看 Docker 创建的子卷
sudo btrfs subvolume list /var/lib/docker

# Docker Btrfs 驱动创建的子卷:
# ID 300 gen 50 top level 5 path docker
# ID 301 gen 51 top level 300 path docker/subvolumes/abc123...
# ID 302 gen 52 top level 300 path docker/subvolumes/def456...

13.3 Docker + Btrfs 快照管理

13.3.1 容器快照备份

# 1. 查看 Docker 子卷
DOCKER_ROOT=$(docker info --format '{{.DockerRootDir}}')
sudo btrfs subvolume list "$DOCKER_ROOT"

# 2. 对 Docker 数据目录创建快照
sudo btrfs subvolume snapshot -r /var/lib/docker /backup/docker-snap-$(date +%Y%m%d)

# 3. 增量备份
sudo btrfs send -p /backup/docker-snap-old /backup/docker-snap-new | \
    ssh backup "btrfs receive /backup/"

13.3.2 快速容器复制

# Docker 利用 Btrfs COW 快速复制容器
docker run -d --name app-v1 myapp:latest

# docker commit 利用 COW,几乎瞬间完成
docker commit app-v1 app-v2

# docker cp 同样利用 COW
docker cp app-v1:/data ./backup/

13.3.3 镜像层管理

Docker 镜像在 Btrfs 上的结构:

Image Layer 1 (base)    → Btrfs 子卷
Image Layer 2 (apt-get) → 基于 Layer 1 的快照 (COW)
Image Layer 3 (config)  → 基于 Layer 2 的快照 (COW)
Container Writable      → 基于 Image 的可写快照

13.4 存储池规划

13.4.1 Docker 存储池设计

# 推荐的 Docker Btrfs 子卷布局
# /dev/sdb1 → Btrfs 文件系统

# 子卷布局
# /@          → 系统根
# /@docker    → /var/lib/docker
# /@docker-data → Docker 数据卷
# /@snapshots → 快照存储

# 创建
btrfs subvolume create /mnt/@docker
btrfs subvolume create /mnt/@docker-data

# fstab
UUID=xxx /var/lib/docker      btrfs subvol=/@docker,compress=zstd:3,ssd,discard=async 0 0
UUID=xxx /var/lib/docker-data btrfs subvol=/@docker-data,compress=zstd:3,ssd 0 0

13.4.2 空间管理

# 查看 Docker 使用的空间
docker system df

# 输出示例:
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          15        8         5.2GB     2.1GB (40%)
# Containers      10        5         500MB     300MB (60%)
# Local Volumes   20        12        10GB      5GB (50%)
# Build Cache     0         0         0B        0B

# 清理未使用的资源
docker system prune -a

# 查看 Btrfs 层面的空间使用
sudo btrfs filesystem usage /var/lib/docker
sudo compsize /var/lib/docker

13.4.3 配额限制容器空间

# 启用配额
sudo btrfs quota enable /var/lib/docker

# 找到容器的子卷 ID
CONTAINER_ID=$(docker inspect --format '{{.Id}}' my-container)
SUBVOL_ID=$(sudo btrfs subvolume list /var/lib/docker | \
    grep "$CONTAINER_ID" | awk '{print $2}')

# 设置配额(10GB)
sudo btrfs qgroup limit 10G "$SUBVOL_ID" /var/lib/docker

# 查看使用情况
sudo btrfs qgroup show /var/lib/docker

13.5 Docker Compose + Btrfs 示例

13.5.1 数据库服务

# docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:16
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: secret

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data

volumes:
  postgres-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /var/lib/docker-data/postgres  # Btrfs 子卷上
  redis-data:
    driver: local
# 在 Btrfs 上为数据库创建专用目录(关闭 COW)
sudo mkdir -p /var/lib/docker-data/postgres
sudo chattr +C /var/lib/docker-data/postgres

# 验证 COW 已关闭
lsattr /var/lib/docker-data/postgres

13.6 监控与运维

13.6.1 Docker + Btrfs 监控脚本

#!/bin/bash
# docker-btrfs-monitor.sh
set -euo pipefail

DOCKER_ROOT=$(docker info --format '{{.DockerRootDir}}')
ALERT_PERCENT=80

echo "=== Docker + Btrfs Monitor ==="
echo "Docker Root: $DOCKER_ROOT"
echo "Time: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""

# Docker 资源使用
echo "--- Docker Resources ---"
docker system df
echo ""

# Btrfs 空间使用
echo "--- Btrfs Space ---"
sudo btrfs filesystem usage "$DOCKER_ROOT" | head -8
echo ""

# 设备统计
echo "--- Device Stats ---"
sudo btrfs device stats "$DOCKER_ROOT"
echo ""

# 子卷统计
SUBVOL_COUNT=$(sudo btrfs subvolume list "$DOCKER_ROOT" | wc -l)
echo "Total subvolumes: $SUBVOL_COUNT"

# 检查空间使用
USAGE=$(sudo btrfs filesystem usage "$DOCKER_ROOT" | grep "Device size" | awk '{print $3}')
USED=$(sudo btrfs filesystem usage "$DOCKER_ROOT" | grep "^Used:" | awk '{print $2}')
echo "Usage: $USED / $USAGE"

13.6.2 自动清理旧容器/镜像

#!/bin/bash
# docker-btrfs-cleanup.sh

# 清理停止的容器
docker container prune -f

# 清理未使用的镜像
docker image prune -a -f --filter "until=168h"  # 超过 7 天

# 清理未使用的卷
docker volume prune -f

# 清理构建缓存
docker builder prune -f

# 清理 Btrfs 旧快照
sudo btrfs subvolume list -s /var/lib/docker | \
    awk '{print $NF}' | \
    while read snap; do
        snap_date=$(echo "$snap" | grep -oP '\d{8}' || true)
        if [[ -n "$snap_date" ]]; then
            cutoff=$(date -d "30 days ago" +%Y%m%d)
            if [[ "$snap_date" < "$cutoff" ]]; then
                echo "Deleting old snapshot: $snap"
                sudo btrfs subvolume delete "/var/lib/docker/$snap" 2>/dev/null || true
            fi
        fi
    done

13.7 本章小结

操作说明
配置 Btrfs 驱动daemon.jsonstorage-driver: btrfs
数据目录建议专用子卷 /@docker
关闭 COW数据库目录 chattr +C
空间管理docker system prune + btrfs balance
备份基于快照的增量备份
监控监控子卷数量和空间使用

关键要点

  1. Docker Btrfs 驱动利用 COW 实现快速容器创建
  2. 数据库目录需要关闭 COW(chattr +C
  3. 建议 Docker 数据目录使用专用子卷
  4. 定期清理未使用的容器和镜像
  5. 利用 Btrfs 快照进行 Docker 数据备份

扩展阅读