Docker Compose 拓扑
docker-compose.yml 运行 API(fonrex-api)、数据库(db)和缓存(redis)。第四个服务 fonrex-migrate 按需执行迁移。docker compose exec 等命令使用服务名;docker exec 使用容器名(fonrex-db、fonrex-redis)。
┌───────────────────────────── docker compose ─────────────────────────────┐
│ │
│ fonrex-api ──────────► fonrex-db (TimescaleDB) │
│ :5000 127.0.0.1:5432, volume timescale_data │
│ │ │
│ └────────────────► fonrex-redis (Redis 7) │
│ 127.0.0.1:6379, volume redis_data │
│ │
│ fonrex-migrate (profile "migrate"): alembic upgrade head │
└──────────────────────────────────────────────────────────────────────────┘
服务
fonrex-api
- 镜像:基于
Dockerfile构建(Python 3.12,非 root 用户)。包含代码、Alembic 迁移脚本和种子文件(data/*.csv)。 - 端口:主机所有网络接口上的
5000,由 API 密钥保护。 - 启动(
entrypoint.sh):等待 PostgreSQL 和 Redis 就绪,执行alembic upgrade head,可选地导入data/etf.csv(SEED_ON_FIRST_RUN=true),然后以 Uvicorn worker 启动 Gunicorn(WEB_CONCURRENCY,默认为 1)。 - 配置:
.env(env_file)。DATABASE_URL、REDIS_URL和ASYNC_DATABASE_URL会被覆盖,使容器连接到db和redis服务,而不是localhost。 - 挂载:仅挂载应用需要写入的内容:
./logs和./static/logos。 - 健康检查:
curl -f http://localhost:5000/health。
db(容器 fonrex-db)
- 镜像:
timescale/timescaledb-ha:pg16(PostgreSQL 16 + TimescaleDB)。 - 端口:
127.0.0.1:5432,可从主机访问(psql、Zipline bundle),绝不对网络开放。 - 卷:
timescale_data,挂载到该镜像的数据目录/home/postgres/pgdata/data(PGDATA)。数据在docker compose down和重新构建后依然保留。 - 初始化:
postgres-init.sh创建fonrex数据库。
redis(容器 fonrex-redis)
- 镜像:
redis:7-alpine,--appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru。 - 端口:
127.0.0.1:6379(Redis 没有设置密码)。 - 作用:响应缓存、实时报价、WebSocket 流的 Pub/Sub 频道。
fonrex-migrate
- Profile:
migrate,不会随docker compose up启动。 - 命令:
alembic upgrade head。可用于在不启动 API 的情况下执行迁移。
常用操作
docker compose up -d # start
docker compose up -d --build # rebuild after a code update
docker compose logs -f fonrex-api # API logs
docker compose --profile migrate run --rm fonrex-migrate # migrations alone
docker compose down # stop, keep the data
docker compose down -v # stop and DELETE the database and cache volumes
开发:docker compose -f docker-compose.yml -f docker-compose.dev.yml up 会将项目文件夹挂载到 /app,因此修改代码后只需重启。
备份数据库
# Backup to one file on the host
docker compose exec -T db pg_dump -U fonrex -d fonrex -Fc > fonrex.dump
# Restore into an empty database
docker compose up -d db
docker compose exec -T db psql -U fonrex -d fonrex \
-c "CREATE EXTENSION IF NOT EXISTS timescaledb;" -c "SELECT timescaledb_pre_restore();"
docker compose exec -T db pg_restore -U fonrex -d fonrex -Fc < fonrex.dump
docker compose exec -T db psql -U fonrex -d fonrex -c "SELECT timescaledb_post_restore();"
docker compose up -d
请使用与生成备份时相同的 TimescaleDB 版本进行恢复。切勿将备份文件提交到 Git:其中包含您实例的数据。
故障排查
每个请求都返回 401 Missing API key 或 403
在 .env 中设置 FONREX_API_KEY,运行 docker compose up -d,并在每个请求中发送密钥。启动日志会说明身份验证模式:docker compose logs fonrex-api | grep -i auth。
logs 权限被拒绝
mkdir -p logs
chmod 777 logs
docker compose up -d
容器名已被占用
docker rm -f fonrex-db fonrex-redis fonrex-api
docker compose up -d
数据库未存放在卷上的旧安装
旧版本将卷挂载到 /var/lib/postgresql/data,而该镜像并不使用这个路径:数据库实际存放在容器内部。升级前请检查:
docker exec fonrex-db psql -U fonrex -d fonrex -tc "show data_directory"
docker inspect fonrex-db --format '{{range .Mounts}}{{.Destination}} {{end}}'
如果数据目录不是一个挂载目标,请在使用新的 docker-compose.yml 执行 docker compose up -d 之前备份数据库,然后再恢复。