FastAPI 应用部署在 Docker 容器中,通过 Portainer 管理。当应用启动后,能够正常接收请求,但运行一段时间后,所有请求会被阻塞或超时,curl 请求挂起,无日志记录。
可能的原因
1. Docker 网络问题
Docker Bridge 网络可能出现连接超时或网络资源限制问题。
2. 资源泄露或限制
应用可能因文件描述符耗尽、内存不足或 TCP 连接未正确关闭导致资源泄漏。
3. 应用代码问题
异步任务未正确关闭、数据库连接未释放或 aiohttp 客户端未关闭可能引发阻塞。
4. 容器健康检查缺失
如果没有健康检查机制,容器可能处于非活跃状态而没有自动恢复。
解决步骤
1、检查 Docker 和 Portainer 配置
确保 Docker 映射的主机端口未被占用。
docker ps
netstat -tuln
检查是否为容器设置了 CPU 或内存限制。
docker inspect <container_id>
2、优化 Dockerfile
FROM python:3.10-slim
# 环境变量
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV POETRY_VERSION=1.8.2
# 工作目录
WORKDIR /app
# 安装依赖
RUN apt-get update && apt-get install -y \
curl \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 安装 Poetry
RUN curl -sSL https://install.python-poetry.org | python3 -
ENV PATH="${PATH}:/root/.local/bin"
# 安装应用依赖
COPY pyproject.toml poetry.lock* ./
RUN poetry install --no-interaction --no-ansi
# 添加应用代码
COPY . .
# 暴露端口
EXPOSE 8121
# 启动服务
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8121", "--workers", "2"]
3、增加健康检查
通过 Docker 添加健康检查,确保容器处于健康状态。
在 docker-compose.yml 中添加:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8121/health"]
interval: 30s
timeout: 10s
retries: 3
在 FastAPI 应用中实现 /health 路由:
@app.get("/health")
async def health_check():
return {"status": "ok"}
4、代码检查
确定 aiohttp 客户端正确关闭,在类中添加析构函数以确保资源释放:
async def close_client(self):
if self.client:
await self.client.close()
self.client = None
在应用关闭事件中调用:
@app.on_event("shutdown")
async def shutdown():
log.info("Shutting down application")
if forwarder.client:
await forwarder.close_client()
确认数据库连接是否正确关闭。使用 Tortoise.close_connections:
@app.on_event("shutdown")
async def shutdown():
await Tortoise.close_connections()
5、日志和监控
• 增加请求日志
使用 Middleware 或 FastAPI 内置日志功能,捕获所有请求和响应。
• 监控容器运行状态
使用工具如 cAdvisor 或 Prometheus 监控容器资源使用情况。
通过以上步骤,优化 Docker 的配置、应用代码和容器监控,可以有效解决 FastAPI 容器长时间运行后无法接收请求的问题。