Files
danyang-match/infrastructure/docker-compose.staging.yml
T
WorkBuddy 797b1c46cf 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 直发客户端不可达)留待下一轮「改缺陷」处理。
2026-09-22 14:26:48 +08:00

148 lines
5.4 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Staging Docker Compose(预发环境,仅开发/测试)
version: '3.8'
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: danyang_match_staging
POSTGRES_USER: staging
POSTGRES_PASSWORD: staging_dev_password_change_me
ports:
- "5433:5432"
volumes:
- postgres_staging_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U staging -d danyang_match_staging"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6380:6379"
command: redis-server --appendonly yes --requirepass staging-redis-pass-change-me
volumes:
- redis_staging_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "staging-redis-pass-change-me", "ping"]
interval: 10s
timeout: 5s
retries: 5
seaweedfs:
# 同 docker-compose.yml:对象存储已从 MinIO 换成 SeaweedFS(钉 4.47)。
# staging 与本地/生产保持同一实现,避免「只有预发用的是另一套存储」这类偏差。
image: chrislusf/seaweedfs:4.47
container_name: danyang-match-staging-seaweedfs
# 必须覆盖 entrypoint:镜像 ENTRYPOINT 是 /usr/bin/weed,只写 command 会被追加成
# `weed sh -c ...` → `weed: unknown subcommand "sh"`(本地实测踩到)。
entrypoint: ["sh", "-c"]
command:
- |
cat > /tmp/s3cfg.json <<CFG
{"identities":[{"name":"app","credentials":[{"accessKey":"$${MINIO_ACCESS_KEY}","secretKey":"$${MINIO_SECRET_KEY}"}],"actions":["Admin","Read","Write","List","Tagging"]}]}
CFG
# -volume.max=100:bucket 名即 collection,默认上限 8 个 volume 只够一个 bucket
# (第二个桶写入会 InternalError)。详见 docker-compose.yml 中的说明。
exec weed server -s3 -s3.port=8333 -s3.config=/tmp/s3cfg.json -dir=/data -volume.max=100
environment:
MINIO_ACCESS_KEY: staging
MINIO_SECRET_KEY: staging_dev_password
ports:
# 与生产错开一位(8080/8081、5432/5433 同理):本地栈的 8333 已被占,故用 8334。
- "8334:8333"
- "9334:9333"
- "8889:8888"
volumes:
- seaweedfs_staging_data:/data
healthcheck:
test: ["CMD-SHELL", "code=$$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8333/); [ \"$$code\" = 200 ] || [ \"$$code\" = 403 ]"]
interval: 5s
timeout: 5s
retries: 24
storage-init:
# 同 docker-compose.yml:SeaweedFS 不自动建桶,必须预建 public / private。
image: chrislusf/seaweedfs:4.47
container_name: danyang-match-staging-storage-init
depends_on:
seaweedfs:
condition: service_healthy
entrypoint:
- sh
- -c
- |
for b in public private; do
code=$$(curl -s -o /dev/null -w '%{http_code}' "http://seaweedfs:8888/buckets/$$b/" || echo 000)
if [ "$$code" = "200" ]; then echo "bucket $$b: already exists"; continue; fi
i=0
while [ $$i -lt 30 ]; do
code=$$(curl -s -o /dev/null -w '%{http_code}' -X POST "http://seaweedfs:8888/buckets/$$b/" || echo 000)
case "$$code" in 200|201|409) break ;; esac
i=$$((i+1)); sleep 2
done
echo "bucket $$b: create -> $$code"
done
restart: "no"
backend:
build:
context: ../backend
dockerfile: Dockerfile
container_name: danyang-match-staging-backend
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
SPRING_PROFILES_ACTIVE: staging
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: danyang_match_staging
DB_USER: staging
DB_PASSWORD: staging_dev_password_change_me
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_PASSWORD: staging-redis-pass-change-me
MINIO_ENDPOINT: http://seaweedfs:8333
MINIO_ACCESS_KEY: staging
MINIO_SECRET_KEY: staging_dev_password
JWT_ACCESS_SECRET: staging-access-secret-dev-only
JWT_REFRESH_SECRET: staging-refresh-secret-dev-only
CHECKIN_TOKEN_SECRET: staging-checkin-secret-dev-only
ENCRYPTION_KEY: 32539f3d2fa8123dcec899cc3dbee7347034123a126ac22fcb4702e10c454d50
FEATURES_APPEAL_ENABLED: "true"
ports:
- "8081:8080"
healthcheck:
# 探针用 127.0.0.1 而非 localhost:busybox wget 解析 localhost 时可能优先取 ::1,
# 而服务若只绑 IPv4 会导致探针假失败(本地栈的 nginx 已实测踩到)。
test: ["CMD-SHELL", "curl -f http://127.0.0.1:8080/api/v1/health/ready || exit 1"]
interval: 30s
timeout: 10s
retries: 3
admin-web:
build:
context: ../admin-web
dockerfile: Dockerfile
container_name: danyang-match-staging-admin
depends_on:
- backend
ports:
# staging 与生产同机共存,全部端口按「生产 + 1」错开(5433/6380/8081/13521)。
# 生产管理端为 13520(admin-web/vite.config.ts + docker-compose.prod.yml),
# 故此处为 13521 —— 与 tests/uat/run-uat.sh 的 UAT_ADMIN_URL 默认值一致,
# 两处均由 ui-tests/ui-document-baseline-contracts.mjs 钉住。
# 管理端构建产物部署在 /admin/ 子路径下(见 admin-web/vite.config.ts 的 base),
# 故直连访问地址为 http://localhost:13521/admin/ 。
- "13521:80"
volumes:
postgres_staging_data:
redis_staging_data:
seaweedfs_staging_data: