CapRover

无状态应用 + 持久化数据

开始之前,请先阅读:

本文档将帮助你搭建“无状态应用 + 持久化数据”的方案。例如:使用 "php:7.4-apache" 托管的网站,将 "uploads"(/var/www/html/uploads)目录(或你自定义的其他目录)存放到 AWS、Wasabi S3 等对象存储,或任何其他 rclone 支持的存储系统。这样一来,原本可能被固定在某个节点(例如节点 X)上的应用,也可以在同一个 Docker swarm 内故障切换到其他节点。

为了实现上述方案,可以使用多种 Docker volume 插件。我 @Daniël 和同事 Floris 一开始使用的是 "rexray/s3fs",后来因为 "sapk/plugin-rclone" 更稳定、且更擅长处理从节点 X 切换到节点 Y 的故障转移,于是改用了它。


**重要说明:**以下步骤适用于中级与高级(Linux)用户。


占位变量

  • $volumename 例如可以是 captain--yourappname-rclone
  • $remotename 例如可以是 captain--yourappname
  • $remotename/path 例如可以是 captain--yourappname/_data
  • $rcloneremotename 例如可以是 wasabi-s3

1) 准备 rclone

首先创建 rclone.conf 文件,你可以在任何安装了 rclone 的(本地)机器上完成。 为方便说明,本文档假设你已在 Docker swarm 的主节点上 安装 rclone

在主节点上运行 "rclone config" 来创建配置文件,完成后再运行 rclone config file 以查看配置文件的存放位置。 如果你使用 root 用户,它通常会存放在 /root/.config/rclone/rclone.conf,后续内容将以此路径作为参考。

rclone.conf 文件大致如下所示:

[$rcloneremotename]
type = s3
provider = Wasabi
access_key_id = YourAccessKey
secret_access_key = YourSecretAccessKey
region = eu-central-1
endpoint = s3.eu-central-1.wasabisys.com
env_auth = false
upload_cutoff = 25M
chunk_size = 5M
disable_checksum = false
upload_concurrency = 3

确保每个 swarm 节点都存在 /root/.config/rclone/rclone.conf,并且内容完全一致;你可以通过 md5sum /root/.config/rclone/rclone.conf 对比校验和来确认。 或者至少确保在存在多个配置时,你实际使用的那份配置在所有节点上是一致的。

2) 准备存储系统

确保你的 S3 bucket(或你在 rclone config 中配置的存储系统上将要使用的目录)实际存在,并且 bucket/目录名与 $remotename 一致。

3) 准备 Docker rclone 插件

在每个 swarm 节点上,通过 docker plugin install sapk/plugin-rclone 安装 Docker volume 插件。

然后在每个节点上执行下面的命令。以下命令是专为 "php:N.N-apache" 容器准备的(例如 php:7.4-apache)。

docker volume create --driver sapk/plugin-rclone --opt config="$(base64 /root/.config/rclone/rclone.conf)" --opt args="--uid 33 --gid 33 --allow-root --allow-other" --opt remote=$rcloneremotename:$remotename/path --name $volumename

如果你使用的是 S3 bucket,且文件会通过 AWS/Wasabi 的 Web 界面或其他方式(例如将 SFTPGo 挂载到 S3 bucket)上传,那么你需要让 rclone 刷新其目录缓存:

docker volume create --driver sapk/plugin-rclone --opt config="$(base64 /root/.config/rclone/rclone.conf)" --opt args="--uid 33 --gid 33 --allow-root --allow-other --dir-cache-time 5s" --opt remote=$rcloneremotename:$remotename/path --name $volumename

其工作方式是:通过 "rclone mount" 将 volume 挂载到 Docker swarm 节点上。不过需要注意,其他参数/标志位可能会改善或降低你的应用体验,因此建议在使用过程中进行充分测试。

上面的 UID 与 GID 是为 Apache2 匹配的;对于其他应用可能需要使用不同的值。

4) 准备应用

接下来部署一个空白应用,并确保 "Has Persistent Data" 未勾选,然后在 "HTTP Settings"、"App Configs" 与 "Deployment" 标签页中按需配置参数。

在 "App Configs" 的 "Service Update Override" 区域,填入如下内容。 注意:/var/www/html/uploads 是示例路径/目录,你应根据自己的应用情况自行定义,这里仅作参考。

根据你的应用需求,将 "ReadOnly" 设置为 truefalse。 如果你的 PHP 应用允许用户上传文件,请将其设为 false

TaskTemplate:
  ContainerSpec:
    Mounts: [
      {
        "Type": "volume",
        "Source": "$volumename",
        "Target": "/var/www/html/uploads",
        "ReadOnly": false
      }
    ]

这样运行在 "php:7.4-apache" 上的应用就可以从 node1 迁移到任何已正确配置的其他节点上。

如果你有问题或遇到故障,请在 Slack 的 General 频道联系;如有需要可以 @ 我 @Daniël,我或其他人会尽力协助你解决。