如何用 rclone serve docker 把任意云存储以 Docker 卷插件方式提供给容器挂载?
rclone 可以通过 rclone serve docker 命令实现 Docker 的卷插件(volume plugin)API,让 docker daemon 直接把它背后的任意云存储(SFTP、Google Drive、S3 等)当作一个具名卷来创建和挂载,容器内看到的就像普通目录。这条功能自 rclone v1.56 引入,主要文档在 docs/content/docker.md 和 docs/content/commands/rclone_serve_docker.md。
插件必须与 docker daemon 运行在同一台主机上(Swarm 集群则是每个节点都要装),因为负责把远端文件系统挂载进容器的就是它。
前提条件
按文档要求,主机上需要准备:
- Docker Engine >= 19.03.15(托管插件模式的要求);
- FUSE 驱动,rclone 挂载所必需(Ubuntu 示例命令):
sudo apt-get -y install fuse3
- 插件的两个固定目录。插件不会自动创建它们,必须在安装前准备好:
/var/lib/docker-plugins/rclone/config:存放rclone.conf,即使为空也必須存在;/var/lib/docker-plugins/rclone/cache:存放插件状态文件和可选的 VFS 缓存。
sudo mkdir -p /var/lib/docker-plugins/rclone/config
sudo mkdir -p /var/lib/docker-plugins/rclone/cache
- 托管模式只能装在 Linux;MacOS 和 Windows 不支持原生 Docker 插件,文档明确要求在这些系统上改用托管模式(managed plugin)。
安装插件:托管模式(推荐主路径)
托管插件就是一个由 docker daemon 拉起的特殊容器,内部运行 rclone serve docker,config 和 cache 目录在启动时 bind mount 进去,docker daemon 通过容器内创建的 unix socket 与它通信。插件镜像在 Docker Hub 上发布,镜像名是 rclone/docker-volume-rclone。
安装命令(amd64 换成你的架构):
docker plugin install rclone/docker-volume-rclone:amd64 --grant-all-permissions --alias rclone
docker plugin list
当前可用的架构 tag 只有三个:amd64、arm64、arm-v7。要指定版本时用 ARCHITECTURE-VERSION 形式的 tag,例如 arm64 上的 v1.56.2 写作 rclone/docker-volume-rclone:arm64-1.56.2(注意去掉了 v)。latest tag 目前是 amd64 的别名;非 Intel 架构不能省略架构名,必须写全 tag,否则插件起不来。
安装时可以一次性带上插件参数:
docker plugin install rclone/docker-volume-rclone:amd64 \
--alias rclone --grant-all-permissions \
args="-v --allow-other" config=/etc/rclone
安装后如果插件处于未启用状态,可以用 docker plugin set 调整这几项设置:args、config、cache、HTTP_PROXY、HTTPS_PROXY、NO_PROXY、RCLONE_VERBOSE。示例:
docker plugin disable rclone
docker plugin set rclone RCLONE_VERBOSE=2 config=/etc/rclone args="--vfs-cache-mode=writes --allow-other"
docker plugin enable rclone
docker plugin inspect rclone
几个文档明确指出的细节:
args是rclone serve docker的命令行参数,支持 serve docker flags、通用 rclone flags,也包括后端参数(作为建卷时的默认值)。docker 存在一个 bug:args为空值时插件会失败,所以至少要给args="-v"这样的非空值。config=/host/dir指向rclone.conf所在目录。文件本身不存在不报错,但目录必须存在。插件会周期性改写该文件(例如续期存储访问 token),要避免主机上其他 rclone 实例同时改动它导致文件损坏。SFTP 私钥等文件也可以放这里,但注意它在插件容器内的固定路径是/data/config,比如主机上的sftp-box1.key对应的卷选项要写成-o sftp-key-file=/data/config/sftp-box1.key。cache=/host/dir指向缓存目录,VFS 缓存和docker-plugin.state状态文件都在里面。- Swarm 集群里要自行保证各节点插件设置一致,文档没有提供自动同步手段。
如果 docker 拒绝 disable 插件,说明有活动卷、容器或 swarm service 还在使用它,需要先把它们找出来停掉。
安装插件:Linux 上以 systemd 服务运行(可选方案)
文档提示:大多数情况应优先用托管模式,且只有 Linux 可以走这条路。做法是把 rclone 本身安装到主机后(先直接跑一次 rclone serve docker 可以做测试),用仓库中 contrib/docker-plugin/systemd/docker-volume-rclone.service 和 contrib/docker-plugin/systemd/docker-volume-rclone.socket 这两个 systemd 配置(文档正文中给出的下载文件名写的是 docker-volume-plugin.service/.socket,以仓库实际文件名 docker-volume-rclone.* 为准),放入 /etc/systemd/system/。
service 文件实际内容很简短,核心是 ExecStart=/usr/bin/rclone serve docker,并通过 ExecStartPre 自动创建三个目录(/var/lib/docker-volumes/rclone、config 和 cache 目录),环境变量固定为 RCLONE_CONFIG=/var/lib/docker-plugins/rclone/config/rclone.conf、RCLONE_CACHE_DIR=/var/lib/docker-plugins/rclone/cache、RCLONE_VERBOSE=1;socket 文件监听 /run/docker/plugins/rclone.sock。
该节所有命令都要以 root 执行。创建目录:
mkdir -p /var/lib/docker-volumes/rclone
mkdir -p /var/lib/docker-plugins/rclone/config
mkdir -p /var/lib/docker-plugins/rclone/cache
文档给了两种启动方式。socket 激活方式:
systemctl daemon-reload
systemctl start docker-volume-rclone.service
systemctl enable docker-volume-rclone.socket
systemctl start docker-volume-rclone.socket
systemctl restart docker
或直接启动 service:systemctl daemon-reload、systemctl enable docker-volume-rclone.service(开机自启)、systemctl start docker-volume-rclone.service、systemctl restart docker。最后一步是让 docker daemon 检测到新的插件 socket——托管模式下不需要这一步,因为 docker 自己知道插件状态变化。另外注意:如果之后改变监听 socket,必须重启 docker daemon 才会重新连接,重启前所有卷相关的 docker 命令都会超时等待旧 socket。
rclone serve docker 直接以命令行方式运行只支持 Linux,不支持 Windows 和 MacOS。默认监听 unix socket /run/docker/plugins/rclone.sock;若用 --socket-addr 指定 TCP 地址,rclone 会额外创建一个 /etc/docker/plugins/rclone.spec 小文件记录 socket 地址(文档中的测试示例):
sudo rclone serve docker --base-dir /tmp/rclone-volumes --socket-addr localhost:8787 -vv
创建卷:remote、type/path 与挂载参数
卷通过 docker volume create 创建,-d rclone 指定 rclone 驱动(即使插件是按全名 rclone/docker-volume-rclone 安装的,只要安装时给了 --alias rclone,就可以用短名):
docker volume create vol1 -d rclone -o remote=storj: -o vfs-cache-mode=full
docker volume create vol2 -d rclone -o remote=:storj,access_grant=xxx:heimdall
docker volume create vol3 -d rclone -o type=storj -o path=heimdall -o storj-access-grant=xxx -o poll-interval=0
文档给出了三种指定后端的方式:
remote(可别名fs,避免与 crypt、alias 这类后端自己的remote参数混淆):指向配置文件里已存在的 remote 名,带尾随冒号,可再带远端路径,如-o remote=storj:。remote=:backend:dir/subdir即时(无配置)语法,或等价的-o type=backend -o path=dir/subdir。path部分可省略。拆成两个选项在脚本里更方便参数化。- 后端参数直接作为
-o选项传入。规则是:去掉命令行的--前缀,短横线可以换成下划线。例如--vfs-cache-mode full写作-o vfs-cache-mode=full或-o vfs_cache_mode=full;无值布尔 flag 要补true,例如--allow-other写作-o allow-other=true。
一个限制要注意:参数只能给被 remote 直接引用的那个后端。如果它自身是 alias、chunker、crypt 这类包装后端,无法通过卷选项给它内部引用的远端传参——rclone 连接串解析器的限制。绕法是给插件喂 rclone.conf,或者用插件参数(args)设默认值。
如果所有选项都是静态的,甚至可以完全不跑 rclone config、不建 rclone.conf(但 config 目录仍须存在)。文档的 SFTP 示例:
docker volume create firstvolume -d rclone -o type=sftp -o sftp-host=_hostname_ -o sftp-user=_username_ -o sftp-pass=_password_ -o allow-other=true
其中 _hostname_、_username_、_password_ 是文档里的占位符,替换为你自己的主机名和 SSH 凭据(最简单可用 localhost);也可以加 -o path=/home/username 把远端路径改为主机家目录。
OAuth 类后端的 token 配置
像 Google Drive 这类需要 access token 的后端,token 可以通过浏览器设置并由 rclone 定期续期,但托管插件没有浏览器。文档的解法是在另一台带浏览器和图形界面的机器上运行 rclone config 建好 Google Drive remote,然后把生成的 rclone.conf 传到集群每台节点,保存为 /var/lib/docker-plugins/rclone/config/rclone.conf(该位置默认只有 root 可写)。文档中的配置示例:
[gdrive]
type = drive
scope = drive
drive_id = 1234567...
root_folder_id = 0Abcd...
token = {"access_token":...}
验证挂载结果
单机场景,创建一个测试容器把卷挂进去(ubuntu:latest 是文档示例镜像,--workdir /mnt 让 shell 直接落在挂载点):
docker run --rm -it -v firstvolume:/mnt --workdir /mnt ubuntu:latest bash
如果一切正常,你会进入新容器并且工作目录就是挂载的远端;容器内输入 ls 能看到远端目录内容,exit 退出后容器停止,但卷保留、可复用。
用 CLI 检查卷本身:
docker volume list
docker volume inspect vol1
Swarm 场景,文档用 example.yml(compose v3 格式)描述一个 heimdall 服务,卷声明如下:
version: '3'
services:
heimdall:
image: linuxserver/heimdall:latest
ports: [8080:80]
volumes: [configdata:/config]
volumes:
configdata:
driver: rclone
driver_opts:
remote: 'gdrive:heimdall'
allow_other: 'true'
vfs_cache_mode: full
poll_interval: 0
然后 docker stack deploy example -c ./example.yml 部署。几秒后 docker 会把栈分发到集群、在节点上创建 example_heimdall 服务(端口 8080),并向节点上的 rclone 插件请求 example_configdata 卷。验证命令:
docker service ls
docker service ps example_heimdall
docker volume ls
YAML 写法上有几个文档特别强调的坑:
- 布尔值必须加引号写成
'true'或"false",这两个词被 YAML 保留; remote值以冒号结尾时必须加引号,如remote: "storage_box:";- 含双引号和花括号的 JSON token 必须用单引号整体包住;
- YAML 里选项名习惯用
_而不是-。
另外注意:栈删除时(docker stack remove example)集群节点上按需创建的卷不会自动删除,需要逐节点手动 docker volume remove example_configdata。
用 healthcheck 验证挂载可用性
docker 卷插件协议没有让插件向 daemon 上报卷可用/不可用的通道。文档给出的替代做法是在消费容器上配 healthcheck 探测挂载点是否响应(/path/to/rclone/mount 替换为实际挂载路径):
services:
my_service:
image: my_image
healthcheck:
test: ls /path/to/rclone/mount || exit 1
interval: 1m
timeout: 15s
retries: 3
start_period: 15s
重启与升级插件
插件重启(例如 docker plugin disable rclone && docker plugin enable rclone、升级插件、主机重启)时,rclone 会读取 docker-plugin.state 文件,在后台恢复之前的卷和挂载;socket 本身会立刻开始提供服务,慢或不可达的远端不会卡住插件启动。
但有一个必须知道的后果:重启插件必然停掉并重建 FUSE 挂载进程。已经在运行、且在 rclone 卷上持有打开文件句柄的容器,会一直对着旧的死挂载,报 transport endpoint is not continuous(文档原文措辞为 transport endpoint is not connected),直到容器重启。文档的建议:
- 重启或升级插件后,把正在使用 rclone 卷的容器都重启一遍(如
docker restart <container>),或者提前停掉、事后启动; - 持续打开文件的应用受影响最大,文档点名了 Grafana、Prometheus、SQLite 类应用,应始终重启。
修改卷选项的坑
Docker CLI 没有 docker volume update。对已存在的卷重跑 docker volume create 并给新选项不会生效,也不报错,这是文档明确指出的 docker 陷阱。正确做法是先删再建:
docker volume remove my_vol
docker volume create my_vol -d rclone -o opt1=new_val1 ...
然后用 docker volume list 和 docker volume inspect my_vol 确认设置已更新。如果 docker 拒绝删除该卷,先找出使用它的容器或 swarm service 并停掉。
排查与安全边界
排查
文档给出的诊断顺序:
- 查看托管插件设置与状态:
docker plugin list、docker plugin inspect rclone(注意 docker 包括 20.10.7 在内只显示args的默认值,不显示实际值)。 - 插件输出进入 docker daemon 日志:
journalctl --unit docker。docker 会把插件行显示为 errors,实际级别要看封装在消息串里的内容。 - 打印插件内真实版本:
PLUGID=$(docker plugin list --no-trunc | awk '/rclone/{print$1}')
sudo runc --root /run/docker/runtime-runc/plugins.moby exec $PLUGID rclone version
甚至可以用 runc 进入插件容器的 shell:sudo runc --root /run/docker/runtime-runc/plugins.moby exec --tty $PLUGID bash。
- 用 curl 检查插件 socket 连通性(
PLUGID取自docker plugin list --no-trunc输出,需替换):
sudo curl -H Content-Type:application/json -XPOST -d {} --unix-socket /run/docker/plugins/$PLUGID/rclone.sock http://localhost/Plugin.Activate
- 最后手段:清除插件状态。文档特别警告——现有的 rclone docker 卷大概率都要重建,因为重装不清理状态文件正是为了便于恢复:
docker plugin disable rclone # disable the plugin to ensure no interference
sudo rm /var/lib/docker-plugins/rclone/cache/docker-plugin.state # removing the plugin state
docker plugin enable rclone # re-enable the plugin afterward
安全边界
- 插件 API 接受
remote(即fs)选项,解析方式与 rclone 连接串完全一致。连接串是受信任配置:可以带内联后端选项,而某些后端会用这些选项执行本地命令(文档举例 sftp 后端的ssh选项会拉起外部二进制)。任何能向插件 socket 发请求的人,都能以运行rclone serve docker的用户身份(通常是 root)执行任意命令。socket 访问要按这个级别对待,只暴露给可信调用方。 - 默认 unix socket
/run/docker/plugins/rclone.sock以0660创建,属主 root,属组为--socket-gid指定的组(默认取进程 GID),只有 root 和该组成员(通常就是 docker daemon)能访问。不要放宽权限,也不要把这个组给不受信用户。 - 用
--socket-addr监听 TCP socket 时没有认证,任何能打开该端口的人都可访问 API,文档要求绑定到 loopback 或其他可信地址并用防火墙保护。持有 docker daemon 访问权本身已等价于主机 root,这里的顾虑是把 socket 暴露得比 daemon 本身更广。
挂载方法选项
mount-type(别名 mount_type)决定挂载方式,一般取 mount、cmount 或 mount2 之一。注意:托管插件目前不支持 cmount,mount2 很少需要。该选项默认取第一个找到的方式,通常是 mount,一般不用显式指定。persist 是一个保留的布尔选项,文档说明其用途是将来允许把即时远端持久化到插件的 rclone.conf 中。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00