Cloud Run容器内Flask与Chainlit多端口部署故障求助
问题排查与解决方案
核心问题分析
1. Cloud Run单端口限制
Cloud Run每个服务仅允许对外暴露一个端口(默认8080),即使Dockerfile中EXPOSE了8080和8000,Cloud Run也只会映射你配置的单个端口,8000端口无法从外部网络访问,这是聊天功能无法使用的根本原因之一。
2. Flask重定向目标错误
app.py中redirect("http://localhost:8000")的逻辑存在问题:
- 本地测试时,
localhost指向你的本地机器,容器内的8000端口可以被本地浏览器访问; - 部署到Cloud Run后,用户浏览器的
localhost是用户自己的设备,而非Cloud Run容器内部,因此会出现无法访问的错误。
3. 启动脚本的潜在问题
- 依赖固定
sleep时间等待Ollama启动,若Ollama启动较慢,会导致Chainlit因依赖未就绪而启动失败; - 后台进程的日志可能未被正确输出到stdout,导致Cloud Run日志中看不到Chainlit的运行记录。
分步解决方案
方案1:通过Flask反向代理整合服务(推荐)
将Chainlit服务通过Flask代理到同一个端口,避免多端口暴露问题,修改app.py如下:
from flask import Flask, redirect, render_template, request, Response import requests app = Flask(__name__) # 容器内Chainlit服务的地址 CHAINLIT_SERVICE = "http://localhost:8000" @app.route("/") def home(): return render_template("index.html") @app.route("/chat") def chat(): # 重定向到代理后的Chainlit入口 return redirect(f"{CHAINLIT_SERVICE}/chat") # 代理所有Chainlit相关请求 @app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]) def proxy_chainlit(path): target_url = f"{CHAINLIT_SERVICE}/{path}" # 转发请求到Chainlit req = requests.request( method=request.method, url=target_url, headers={k: v for k, v in request.headers.items() if k != "Host"}, data=request.get_data(), cookies=request.cookies, allow_redirects=False ) # 处理响应头,移除Cloud Run不兼容的字段 excluded_headers = ["content-encoding", "content-length", "transfer-encoding", "connection"] response_headers = [ (name, value) for name, value in req.raw.headers.items() if name.lower() not in excluded_headers ] return Response(req.content, req.status_code, response_headers) if __name__ == "__main__": app.run(host="0.0.0.0", port=8080)
方案2:修复启动脚本,确保服务稳定启动
修改启动脚本,替换固定sleep为主动检查Ollama就绪状态,同时显式指定Chainlit的监听地址和端口,确保日志输出:
#!/bin/bash # 启动Ollama后台服务 ollama serve & OLLAMA_PID=$! # 主动等待Ollama就绪(轮询API直到响应正常) echo "🔵 Waiting for Ollama to initialize..." until curl -s http://localhost:11434/api/tags > /dev/null; do sleep 1 done echo "🟢 Ollama is ready!" # 拉取所需Ollama模型(根据你的需求替换模型名) ollama pull llama2 # 启动Chainlit,显式指定监听0.0.0.0和端口8000 echo "🔵 Starting Chainlit service..." poetry run chainlit run --headless --host 0.0.0.0 --port 8000 src/chatbot.py & CHAINLIT_PID=$! # 启动Flask服务 echo "🔵 Starting Flask service..." poetry run gunicorn -b 0.0.0.0:8080 src.app.app:app & FLASK_PID=$! # 等待任一进程退出,然后终止所有服务(保证容器优雅退出) wait -n $OLLAMA_PID $CHAINLIT_PID $FLASK_PID kill $OLLAMA_PID $CHAINLIT_PID $FLASK_PID 2>/dev/null
方案3:Cloud Run配置调整
- 在Cloud Run服务配置中,确保容器端口设置为8080(与Flask监听端口一致);
- 不需要配置8000端口,所有请求将通过Flask代理到容器内的Chainlit服务。
验证步骤
- 重新构建Docker镜像并推送到Cloud Run;
- 访问Cloud Run生成的域名首页,点击"chat"按钮;
- 查看Cloud Run日志,确认Ollama、Chainlit、Flask三个服务都正常启动;
- 测试聊天功能,确认可以正常与AI机器人交互。
内容的提问来源于stack exchange,提问作者Boubacar Traoré
相关产品推荐
相关产品推荐

