refactor(storage): 对象存储从 MinIO 换成 SeaweedFS(钉 4.47)

动机:MinIO 的 GitHub 仓库已于 2026-02 归档,不再产出安全补丁,已累积多个
CVE 且不修;本项目存身份证 / 实名材料 / 用户照片,无人修 CVE 才是真正驱动因素
(Docker Hub 下架只是表象,quay.io 仍在提供)。

变更:
- 三套 compose(dev / staging / prod)的 minio 服务替换为 seaweedfs 4.47:
  覆盖 entrypoint 渲染 -s3.config 注入 identity(S3 网关默认不鉴权,必须显式开启),
  -volume.max=100 解除第二个 bucket 写入时的 InternalError。
- 新增一次性 storage-init 容器,经 filer 接口预建 public / private 桶
  (SeaweedFS PutObject 到不存在的 bucket 直接失败;全仓库原无任何 createBucket)。
- S3Config 显式开启 path-style:AWS SDK v1 默认 virtual-host 会把 bucket 拼进
  主机名,容器名在 DNS 中不存在必然失败(本机有 http_proxy 时易误判为 502 拒绝)。
- ci.yml:镜像校验与起栈步骤改为 seaweedfs + storage-init。
- 运维脚本 health-check.sh / run-uat.sh 的 MinIO 探针改为 SeaweedFS
  (S3 网关开启鉴权后匿名根请求返回 403,200/403 均算存活)。

注:path-style 与建桶属换存储的必要项;presigned URL 的 host 须对外可达这一
既有缺陷(原 minio:9000 直发客户端不可达)留待下一轮「改缺陷」处理。
This commit is contained in:
WorkBuddy
2026-09-22 14:26:48 +08:00
parent aa1114338e
commit 797b1c46cf
8 changed files with 249 additions and 76 deletions
@@ -37,6 +37,21 @@ public class S3Config {
new AwsClientBuilder.EndpointConfiguration(endpoint, region))
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials(accessKey, secretKey)))
// 必须显式开启 path-style。
//
// AWS SDK v1 默认是 virtual-host 风格,会把 bucket 拼进主机名:
// endpoint=http://seaweedfs:8333 -> http://private.seaweedfs:8333/...
// 而 `seaweedfs` 是 Docker 内部服务名,`private.seaweedfs` 没有任何 DNS 记录,
// 请求必然失败。private 部署的对象存储几乎都用 IP 或容器名,
// virtual-host 天然不可用 —— path-style(http://host:port/bucket/key)才是正解。
//
// 这一点在换存储前就已埋着:MinIO 时代之所以没暴露,是因为对象存储链路
// 从未被任何测试真正走过(E2E 对存储零覆盖),而不是因为配置正确。
//
// 排查提醒:本机有 http_proxy 时,*.localhost 这类 virtual-host 域名
// 不在 NO_PROXY 内会走代理并返回 502,看起来像「存储不支持」,
// 实为代理假象 —— 判据里 502 不能当作「被拒绝」。
.withPathStyleAccessEnabled(true)
.build();
}
}