背景

在使用 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 的镜像在使用时,都应明确检查并覆盖其持久化路径,否则极易在长期运维中留下隐患。

Leave a Reply

Your email address will not be published. Required fields are marked *