Files
ystp/docs/deployment.md

5.3 KiB
Raw Blame History

部署指南

生产部署

仓库提供完整的 docker/Dockerfiledocker/docker-compose.prod.yml。生产编排包含 API、Worker、PostgreSQL 和 Redis数据库与 Redis 不发布宿主机端口API 和 Worker 使用同一上传卷,并以非 root、只读根文件系统运行。

环境要求

  • Linux x86_64
  • Docker Engine 26+ 与 Docker Compose 2.20+
  • 最低 2 核 CPU、4GB 内存;启用 AVIF 和独立 Worker 时建议 4 核、8GB 内存
  • 首次构建可访问 Docker Hub 与 crates.io

Debian 13、4 核 CPU、8GB 内存的实测起始值为 WORKER_CONCURRENCY=2IMAGE_PROCESSING_CONCURRENCY=2。AVIF 是 CPU 密集型编码,不要直接把并发设置为 CPU 核数的数倍。

首次启动

cp docker/.env.production.example .env.production
chmod 600 .env.production

# 分别生成 POSTGRES_PASSWORD、JWT_SECRET、API_KEY_PEPPER 和管理员密码。
# hex 不包含数据库 URL 与 .env 需要转义的保留字符。
openssl rand -hex 32

# 编辑公开地址和全部 replace-with-* 值后检查配置。
docker compose \
  --env-file .env.production \
  -f docker/docker-compose.prod.yml \
  config --quiet

docker compose \
  --env-file .env.production \
  -f docker/docker-compose.prod.yml \
  up -d --build

API 健康后 Worker 才会启动,避免两个进程在首次部署时同时执行迁移。

管理员可用邮箱或用户名登录。首次启动时设置 ADMIN_USERNAMEADMIN_PASSWORD 即可创建管理员;若未设置 ADMIN_EMAIL,系统会生成仅用于满足内部数据约束的 用户名@local.invalid 占位邮箱。确认账号创建后应从生产环境文件中移除 ADMIN_PASSWORD,避免每次重启都重置密码。

docker compose --env-file .env.production -f docker/docker-compose.prod.yml ps
curl --fail http://127.0.0.1:8080/health

预期健康响应:

{"status":"healthy","database":"connected","redis":"connected"}

更新与回滚

更新代码后保留 .env.production 和命名卷,重新构建并滚动重建:

git pull --ff-only
docker compose --env-file .env.production -f docker/docker-compose.prod.yml build api
docker compose --env-file .env.production -f docker/docker-compose.prod.yml up -d

生产镜像应使用不可变的 IMAGEFORGE_TAG。回滚时把该值改回上一镜像标签,然后再次运行 up -d

反向代理

直接通过服务器地址访问时保持 TRUST_PROXY_HEADERS=false。只有当 8080 端口不对客户端开放、所有请求都经过可信反向代理时,才设置为 true,并由代理覆盖 X-Forwarded-ForX-Forwarded-Proto

代理至少需要:

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    client_max_body_size 100m;
    proxy_read_timeout 300s;
}

日志与备份

docker compose --env-file .env.production -f docker/docker-compose.prod.yml logs -f api worker

docker compose --env-file .env.production -f docker/docker-compose.prod.yml \
  exec -T postgres pg_dump -U imageforge imageforge | gzip > imageforge.sql.gz

除数据库外,还要备份 Compose 的 uploads 命名卷。恢复前停止 API 与 Worker避免数据库记录与文件卷产生时间差。

本地开发

cp .env.example .env
docker compose -f docker/docker-compose.dev.yml up -d

# 终端 1
IMAGEFORGE_ROLE=api cargo run

# 终端 2
IMAGEFORGE_ROLE=worker cargo run

# 终端 3
cd frontend
npm ci
npm run dev

API 或 Worker 启动时会通过 SQLx 顺序执行尚未应用的迁移。迁移失败时进程退出,不会在不完整的数据库结构上继续提供服务。

压缩质量回归

基准工具会下载固定 Picsum 照片,分别生成 JPEG、PNG、WebP、AVIF 输入,再通过真实 HTTP API 测量目标达标率、格式签名、SSIM、PSNR、分辨率和耗时。

python3 -m venv .venv-benchmark
. .venv-benchmark/bin/activate
pip install -r scripts/requirements-benchmark.txt

python scripts/benchmark_compression.py generate --output-dir .bench/corpus

IMAGEFORGE_BENCH_EMAIL=admin@example.com \
IMAGEFORGE_BENCH_PASSWORD='replace-me' \
python scripts/benchmark_compression.py run \
  --base-url http://127.0.0.1:8080 \
  --input-dir .bench/corpus \
  --output-dir .bench/results \
  --formats jpeg,webp,avif \
  --rates 30,50,70 \
  --strict

--strict 会在请求失败、输出格式不匹配或目标体积未达标时返回非零退出码。测试素材与结果位于 .bench/,不会提交到 Git。

故障排查

# 容器与健康状态
docker compose --env-file .env.production -f docker/docker-compose.prod.yml ps

# 最近日志
docker compose --env-file .env.production -f docker/docker-compose.prod.yml logs --tail=200 api worker

# 数据库迁移状态
docker compose --env-file .env.production -f docker/docker-compose.prod.yml \
  exec -T postgres psql -U imageforge -d imageforge \
  -c 'SELECT version, success FROM _sqlx_migrations ORDER BY version;'

# 主机资源
docker stats
df -h

若图片压缩长时间排队,先检查 CPU再下调 IMAGE_PROCESSING_CONCURRENCY;若 API 健康但批量任务不推进,检查 Worker 日志和 Redis 状态。