Docker Volume Plugin
简介
Docker 1.9 增加了对通过命令行界面创建命名卷并将其挂载到容器中,以此在容器之间共享数据的支持。
从 Docker 1.10 开始,你可以使用 Docker Compose,通过 docker-compose.yml 文件中的描述来创建命名卷,供单主机上的容器组使用。
从 Docker 1.12 起,Docker Swarm(包含在 Docker 引擎中)开始支持卷,这些卷可以根据 swarm compose v3 文件中的描述创建,用于跨多个集群节点的 swarm 堆栈。
Docker 卷插件 为 Docker 中默认的 local
卷驱动程序增添了跨容器和主机共享的有状态卷。与本地卷不同,当移除这种卷时,你的数据不会被删除。插件可以由 Docker 守护进程管理运行,也可以作为原生系统服务(在 systemd、sysv 或 upstart 下)运行,或者作为独立的可执行文件运行。
Rclone 可以以所有这些模式作为 Docker 卷插件运行。它通过 插件 API 与本地 Docker 守护进程进行交互,并处理将远程文件系统挂载到 Docker 容器中的操作,因此它必须与 Docker 守护进程运行在同一主机上,或者在每个 Swarm 节点上运行。
入门指南
在第一个示例中,我们将在独立的 Ubuntu 机器上使用 Docker 引擎,搭配 SFTP 的 rclone 卷。
首先要在主机上安装 Docker。
FUSE 驱动程序是 rclone 挂载的先决条件,应该在主机上安装:
sudo apt-get -y install fuse
Create two directories required by rclone docker plugin:
sudo mkdir -p /var/lib/docker-plugins/rclone/config
sudo mkdir -p /var/lib/docker-plugins/rclone/cache
Install the managed rclone docker plugin for your architecture (here amd64
):
docker plugin install rclone/docker-volume-rclone:amd64 args="-v" --alias rclone --grant-all-permissions
docker plugin list
Create your SFTP volume:
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
请注意,由于所有选项都是静态的,你甚至无需运行 rclone config
命令或创建 rclone.conf
文件(但 config
目录仍需存在)。在最简单的情况下,你可以使用 localhost
作为 主机名,并使用你的 SSH 凭证作为 用户名 和 密码。
你还可以将远程路径更改为主机上的主目录,例如 -o path=/home/username
。
现在是时候创建一个测试容器并将卷挂载到其中了:
docker run --rm -it -v firstvolume:/mnt --workdir /mnt ubuntu:latest bash
.
如果一切顺利,你将进入新容器并直接切换到已挂载的 SFTP 远程目录。你可以输入 ls
命令列出已挂载目录的内容,或者进行其他操作。完成后,输入 exit
。
容器将停止运行,但卷会保留,随时可以再次使用。
当不再需要该卷时,将其移除:
docker volume list
docker volume remove firstvolume
现在,让我们尝试一些更复杂的操作:在多节点 Docker Swarm 上使用 Google Drive 卷。
你应该从在 每个 Swarm 节点上安装 Docker 和 FUSE、创建插件目录并安装 rclone 插件开始。 然后 设置 Swarm。
Google Drive 卷需要一个访问令牌,该令牌可以通过 Web 浏览器设置,并且会由 rclone 定期更新。由于托管插件无法运行浏览器,因此我们将使用类似于 在无图形界面的设备上设置 rclone 的技术。
在另一台配备 Web 浏览器 和图形用户界面的机器上运行 rclone config。
创建 Google Drive 远程存储。
完成后,将生成的 rclone.conf
文件传输到 Swarm 集群,并保存为 /var/lib/docker-plugins/rclone/config/rclone.conf
,保存到 每个 节点上。默认情况下,此位置仅对 root 用户可访问,因此你需要相应的权限。生成的配置文件将如下所示:
[gdrive]
type = drive
scope = drive
drive_id = 1234567...
root_folder_id = 0Abcd...
token = {"access_token":...}
现在,创建一个名为 example.yml
的文件,内容为如下所示的 Swarm 堆栈描述:
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
and run the stack:
docker stack deploy example -c ./example.yml
几秒钟后,Docker 会将解析后的堆栈描述分发到集群中,在端口 8080 上创建 example_heimdall
服务,在一个或多个集群节点上运行服务容器,并向节点主机上的 rclone 插件请求 example_configdata
卷。
你可以使用以下命令来确认结果:
docker service ls
docker service ps example_heimdall
docker volume ls
将你的浏览器指向 http://集群主机地址:8080
,并体验该服务。完成后,使用 docker stack remove example
停止服务。
请注意,在集群节点上按需创建的 example_configdata
卷不会随堆栈一起自动删除,而是会保留以供将来重用。你可以通过在每个节点上执行 docker volume remove example_configdata
命令来手动删除它们。
通过命令行界面创建卷
可以使用 docker volume create 命令来创建卷。以下是一些示例:
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
请注意 -d rclone
标志,它告诉 Docker 从 rclone 驱动程序请求卷。即使你使用完整名称 rclone/docker-volume-rclone
安装了托管驱动程序,这也能正常工作,因为你提供了 --alias rclone
选项。
可以按以下方式检查卷:
docker volume list
docker volume inspect vol1
卷配置
Rclone 标志和卷选项通过 docker volume create
命令的 -o
标志进行设置。这些选项包括后端特定的参数,以及挂载和 VFS 选项。此外,还有一些特殊的 -o
选项:
remote
、fs
、type
、path
、mount-type
和 persist
。
remote
用于指定配置文件中现有的远程存储名称,后面需跟冒号,还可选择性地添加远程路径。完整的语法请参考 rclone 文档。
为避免与 crypt 或 alias 等后端的 remote 参数混淆,此选项可别名为 fs
。
remote=:backend:dir/subdir
语法可用于创建 即时(无配置)远程存储,而 type
和 path
选项则提供了一种更简单的替代方法。使用以下两个分开的选项
-o type=backend -o path=dir/subdir
is equivalent to the combined syntax
-o remote=:backend:dir/subdir
但在脚本中,它的参数化可能更容易。path
部分是可选的。
挂载和 VFS 选项 以及 后端参数 的命名方式与它们对应的命令行标志相同,但去掉了 --
命令行前缀。你也可以选择在选项名称中使用下划线而不是连字符。例如,--vfs-cache-mode full
变为 -o vfs-cache-mode=full
或 -o vfs_cache_mode=full
。
无值的布尔型命令行标志将被赋予 true
值,例如 --allow-other
变为 -o allow-other=true
或 -o allow_other=true
。
请注意,你只能为挂载的 remote
后端类型直接引用的后端提供参数。如果这是一个包装后端,如 alias、chunker 或 crypt,你不能为被引用的远程存储或后端提供选项。此限制是由 rclone 连接字符串解析器施加的。唯一的解决方法是向插件提供 rclone.conf
文件或配置插件参数(见下文)。
特殊卷选项
mount-type
决定了挂载方法,通常可以是以下之一:mount
、cmount
或 mount2
。它可以别名为 mount_type
。需要注意的是,托管的 rclone Docker 插件目前不支持 cmount
方法,并且 mount2
很少使用。此选项默认为找到的第一种方法,通常是 mount
,因此你通常不需要设置它。
persist
是一个保留的布尔型(true/false)选项。未来,它将允许在插件的 rclone.conf
文件中持久保存即时远程存储。
连接字符串
remote
值可以通过 连接字符串 进行扩展,作为提供后端参数的另一种方式。这与 -o
后端选项等效,但有一个 语法差异。在连接字符串中,参数名称必须去掉后端前缀,但在 -o param=value
数组中必须包含。例如,比较以下选项数组
-o remote=:sftp:/home -o sftp-host=localhost
with equivalent connection string:
-o remote=:sftp,host=localhost:/home
这种差异的存在是因为标志选项 -o key=val
不仅包含后端参数,还包含挂载/VFS 标志以及可能的其他设置。此外,它还允许将 remote
选项与 crypt-remote
(或类似命名的后端参数)区分开来,并且由于更清晰的值替换,在脚本编写方面可能会更简单。
与 Swarm 或 Compose 一起使用
Docker Swarm 和 Docker Compose 都使用 YAML 格式的文本文件来描述容器组(堆栈)、它们的属性、网络和卷。 Compose 使用 compose v2 格式, Swarm 使用 compose v3 格式。 它们大多相似,差异在 Docker 文档 中有解释。
卷由顶级 volumes:
节点的子节点描述。
每个卷都应该以其卷名命名,并且至少有两个元素,一个是显而易见的 driver: rclone
值,另一个是 driver_opts:
结构,其作用与 -o key=val
命令行标志相同:
volumes:
volume_name_1:
driver: rclone
driver_opts:
remote: 'gdrive:'
allow_other: 'true'
vfs_cache_mode: full
token: '{"type": "borrower", "expires": "2021-12-31"}'
poll_interval: 0
请注意几个重要细节:
- YAML 更倾向于在选项名称中使用
_
而非-
。 - YAML 对单引号和双引号的处理是一样的。简单的字符串和整数可以不使用引号。
- 布尔值必须用引号引起来,如
'true'
或"false"
,因为这两个词是 YAML 中的保留字。 - 文件系统字符串使用
remote
(或fs
)作为键。通常这里可以省略引号,但如果字符串以冒号结尾,则 必须 像remote: "storage_box:"
这样用引号引起来。 - YAML 对值中的大括号很敏感,因为这实际上是另一种 键/值映射的语法。例如,JSON 访问令牌通常包含双引号和大括号,所以必须将它们放在单引号中。
作为托管插件安装
Docker 守护进程可以从镜像仓库安装插件并对其进行管理。 我们在 Docker Hub 上维护了 docker-volume-rclone 插件镜像。
Rclone 卷插件要求 Docker 引擎版本 >= 19.03.15
在安装插件之前,主机上需要存在两个目录。请注意,插件 不会 自动创建这些目录。默认情况下,它们必须存在于主机的以下位置(不过你可以调整路径):
/var/lib/docker-plugins/rclone/config
用于存放rclone.conf
配置文件,必须 存在,即使它是空的且配置文件不存在也一样。/var/lib/docker-plugins/rclone/cache
用于存放插件状态文件以及可选的 VFS 缓存。
你可以按照以下方式使用默认设置 安装托管插件:
docker plugin install rclone/docker-volume-rclone:amd64 --grant-all-permissions --alias rclone
镜像规格中冒号后面的 :amd64
部分被称为 标签。
通常,你会希望为你的架构安装最新的插件。在这种情况下,标签只是用来标识架构,就像上面的 amd64
。目前可用的插件架构如下:
amd64
arm64
arm-v7
有时你可能需要特定版本的插件,而不是最新版本。
那么你应该使用 :架构-版本
形式的镜像标签。
例如,要在 arm64
架构上安装 v1.56.2
版本的插件,你将使用标签 arm64-1.56.2
(注意去掉了 v
),因此完整的镜像规格变为 rclone/docker-volume-rclone:arm64-1.56.2
。
我们还提供了 latest
插件标签,但截至撰写本文时,Docker 不支持多架构插件,因此这个标签目前 是 amd64
的别名。
按照惯例,latest
标签是默认标签,可以省略,因此 rclone/docker-volume-rclone:latest
和 rclone/docker-volume-rclone
都将指向 amd64
平台的最新插件版本。
此外,带版本号的 rclone 插件标签中可以省略 amd64
部分。
例如,rclone 镜像引用 rclone/docker-volume-rclone:amd64-1.56.2
可以方便地缩写为 rclone/docker-volume-rclone:1.56.2
。
但是,对于非英特尔架构,你仍然必须使用完整的标签,因为 amd64
或 latest
可能无法启动。
托管插件实际上是一个在与普通 Docker 容器分离的命名空间中运行的特殊容器。在其中运行 rclone serve docker
命令。配置和缓存目录在启动时会被绑定挂载到容器中。Docker 守护进程会连接到容器内该命令创建的 Unix 套接字。该命令会在容器内按需创建远程挂载,然后 Docker 机制会通过内核挂载命名空间将它们传播并绑定挂载到请求的用户容器中。
在安装后且插件处于禁用状态(未使用)时,你可以调整一些插件设置,例如:
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
请注意,如果 Docker 拒绝禁用插件,你应该找到并移除所有与之关联的活动卷,以及使用这些卷的容器和 Swarm 服务。这相当繁琐,因此请提前仔细规划。
你可以调整以下设置:
args
、config
、cache
、HTTP_PROXY
、HTTPS_PROXY
、NO_PROXY
和 RCLONE_VERBOSE
。
你需要确保插件设置在 Swarm 集群节点之间保持同步。
args
为 rclone serve docker
命令设置命令行参数(默认 无)。参数应该用空格分隔,因此在 docker plugin set 命令行中,你通常需要将它们放在引号内。serve docker 标志 和 通用 rclone 标志 都支持,包括将用作卷创建默认值的后端参数。
请注意,由于 这个 Docker 漏洞,如果 args
值为空,插件将失败。可以使用例如 args="-v"
作为解决方法。
config=/host/dir
为配置目录设置替代的主机位置。
插件将在此处查找 rclone.conf
文件。如果配置文件不存在,这不是错误,但目录必须存在。请注意,插件可能会定期重写配置文件,例如在更新存储访问令牌时。请记住这一点,并尽量避免插件与主机上可能尝试同时更改配置的其他 rclone 实例之间发生冲突,以免导致 rclone.conf
文件损坏。
你还可以将 SFTP 远程存储的私钥文件等内容放在此目录中。只需注意,它会在插件容器内以预定义路径 /data/config
进行绑定挂载。例如,如果你的密钥文件在主机上名为 sftp-box1.key
,则相应的卷配置选项应写为 -o sftp-key-file=/data/config/sftp-box1.key
。
cache=/host/dir
为 缓存 目录设置替代的主机位置。
插件将在此处保存 VFS 缓存。此外,它还会在此目录中创建并维护 docker-plugin.state
文件。当插件重新启动或重新安装时,它将查看此文件以重新创建之前存在的任何卷。但是,重启后这些卷不会重新挂载到使用它们的容器中。通常这不是问题,因为 Docker 守护进程通常会在出现故障、守护进程重启或主机重新启动后重启受影响的用户容器。
RCLONE_VERBOSE
将插件的详细程度从 0
(默认仅显示错误)设置为 2
(调试模式)。详细程度也可以通过 args="-v [-v] ..."
进行调整。由于参数更通用,你很少需要使用此设置。
默认情况下,插件输出会被发送到本地主机的 Docker 守护进程日志中。日志条目在 Docker 日志中显示为 错误,但在封装的消息字符串中保留 rclone 分配的实际级别。
HTTP_PROXY
、HTTPS_PROXY
、NO_PROXY
用于自定义插件的代理设置。
你可以在安装插件时一次性设置自定义插件选项:
docker plugin remove rclone
docker plugin install rclone/docker-volume-rclone:amd64 \
--alias rclone --grant-all-permissions \
args="-v --allow-other" config=/etc/rclone
docker plugin inspect rclone
健康检查
docker 插件卷协议并没有提供一种方法让插件 通知 docker 守护进程某个卷不可用。 作为一种变通办法,你可以设置一个健康检查来验证挂载的卷是否可用。 是否响应,例如
services:
my_service:
image: my_image
healthcheck:
test: ls /path/to/rclone/mount || exit 1
interval: 1m
timeout: 15s
retries: 3
start_period: 15s
在 Systemd 下运行插件
在大多数情况下,你应该优先选择托管模式。此外,macOS 和 Windows 不支持原生 Docker 插件。请在这些系统上使用托管模式。只有当你使用的是 Linux 系统时,才继续往下操作。
首先,安装 rclone。
你可以直接运行它(输入 rclone serve docker
并回车)进行测试。
安装 FUSE:
sudo apt-get -y install fuse
Download two systemd configuration files: docker-volume-rclone.service and docker-volume-rclone.socket.
Put them to the /etc/systemd/system/
directory:
cp docker-volume-plugin.service /etc/systemd/system/
cp docker-volume-plugin.socket /etc/systemd/system/
Please note that all commands in this section must be run as root but
we omit sudo
prefix for brevity.
Now create directories required by the service:
mkdir -p /var/lib/docker-volumes/rclone
mkdir -p /var/lib/docker-plugins/rclone/config
mkdir -p /var/lib/docker-plugins/rclone/cache
Run the docker plugin service in the socket activated mode:
systemctl daemon-reload
systemctl start docker-volume-rclone.service
systemctl enable docker-volume-rclone.socket
systemctl start docker-volume-rclone.socket
systemctl restart docker
或者直接运行服务:
- 运行
systemctl daemon-reload
让 systemd 加载新配置。 - 运行
systemctl enable docker-volume-rclone.service
使新服务在机器开机时自动启动。 - 运行
systemctl start docker-volume-rclone.service
立即启动服务。 - 运行
systemctl restart docker
重启 Docker 守护进程,让它检测新的插件套接字。请注意,在托管模式下不需要这一步,因为 Docker 可以感知插件状态的变化。
从用户的角度来看,这两种方法是等效的,但我个人更喜欢套接字激活方式。
故障排除
你可以通过以下命令查看托管插件的设置:
docker plugin list
docker plugin inspect rclone
请注意,Docker(包括最新的 20.10.7 版本)不会显示 args
的实际值,只会显示默认值。
使用 journalctl --unit docker
命令,将托管插件的输出作为 Docker 守护进程日志的一部分查看。请注意,Docker 会将插件的日志行显示为 错误,但可以从封装的消息字符串中查看其实际日志级别。
通常,你会为你的平台安装最新版本的托管插件。 使用以下命令打印实际安装的版本:
PLUGID=$(docker plugin list --no-trunc | awk '/rclone/{print$1}')
sudo runc --root /run/docker/runtime-runc/plugins.moby exec $PLUGID rclone version
You can even use runc
to run shell inside the plugin container:
sudo runc --root /run/docker/runtime-runc/plugins.moby exec --tty $PLUGID bash
Also you can use curl to check the plugin socket connectivity:
docker plugin list --no-trunc
PLUGID=123abc...
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
注意事项
最后,我想提一下更新卷设置的注意事项。
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 ...
and verify that settings did update:
docker volume list
docker volume inspect my_vol
如果 docker 拒绝移除卷,你应该找到容器 或 swarm 服务,并先停止它们。