用 Docker Compose 启动 FastAPI、PostgreSQL 和 Redis
码海寻道 · AI 算法工程化与系统落地实战第 5 篇
一个算法服务真正接入业务后,通常至少需要保存三类信息:请求和任务状态、算法结果、短期缓存或限流数据。FastAPI 负责接口,PostgreSQL 负责业务事实,Redis 负责速度和短期状态。本文用 Docker Compose 把三者启动起来,形成一个可以本地联调的基础环境。
一、三个组件怎么分工?
FastAPI:接收请求、鉴权、参数校验、调用算法 PostgreSQL:任务、结果、模型版本、审计记录 Redis:缓存、限流、短期锁、进度加速读取Redis 不是 PostgreSQL 的替代品。任务最终状态、推理结果和需要长期保存的数据应该进入 PostgreSQL;Redis 中的数据即使丢失,也应能够从数据库或任务系统恢复。
二、项目准备
algorithm-stack/ ├── app/ │ ├── main.py │ ├── config.py │ └── routes.py ├── requirements.txt ├── Dockerfile ├── compose.yaml └── .env.example依赖:
fastapi uvicorn[standard] psycopg[binary] redis pydantic-settings三、编写 Compose 文件
services:api:build:.ports:-"8000:8000"environment:APP_ENV:developmentDATABASE_URL:postgresql://algo:algo@postgres:5432/algorithmREDIS_URL:redis://redis:6379/0depends_on:postgres:condition:service_healthyredis:condition:service_healthypostgres:image:postgres:16environment:POSTGRES_DB:algorithmPOSTGRES_USER:algoPOSTGRES_PASSWORD:algovolumes:-postgres_data:/var/lib/postgresql/dataports:-"5432:5432"healthcheck:test:["CMD-SHELL","pg_isready -U algo -d algorithm"]interval:5stimeout:3sretries:10redis:image:redis:7-alpinevolumes:-redis_data:/dataports:-"6379:6379"healthcheck:test:["CMD","redis-cli","ping"]interval:5stimeout:3sretries:10volumes:postgres_data:redis_data:容器内部访问 PostgreSQL 使用postgres:5432,访问 Redis 使用redis:6379。ports只是把端口暴露到宿主机,服务之间并不依赖宿主机端口。
四、建立数据库连接
# app/config.pyfrompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):database_url:strredis_url:strsettings=Settings()# app/main.pyfromcontextlibimportasynccontextmanagerfromfastapiimportFastAPIfromredis.asyncioimportRedisimportpsycopgfromapp.configimportsettings@asynccontextmanagerasyncdeflifespan(app:FastAPI):app.state.redis=Redis.from_url(settings.redis_url,decode_responses=True)app.state.db=awaitpsycopg.AsyncConnection.connect(settings.database_url)yieldawaitapp.state.redis.aclose()awaitapp.state.db.close()app=FastAPI(lifespan=lifespan)真实项目中不要为每个请求创建一个数据库连接,而应使用连接池。应用启动时如果数据库不可用,要有明确的重试和未就绪策略。
五、实现一个结果接口
fromfastapiimportRequest@app.get("/api/v1/results/{request_id}")asyncdefget_result(request_id:str,request:Request):cache_key=f"algorithm:result:{request_id}"cached=awaitrequest.app.state.redis.get(cache_key)ifcached:return{"source":"redis","data":cached}asyncwithrequest.app.state.db.cursor()ascur:awaitcur.execute("SELECT request_id, status, result_json FROM inference_results ""WHERE request_id = %s",(request_id,),)row=awaitcur.fetchone()ifrowisNone:return{"status":"not_found"}data={"request_id":row[0],"status":row[1],"result":row[2]}awaitrequest.app.state.redis.set(cache_key,str(data),ex=60)return{"source":"postgres","data":data}缓存 Key 至少要包含业务类型、资源 ID、版本和权限维度。不能因为命中 Redis 就跳过用户权限检查。缓存中的结果过期后,应安全回源数据库。
六、启动和验证
dockercompose up-d--builddockercomposepsdockercompose logs-fapi检查数据库:
dockercomposeexecpostgres psql-Ualgo-dalgorithm检查 Redis:
dockercomposeexecredis redis-cliping验证顺序:
- PostgreSQL 和 Redis 状态变为 healthy;
- API 容器成功启动;
- API 能连接两个依赖;
- 写入一条算法结果;
- 第一次读取回源 PostgreSQL;
- 第二次读取命中 Redis;
- 删除或修改结果后,缓存能够失效。
七、开发环境和生产环境的区别
本示例把数据库端口暴露到宿主机,方便调试。生产环境通常只让 API 和 Worker 通过内部网络访问,数据库密码也不能写成 Compose 文件中的明文。
还需要补充:
- 数据库迁移工具和启动迁移流程;
- PostgreSQL 备份与恢复;
- Redis 持久化或明确的缓存丢失策略;
- 连接池大小和超时;
- API、数据库和 Redis 的日志与指标;
- 升级时的数据兼容和回滚方案。
结语
FastAPI、PostgreSQL 和 Redis 是算法服务中很常见的一组基础组件:API 负责交互,PostgreSQL 负责事实,Redis 负责加速。通过 Compose 把它们放在同一套网络和配置中,团队可以快速获得稳定的本地联调环境。
下一篇将加入 MinIO,把上传文件、推理结果和模型文件从容器文件系统中分离出来。
参考资料
- Docker Compose 官方文档
- PostgreSQL 官方文档
- Redis 官方文档
本文中的数据库密码和端口仅用于本地演示,生产环境必须使用密钥管理、网络隔离和备份策略。