部署在Heroku的多Docker应用(Streamlit+FastAPI)连接错误求助
问题根源
- Heroku容器部署中,多个dyno不在同一私有网络,无法通过本地Docker Compose的服务名(如
api)进行内部通信 - Heroku每个dyno仅允许绑定一个平台分配的
PORT环境变量,硬编码端口会导致服务无法正常暴露
解决方案:合并前后端到单个容器(推荐)
将前后端及Nginx反向代理打包进一个容器,通过localhost实现内部通信,同时适配Heroku的端口规则。
步骤1:创建核心配置文件
- 根目录新建
Dockerfile:
FROM python:3.9-slim WORKDIR /app # 安装Nginx和进程管理器 RUN apt-get update && apt-get install -y nginx supervisor && rm -rf /var/lib/apt/lists/* # 复制并安装前后端依赖 COPY frontend/requirements.txt ./frontend/ COPY backend/requirements.txt ./backend/ RUN pip install --no-cache-dir -r frontend/requirements.txt RUN pip install --no-cache-dir -r backend/requirements.txt # 复制前后端代码 COPY frontend/ ./frontend/ COPY backend/ ./backend/ # 复制Nginx配置 COPY nginx.conf /etc/nginx/nginx.conf # 复制Supervisord配置 COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf # 暴露Heroku分配的端口 EXPOSE ${PORT:-80} # 启动进程管理器 CMD ["supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
- 根目录新建
nginx.conf:
events { worker_connections 1024; } http { server { listen ${PORT:-80}; # 根路径转发给Streamlit前端 location / { proxy_pass http://localhost:8501; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # /api路径转发给FastAPI后端 location /api/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } }
- 根目录新建
supervisord.conf:
[supervisord] nodaemon=true # 启动FastAPI后端 [program:backend] command=uvicorn backend.api:app --host 0.0.0.0 --port 8080 directory=/app stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 # 启动Streamlit前端(无头模式适配容器环境) [program:frontend] command=streamlit run frontend/streamlit_app.py --server.port 8501 --server.address 0.0.0.0 --server.headless true directory=/app stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 # 启动Nginx反向代理 [program:nginx] command=nginx -g "daemon off;" directory=/app stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0
步骤2:修改前端请求地址
编辑frontend/streamlit_app.py,将原硬编码的host="http://api:8080/ask"替换为:
host = "http://localhost/api/ask"
步骤3:更新heroku.yml
替换为单服务配置:
build: docker: web: Dockerfile run: web: supervisord -c /etc/supervisor/conf.d/supervisord.conf
步骤4:重新部署
git add . git commit -m "Merge frontend/backend into single container with Nginx proxy" git push heroku main heroku open
替代方案:分拆为两个独立Heroku应用
若需保持前后端分离,可将后端单独部署为一个Heroku应用,然后:
- 在前端应用的Heroku环境变量中设置
BACKEND_URL为后端应用的完整请求地址(如https://your-backend-app.herokuapp.com/ask) - 修改
streamlit_app.py从环境变量读取地址:
import os host = os.getenv("BACKEND_URL", "http://api:8080/ask")
此方案需维护两个应用,且需在后端配置CORS解决跨域问题。
内容的提问来源于stack exchange,提问作者BioGeek
相关产品推荐
相关产品推荐

