背景
在使用 onlyoffice/documentserver 单容器部署 OnlyOffice 的过程中,虽然已经将常见目录(logs / data / cache / public / fonts)通过 bind mount 挂载到了用户目录,但在实际检查容器挂载点时,仍然发现 /var/lib/docker/volumes/ 下存在多组随机字符串命名的 volume。
这类 volume 并非人为创建,而是镜像在 Dockerfile 中通过 VOLUME 指令声明后,由 Docker 自动生成的匿名卷。如果不显式覆盖挂载,这些卷会默默承载真实数据,从而破坏“栈内统一、目录可迁移”的目标。
本文记录一次完整的排查与修正过程,将 OnlyOffice 的 全部持久化数据 统一收敛到单一项目目录下,并清理匿名卷依赖。
问题确认:匿名卷从何而来
通过以下命令检查容器挂载点:
docker inspect onlyoffice --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
可以观察到:
- 已显式挂载的目录(logs / data / cache / public / fonts)均为
bind - 但仍存在若干
volume类型挂载,来源为/var/lib/docker/volumes/<hash>/_data
这些匿名卷对应的典型路径包括:
/var/lib/onlyoffice/var/lib/redis/var/lib/postgresql/var/lib/rabbitmq/usr/share/fonts/truetype/custom
结论:OnlyOffice 内部依赖的 PostgreSQL / RabbitMQ / Redis 等组件,其数据仍然落在 Docker 管理区,而非项目目录。
目标
- 所有持久化数据 仅存在于项目目录内
- 不依赖匿名 volume
- 项目目录整体可
rsync/ 打包 / 迁移 - 启动后不再生成新的随机卷
现有目录结构(示例)
onlyoffice/
├── cache/
├── data/
├── fonts/
├── logs/
├── public/
└── docker-compose.yml
在此基础上,按现有命名风格新增目录:
onlyoffice/
├── onlyoffice/ # /var/lib/onlyoffice
├── redis/ # /var/lib/redis
├── postgresql/ # /var/lib/postgresql
├── rabbitmq/ # /var/lib/rabbitmq
├── fonts-custom/ # /usr/share/fonts/truetype/custom
匿名卷数据迁移(无损)
1. 停止服务并准备目录
docker compose down
rm -rf onlyoffice redis postgresql rabbitmq fonts-custom
mkdir -p onlyoffice redis postgresql rabbitmq fonts-custom
2. 使用临时容器导出匿名卷内容
统一使用 alpine 作为复制工具:
docker run --rm -v <volume_id>:/from -v "$PWD/<target_dir>:/to" alpine \
sh -c "set -e; cp -a /from/. /to/."
分别对 /var/lib/onlyoffice、/var/lib/redis、/var/lib/postgresql、/var/lib/rabbitmq、/usr/share/fonts/truetype/custom 对应的卷执行上述操作。
完成后通过:
du -sh onlyoffice redis postgresql rabbitmq fonts-custom
确认数据体积合理(通常 PostgreSQL 与 RabbitMQ 占用最大)。
更新 Compose:显式覆盖镜像内置 VOLUME
在原有 compose 基础上,仅新增挂载项:
services:
onlyoffice:
image: onlyoffice/documentserver
container_name: onlyoffice
restart: always
ports:
- "8080:80"
volumes:
- ./logs:/var/log/onlyoffice
- ./data:/var/www/onlyoffice/Data
- ./cache:/var/lib/onlyoffice/documentserver/App_Data/cache/files
- ./public:/var/www/onlyoffice/documentserver-example/public/files
- ./fonts:/usr/share/fonts
# 覆盖镜像内置 VOLUME,避免匿名卷
- ./onlyoffice:/var/lib/onlyoffice
- ./redis:/var/lib/redis
- ./postgresql:/var/lib/postgresql
- ./rabbitmq:/var/lib/rabbitmq
- ./fonts-custom:/usr/share/fonts/truetype/custom
启动与验证
docker compose up -d
再次检查挂载点:
docker inspect onlyoffice --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
确认 全部为 bind mount,且不再出现 /var/lib/docker/volumes/...。
RabbitMQ 多节点目录说明与清理
在 rabbitmq/mnesia/ 下可能出现多个 rabbit@<hostname> 目录,这是因为容器 hostname 变化导致的历史节点残留。
可通过以下方式确认当前节点:
docker exec onlyoffice rabbitmqctl status | grep Node
仅保留当前节点对应目录,其余可先移动到备份目录,确认运行稳定后再删除。
建议在 compose 中固定 hostname(如 hostname: onlyoffice),以避免未来再次生成新节点目录。
结果
- OnlyOffice 所有持久化数据统一收敛到项目目录
- 匿名卷彻底消除
- 项目目录可整体迁移、备份、恢复
- 数据布局清晰、可控
这类问题并非 OnlyOffice 独有,任何声明了 VOLUME 的镜像在使用时,都应明确检查并覆盖其持久化路径,否则极易在长期运维中留下隐患。