FastAPI+Docker部署异常:指定Host与Port被忽略致无法远程访问
问题重现
在远程机器用Docker部署FastAPI,已在Dockerfile的CMD中指定--host 0.0.0.0和--port 8501,但容器启动后日志显示Uvicorn运行在http://127.0.0.1:8000,导致外部curl请求连接失败。本地运行相同配置正常,日志显示Uvicorn监听指定的0.0.0.0:8501。
相关配置
Dockerfile:
ARG PYTHON_VERSION=3.11-slim-buster FROM python:${PYTHON_VERSION} as python WORKDIR /app ADD . . RUN pip install -r requirements.txt CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8501"]
docker-compose.yml:
version: '3.5' services: container-name: container_name: container-name build: context: . dockerfile: Dockerfile env_file: - ./env/demo.env ports: - "8501:8501"
启动命令:
docker compose down && docker-compose build --no-cache && docker compose up
日志输出:
... container-name | INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) ...
可能的原因及解决方法
1. 环境变量覆盖命令行参数
Uvicorn会优先读取环境变量配置启动参数,比如UVICORN_HOST、UVICORN_PORT、UVICORN_BIND(格式为host:port)。检查你的demo.env文件:
- 如果存在
UVICORN_HOST=127.0.0.1或UVICORN_PORT=8000,直接删除或修改为UVICORN_HOST=0.0.0.0、UVICORN_PORT=8501 - 如果存在
UVICORN_BIND=127.0.0.1:8000,改成UVICORN_BIND=0.0.0.0:8501
修改后重新构建启动容器,观察日志是否恢复正常。
2. 代码中硬编码启动参数
检查main.py文件,确认是否存在直接指定Uvicorn启动参数的代码,比如:
if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)
虽然用python -m uvicorn启动时不会执行这段代码(此时__name__不是__main__),但如果容器启动逻辑被意外修改为python main.py,就会触发这段逻辑。如果有,建议删除或修改为符合需求的参数。
3. 容器内手动验证启动命令
进入运行中的容器,直接执行启动命令,排查是否是启动流程的问题:
docker exec -it container-name bash
在容器内执行:
python -m uvicorn main:app --host 0.0.0.0 --port 8501
如果此时日志显示正确的http://0.0.0.0:8501,说明容器启动时的参数被其他因素覆盖;如果还是显示默认地址,可能是代码依赖或版本问题。
4. 统一Uvicorn版本,避免版本差异
不同版本的Uvicorn对参数的处理可能存在差异,检查本地和容器内的Uvicorn版本是否一致:
- 本地执行:
pip list | grep uvicorn - 容器内执行(进入容器后):
pip list | grep uvicorn
如果版本不一致,在requirements.txt里指定明确的版本号,比如:
uvicorn==0.23.2
重新构建容器,确保依赖版本统一。
5. 在docker-compose中直接指定command参数
绕过Dockerfile的CMD,直接在docker-compose.yml中设置启动命令,排除Dockerfile配置被覆盖的可能:
services: container-name: # ...其他原有配置 command: ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8501"]
重新启动容器,观察日志是否正常。
6. 检查端口映射与防火墙配置
即使Uvicorn参数生效,还要确保外部能访问:
- 用
docker inspect container-name查看端口映射,确认宿主机的8501端口确实映射到容器的8501端口 - 检查远程机器的防火墙/安全组:比如云服务器的安全组是否开放8501端口入站,或者本地防火墙执行
ufw allow 8501/firewall-cmd --add-port=8501/tcp --permanent放行该端口
内容的提问来源于stack exchange,提问作者maria

