S3 存储上的用户数据

S3 存储上的用户数据(Userdata on S3 Storage)

目录

Wavelog 把用户文件(QSL 卡、eQSL 卡、QSL 明信片图片)存放在 userdata 文件夹中,参见集中式用户数据。Wavelog 没有原生 S3 支持,但你可以把一个 S3 存储桶挂载为该文件夹上的文件系统。Wavelog 察觉不到其中的差别,也无需改动 config.php。

此方案适用于任何兼容 S3 的存储,例如 AWS S3、RustFS、Ceph RGW、Garage 或 Hetzner Object Storage。

信息(哪些文件夹适合放在 S3)

userdata 和 backup 很合适:文件写入一次,很少读取。按下面为 userdata 所示的方式挂载 backup,使用它自己的存储桶或前缀即可。

其他可写文件夹(application/config、application/logs、application/cache、uploads、updates)技术上也能在 S3 上工作,但不推荐。它们会在每次请求时被读取,或者经常被拆成小块写入,既慢又会产生大量 S3 请求。请把它们留在普通的数据卷上。

Linux 服务器

使用 rclone 挂载存储桶,并由 systemd 单元启动。示例假设系统为 Debian/Ubuntu,且 Wavelog 位于 /var/www/html,参见 Linux 安装。

1. 安装 rclone

sudo apt install rclone fuse3 ca-certificates

2. 配置 S3 远程

创建 /etc/rclone/rclone.conf,并用 sudo chmod 600 /etc/rclone/rclone.conf 使其仅对 root 可读:

[s3]
type = s3
provider = Other
endpoint = https://s3.example.com
access_key_id = YOUR_ACCESS_KEY
secret_access_key = YOUR_SECRET_KEY

把 provider 设置为与你的存储相匹配(AWS、Ceph、Other 等)。全部选项见 rclone S3 文档。

3. 创建 systemd 单元

创建 /etc/systemd/system/wavelog-userdata.service:

[Unit]
Description=Wavelog userdata on S3
Wants=network-online.target
After=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/rclone mount s3:wavelog-userdata /var/www/html/userdata \
  --config /etc/rclone/rclone.conf \
  --allow-other --uid 33 --gid 33 \
  --vfs-cache-mode writes
Restart=on-failure

[Install]
WantedBy=multi-user.target

在 Debian/Ubuntu 上,uid/gid 33 就是 www-data。其他发行版请用 id <user> 检查 Web 服务器用户。

4. 启动

sudo systemctl daemon-reload
sudo systemctl enable --now wavelog-userdata.service
findmnt /var/www/html/userdata

如果 userdata 中已经有文件,请在启动该单元之前运行 sudo mv /var/www/html/userdata /var/www/html/userdata.old && sudo mkdir /var/www/html/userdata,然后按迁移现有数据中所述把它们复制回来。

Docker

使用 rclone Docker 数据卷插件。它把存储桶挂载为 Docker 数据卷,因此容器配置保持不变。该插件只适用于 Linux 上的 Docker Engine,不适用于 Docker Desktop。

1. 安装插件

sudo mkdir -p /var/lib/docker-plugins/rclone/config /var/lib/docker-plugins/rclone/cache
docker plugin install rclone/docker-volume-rclone:amd64 args="-v" --alias rclone --grant-all-permissions

在 ARM 主机上请使用 :arm64 而不是 :amd64。

2. 配置 S3 远程

创建 /var/lib/docker-plugins/rclone/config/rclone.conf。这样凭据就不会出现在你的 compose 文件中。

[s3]
type = s3
# RustFS has no own provider in rclone, use Other
provider = Other
endpoint = https://s3.example.com
access_key_id = YOUR_ACCESS_KEY
secret_access_key = YOUR_SECRET_KEY

把 provider 设置为与你的存储相匹配(AWS、Ceph、Other 等)。全部选项见 rclone S3 文档。

3. 在 docker-compose.yml 中使用该数据卷

替换你的 docker-compose.yml 中 volumes: 部分的 wavelog-userdata 条目:

volumes:
  wavelog-userdata:
    driver: rclone
    driver_opts:
      remote: 's3:wavelog-userdata' # <- remote name from rclone.conf : bucket name
      allow_other: 'true'
      uid: '33'
      gid: '33'
      vfs_cache_mode: writes

在 Wavelog 容器内,uid/gid 33 就是 www-data。然后用 docker compose up -d 重建整个栈。

Kubernetes(实验性)

危险:实验性

在 Kubernetes 上使用 S3 是可行的,但有一个在生产环境中很要紧的缺点:如果 CSI 驱动 Pod 重启,Wavelog 就会失去对文件的访问,直到 Wavelog 的 Pod 也重启为止。见下文的驱动重启。生产环境中,普通的 ReadWriteMany 数据卷(CephFS、NFS 等)是更稳妥的选择。

使用瑞士数据科学中心(Swiss Data Science Center)提供的 CSI 驱动 csi-rclone 来替代块存储 PVC。它和上面的方案一样使用 rclone。额外的好处是数据卷为 ReadWriteMany,因此多个 Wavelog 副本可以共享同一份 userdata。

1. 安装驱动

helm repo add renku https://swissdatasciencecenter.github.io/helm-charts
helm install csi-rclone renku/csi-rclone --namespace csi-rclone --create-namespace

这会创建 StorageClass csi-rclone。全部选项见 chart 参数值。

驱动 Pod 以特权模式运行(FUSE)。如果你的集群强制执行 Pod Security Standards,请为命名空间打上 pod-security.kubernetes.io/enforce=privileged 标签。如果 NetworkPolicies 限制了出站流量,驱动 Pod 需要能访问 Kubernetes API 和你的 S3 端点。

