Docker容器中FastAPI用Uvicorn+WatchFiles自动重载失效问题
开发FastAPI应用时,通过docker-compose在Docker容器中运行Uvicorn,开发阶段希望除*.py文件外,其他类型文件变更也能触发自动重载。根据Uvicorn文档,需安装可选依赖WatchFiles才能使用--reload-include参数,但安装后Uvicorn启动时虽提示使用WatchFiles,却完全不触发任何自动重载(无论是否使用include参数);未安装WatchFiles时,Uvicorn默认仅对*.py文件的自动重载正常工作。
现有配置:
Dockerfile
FROM python:3.10 WORKDIR /tmp RUN pip install --upgrade pip COPY requirements.txt . RUN pip install --no-cache-dir --upgrade -r requirements.txt WORKDIR /code CMD ["uvicorn", "package.main:app", "--host", "0.0.0.0", "--port", "80", "--reload"]
docker-compose.yml
version: "3.9" services: fastapi-dev: image: myimagename:${TAG:-latest} build: context: . volumes: - ./src:/code - ./static:/static - ./templates:/templates restart: on-failure ports: - "${HTTP_PORT:-8080}:80"
已尝试操作:
- 在docker-compose.yml中替换Dockerfile的CMD命令,无变化
- 编写
watch.py测试WatchFiles,确认其在容器中可正常检测文件变更,排除文件系统挂载问题
需求:修复该问题,或提供其他实现多类型文件触发重载的方法;若需修复WatchFiles,给出具体步骤。
一、修复WatchFiles配合Uvicorn的自动重载问题
明确指定监听路径
Uvicorn默认仅监听工作目录(/code)下的文件,你的static和templates目录挂载在容器的/static和/templates,不在默认监听范围内。需要用--reload-dir参数指定这些额外路径,结合--reload-include设置要监听的文件类型。修改Dockerfile的CMD或docker-compose的command:
uvicorn package.main:app --host 0.0.0.0 --port 80 --reload --reload-dir /code --reload-dir /static --reload-dir /templates --reload-include "*.html" --reload-include "*.css" --reload-include "*.js"可根据需求调整
--reload-include的文件类型。确认版本兼容性
检查requirements.txt中WatchFiles与Uvicorn的版本匹配度,比如Uvicorn 0.24.x推荐搭配WatchFiles 0.19+,避免版本不兼容导致监听失效。在requirements.txt中明确指定:uvicorn>=0.24.0 watchfiles>=0.19.0添加重载延迟
部分Docker环境下文件系统挂载存在缓存,导致WatchFiles无法及时检测变更。可在启动Uvicorn时添加--reload-delay 1参数,给文件系统同步留缓冲时间:uvicorn ... --reload --reload-delay 1 ...
二、替代方案:无需WatchFiles实现多类型文件重载
如果WatchFiles的问题暂时无法解决,可尝试以下两种方式:
自定义文件监听重启脚本
编写Python脚本,用WatchFiles监听目标文件变更,一旦检测到变化就重启Uvicorn进程。示例脚本:import subprocess from watchfiles import watch def restart_uvicorn(): subprocess.run(["pkill", "-f", "uvicorn"], check=False) subprocess.Popen(["uvicorn", "package.main:app", "--host", "0.0.0.0", "--port", "80"]) if __name__ == "__main__": restart_uvicorn() for changes in watch("/code", "/static", "/templates"): print(f"Detected changes: {changes}") restart_uvicorn()修改Dockerfile的CMD为启动该脚本:
CMD ["python", "/code/watch_restart.py"]启用模板自动重载
针对Jinja2模板文件,可直接启用其自身的自动重载功能,无需Uvicorn重启。在FastAPI中配置:from fastapi import FastAPI from fastapi.templating import Jinja2Templates app = FastAPI() templates = Jinja2Templates(directory="/templates") templates.env.auto_reload = True templates.env.cache = {}静态资源(CSS/JS)可通过浏览器禁用缓存实现开发阶段实时更新,或配合上述自定义脚本监听。
内容的提问来源于stack exchange,提问作者Even0900

