Docker 存储进阶:Volume 驱动、NFS/Ceph 共享存储与 tmpfs 实战
深入讲解 Docker 存储的进阶方案:Volume 插件驱动架构与常用插件(local/nfs/vieux-sshfs)、NFS 共享存储实现多容器跨主机数据访问、Ceph RBD 块存储集成、tmpfs 内存挂载的安全应用场景、存储性能基准对比,以及 Docker Swarm 环境下的有状态服务存储方案选型。
基础篇讲了 Named Volume 和 Bind Mount,本文进入存储进阶:当多台机器上的容器需要共享数据时,单机的 Named Volume 就不够用了。NFS、Ceph 等分布式存储通过 Volume 驱动接入 Docker,实现跨主机数据共享。
Volume 驱动(Plugin)架构
Docker Volume 驱动架构:
docker CLI
↓
Docker Engine
↓ Volume Plugin API
Volume Driver(插件)
↓
实际存储后端
├── local(默认,本地磁盘)
├── nfs(NFS 共享)
├── ceph(Ceph RBD/CephFS)
├── s3(AWS S3/MinIO)
└── vieux/sshfs(SSH 远程目录)
Volume 插件提供统一的 API:
Create/Remove/Mount/Unmount/Path/List/Get
# 查看已安装的 Volume 驱动
docker info | grep -A5 "Plugins"
# Plugins:
# Volume: local ← 默认
# 安装 Volume 插件(以 vieux/sshfs 为例)
docker plugin install vieux/sshfs
# 查看插件
docker plugin ls
一、local 驱动的高级用法
local 是默认驱动,支持通过 --opt 使用 mount 命令的选项。
# 创建 tmpfs 类型的 Volume(内存存储)
docker volume create \
--driver local \
--opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=256m,uid=1000 \
my-tmpfs
docker run -d --mount source=my-tmpfs,target=/cache myapp
# 创建 NFS 挂载的 Volume(local 驱动通过 mount 选项)
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,vers=4,rw \
--opt device=:/data/shared \
nfs-shared
# 创建绑定指定路径的 Volume(相当于有名字的 bind mount)
docker volume create \
--driver local \
--opt type=none \
--opt device=/data/myapp \
--opt o=bind \
myapp-data
二、NFS 共享存储
NFS 是最常见的跨主机共享存储方案,配置简单,适合中小规模部署。
NFS 服务端配置
# 在 NFS 服务器上(192.168.1.100)
# 安装 NFS 服务
apt-get install -y nfs-kernel-server # Ubuntu
yum install -y nfs-utils # CentOS
# 创建共享目录
mkdir -p /data/docker-shared
chmod 777 /data/docker-shared
# 配置 exports
cat >> /etc/exports << 'EOF'
/data/docker-shared 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)
# rw → 读写权限
# sync → 写入时同步到磁盘(更安全)
# no_root_squash → 允许 root 用户访问(Docker 容器需要)
EOF
# 重新加载
exportfs -ra
systemctl restart nfs-kernel-server
# 验证
showmount -e localhost
# Export list for localhost:
# /data/docker-shared 192.168.1.0/24
Docker 使用 NFS Volume
# 方法1:docker volume create
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,vers=4,rw,sync \
--opt device=:/data/docker-shared \
nfs-shared-vol
# 使用
docker run -d \
--mount source=nfs-shared-vol,target=/shared \
myapp
# 方法2:直接在 docker run 中指定(不预创建 Volume)
docker run -d \
--mount type=volume,\
source=nfs-shared,\
target=/shared,\
volume-driver=local,\
volume-opt=type=nfs,\
"volume-opt=o=addr=192.168.1.100,vers=4",\
volume-opt=device=:/data/docker-shared \
myapp
docker-compose 中使用 NFS
# compose.yml
services:
api-1:
image: myapp:v1
volumes:
- shared-uploads:/app/uploads
deploy:
replicas: 3 # 多副本共享同一个 NFS Volume
api-2:
image: myapp:v1
volumes:
- shared-uploads:/app/uploads
volumes:
shared-uploads:
driver: local
driver_opts:
type: nfs
o: addr=192.168.1.100,vers=4,rw,sync,hard,intr
device: ":/data/docker-shared/uploads"
# NFS 挂载选项说明:
# vers=4 → NFS v4(推荐)
# hard → 连接断开时无限重试(不丢数据)
# intr → 允许中断(用 Ctrl+C 可以停止)
# soft → 超时后返回错误(rpc超时时不挂起)
# timeo=900 → 超时 90 秒(默认)
# retrans=3 → 重传 3 次
三、Ceph 存储集成
Ceph 提供块存储(RBD)和文件存储(CephFS)两种方式接入 Docker。
CephFS(文件存储,类似 NFS)
# 前提:已有 Ceph 集群,创建了 CephFS
# 安装 ceph-fuse
apt-get install -y ceph-fuse
# 挂载 CephFS(宿主机层面)
mkdir -p /mnt/cephfs
ceph-fuse -m 192.168.1.50:6789 /mnt/cephfs \
--id=docker \
--keyring=/etc/ceph/ceph.client.docker.keyring
# 验证
df -h /mnt/cephfs
# ceph-fuse 100G 10G 90G 10% /mnt/cephfs
# 用 bind mount 给容器使用
docker run -d \
--mount type=bind,source=/mnt/cephfs/myapp,target=/data \
myapp
# 或者创建 bind volume
docker volume create \
--driver local \
--opt type=none \
--opt device=/mnt/cephfs/myapp \
--opt o=bind \
cephfs-myapp-vol
Ceph RBD(块存储,高性能)
# 安装 Docker Volume 插件(ceph/rbd-docker-plugin)
docker plugin install ceph/rbd
# 创建 Ceph RBD Volume
docker volume create \
--driver ceph/rbd \
--opt name=myapp-data \
--opt size=20G \
--opt pool=docker-pool \
--opt monitors=192.168.1.50:6789 \
--opt keyring=/etc/ceph/ceph.client.admin.keyring \
rbd-myapp-vol
# 使用(每次只能挂载到一台宿主机,RBD 不支持多主机同时挂载)
docker run -d \
--mount source=rbd-myapp-vol,target=/data \
myapp
四、tmpfs 进阶用法
# tmpfs 基础(内存中的临时文件系统)
docker run -d \
--tmpfs /tmp:rw,noexec,nosuid,size=128m \
myapp
# --mount 格式(更完整的选项)
docker run -d \
--mount type=tmpfs,target=/tmp,tmpfs-size=256m,tmpfs-mode=1777 \
myapp
# tmpfs 选项说明:
# size → 最大大小(不设置则用可用内存)
# mode → 文件权限(1777 = sticky bit,类似 /tmp)
# noexec → 禁止执行二进制(安全加固)
# nosuid → 禁止 setuid 位(安全加固)
生产安全场景:密钥/凭证存内存
# 场景:应用启动时需要一个密钥文件,但不能写磁盘
# 1. tmpfs 挂载到 /secrets
docker run -d \
--mount type=tmpfs,target=/secrets,tmpfs-mode=0700 \
-e VAULT_ADDR=http://vault:8200 \
-e VAULT_TOKEN=s.xxxxx \
myapp
# 2. 应用启动时从 Vault 获取密钥,写入 /secrets/
# entrypoint.sh:
# vault kv get -field=key secret/myapp > /secrets/app.key
# chmod 600 /secrets/app.key
# exec python3 app.py
# 好处:密钥存在内存中,容器重启后自动消失,不写磁盘
五、Volume 备份与恢复
# 备份 Named Volume(通用方法)
docker run --rm \
-v mysql_data:/source:ro \
-v $(pwd):/backup \
ubuntu:22.04 \
tar czf /backup/mysql_data_$(date +%Y%m%d_%H%M%S).tar.gz \
-C /source .
# 验证备份
ls -lh mysql_data_*.tar.gz
# 恢复 Volume
docker run --rm \
-v mysql_data:/target \
-v $(pwd):/backup \
ubuntu:22.04 \
tar xzf /backup/mysql_data_20260721_120000.tar.gz \
-C /target
# 自动化备份脚本(每天凌晨 2 点)
cat > /etc/cron.d/docker-volume-backup << 'EOF'
0 2 * * * root /usr/local/bin/backup-volumes.sh >> /var/log/backup.log 2>&1
EOF
cat > /usr/local/bin/backup-volumes.sh << 'SCRIPT'
#!/bin/bash
BACKUP_DIR=/data/backups/volumes
RETENTION_DAYS=7
DATE=$(date +%Y%m%d)
for VOLUME in mysql_data redis_data; do
docker run --rm \
-v ${VOLUME}:/source:ro \
-v ${BACKUP_DIR}:/backup \
ubuntu:22.04 \
tar czf /backup/${VOLUME}_${DATE}.tar.gz -C /source .
done
# 删除超过 7 天的备份
find ${BACKUP_DIR} -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete
SCRIPT
chmod +x /usr/local/bin/backup-volumes.sh
六、存储性能对比
存储方案 顺序读 顺序写 随机 IOPS 延迟 适用场景
──────────────────────────────────────────────────────────────────
本地 SSD overlay ~1500MB/s ~900MB/s ~200K 低 单机,最高性能
bind mount(SSD) ~1500MB/s ~900MB/s ~200K 低 配置文件,代码
Named Volume(本地) ~1500MB/s ~900MB/s ~200K 低 本地数据库
NFS v4 ~100MB/s ~80MB/s ~5K 中 共享文件,日志
Ceph RBD ~500MB/s ~400MB/s ~50K 中低 有状态服务迁移
CephFS ~200MB/s ~150MB/s ~20K 中 多写场景
tmpfs ~10GB/s ~10GB/s ~1M 极低 临时数据,密钥
关键参考:
- 数据库(MySQL/Redis):用本地 SSD Volume,性能差距 10 倍以上
- 多副本共享上传文件:NFS 够用,或用 MinIO/S3
- 跨主机有状态服务:Ceph RBD(每次只能一个节点挂载)
- 会话/临时缓存:tmpfs(极高性能+自动清理)
七、Docker Swarm 中的存储方案
# swarm 中有状态服务(数据库)的存储推荐方案
version: "3.9"
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
volumes:
- mysql_data:/var/lib/mysql
deploy:
replicas: 1 # 有状态服务只能 1 个副本(数据不能分裂)
placement:
constraints:
- node.labels.storage == ssd # 固定到有 SSD 的节点
volumes:
mysql_data:
driver: local # 本地高性能
driver_opts:
type: none
device: /data/mysql # 宿主机的 SSD 路径
o: bind
# 给节点打标签
docker node update --label-add storage=ssd node-01
小结
存储方案选型的核心逻辑:
单机场景:Named Volume(本地磁盘)= 最简单、最高性能,数据库首选。
多机共享文件:NFS Volume Driver,配置最简单;适合上传文件、日志聚合、共享配置。
多机高性能块存储:Ceph RBD,性能接近本地;适合需要跨机器迁移的有状态服务(但每次只能一个节点挂载)。
临时敏感数据:tmpfs,数据不落盘,容器重启自动清除,用于密钥、临时缓存。
无论选哪种存储,备份脚本都是必须的:用 docker run --rm -v volume:/source ubuntu tar czf 这个通用模式,可以备份任何 Docker Volume。