2. 创建 Secret

驱动会从同一命名空间中与 PVC 同名的 Secret 读取 rclone 配置:

apiVersion: v1
kind: Secret
metadata:
  name: wavelog-userdata # must match the PVC name
  namespace: wavelog
type: Opaque
stringData:
  remote: s3
  remotePath: wavelog-userdata # bucket name, optionally with a prefix: bucket/prefix
  configData: |
    [s3]
    type = s3
    provider = Other
    endpoint = https://s3.example.com
    access_key_id = YOUR_ACCESS_KEY
    secret_access_key = YOUR_SECRET_KEY
  vfsOpt: '{"UID": 33, "GID": 33, "DirCacheTime": "5s", "CacheMode": "writes"}'
  • remotePath 按原样挂载。如果你删除并重建 PVC,它会重新找到自己的数据。驱动从不会删除存储桶中的数据。
  • vfsOpt 以 JSON 形式接收 rclone VFS 选项。UID/GID 33 是 Wavelog 镜像内的 www-data。
  • DirCacheTime 是 rclone 缓存目录列表的时长(默认 1 分钟)。在有多个 Wavelog 副本时,刚上传的 QSL 卡在这段时间内对其他副本不可见,并会返回 404。几秒钟是在延迟与 S3 请求数量之间不错的折中。
  • 这些选项在挂载数据卷时读取。要修改它们,请编辑 Secret 并重启 Wavelog 的 Pod。

3. 创建并挂载 PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wavelog-userdata
  namespace: wavelog
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: csi-rclone
  resources:
    requests:
      storage: 10Gi # ignored by S3, but required by Kubernetes

在你的 Wavelog Deployment 中:

spec:
  template:
    spec:
      containers:
        - name: wavelog
          volumeMounts:
            - name: userdata
              mountPath: /var/www/html/userdata
      volumes:
        - name: userdata
          persistentVolumeClaim:
            claimName: wavelog-userdata

警告:多个副本

即使 DirCacheTime 很短,新文件也需要几秒钟才会出现在其他副本上,因为 rclone 是在文件写入之后稍晚才上传它。Ingress 控制器上的会话保持(sticky sessions)会把每个用户送到同一个副本,因此上传者能立刻看到该文件。

注意(Mountpoint for Amazon S3)

不推荐使用 AWS 的 CSI 驱动「Mountpoint for Amazon S3」。默认情况下它无法覆盖或删除文件,而这正是 Wavelog 需要的功能。

驱动重启

rclone 运行在驱动的节点 Pod(csi-rclone-nodeplugin)内。如果该 Pod 重启,该节点上的所有挂载都会消失。该节点上的 Wavelog Pod 仍在运行,但 userdata 会以 Transport endpoint is not connected 报错:QSL 图片返回错误,上传也会失败。Kubernetes 不会重新挂载正在运行的 Pod 的数据卷,只重启容器同样无济于事。整个 Pod 必须重建。这是基于 FUSE 的 CSI 驱动的普遍限制。

出现这种情况的时机:

  • 驱动升级: DaemonSet 会立即替换所有驱动 Pod,运行着 Wavelog Pod 的节点也不例外。这是最主要的原因。
  • 驱动崩溃: 比较少见,例如 rclone 守护进程未通过存活探针时。
  • 节点重启或排空: 影响不大,Wavelog Pod 本来就会被重启或迁移。

驱动重启后,请重建 Wavelog 的 Pod:

kubectl -n wavelog rollout restart deployment/wavelog

为避免升级时意外重启,可把驱动 DaemonSet 的更新策略设为 OnDelete。这样新的驱动版本只会在其 Pod 被删除时才推出,例如在下一次节点排空时——那时 Wavelog 的 Pod 本来就要迁移。chart 中没有对应的参数值,请使用 Helm post-renderer 或直接给 DaemonSet 打补丁:

kubectl -n csi-rclone patch daemonset csi-rclone-nodeplugin -p '{"spec":{"updateStrategy":{"type":"OnDelete"}}}'

helm upgrade 会重置手动打的补丁,因此 post-renderer 才是永久的解决方案。

注意事项

警告

  • 延迟: 每次文件访问都要经过网络。对 QSL 图片来说这没问题,请保持缓存选项开启。
  • 权限: Web 服务器以 www-data(uid/gid 33)运行。若 uid/gid 不正确,Wavelog 无法写入该文件夹。
  • PUID/PGID: 如果你在 Wavelog 容器上设置了 PUID/PGID,请在挂载时使用相同的 uid/gid 值。否则容器会在启动时尝试对挂载的文件夹执行 chown,这在 S3 上会失败,容器也就无法启动。
  • 保持存储桶私有: 文件由 Wavelog 自己提供。存储桶不需要任何公开访问权限。

迁移现有数据

  1. 启用维护模式。
  2. 备份当前的 userdata 文件夹。
  3. 用新的 S3 数据卷启动 Wavelog,并把旧数据复制进去:
    • Linux 服务器:sudo cp -r /var/www/html/userdata.old/. /var/www/html/userdata/
    • Docker:docker cp ./userdata/. wavelog-main:/var/www/html/userdata/
    • Kubernetes:kubectl cp ./userdata/. <wavelog-pod>:/var/www/html/userdata/
  4. 进入管理 > 调试,确认 userdata 显示为可写。
  5. 在 Web 界面中打开几张 QSL 卡和 eQSL 卡,上传一张测试 QSL 卡,然后再删除它。
  6. 关闭维护模式。
Wavelog 手册(中文版) / S3 存储上的用户数据 0 字 0 行 bg8lng
2026-10-21T12:42:36.030174883Z 2026-10-21T12:43:40.518152725Z