Google Cloud Run非服务器进程无法进入就绪状态问题咨询
解决Cloud Run中非服务器进程的就绪状态问题
问题背景
在Google Cloud Run中运行Python WebSocket客户端脚本,已成功连接第三方WebSocket服务器(提供了URI和API密钥)并正常传输数据,但Cloud Run始终无法将容器识别为就绪状态。排查后确认:Cloud Run要求进程必须监听暴露的端口,而客户端脚本本身不具备监听端口的能力,这是导致就绪检测失败的核心原因。
原客户端脚本
import asyncio from websockets.client import connect async def hello(): headers = { "Authorization": "Bearer " + "API_KEY", "Sec-WebSocket-Version": "13", "Connection": "Upgrade", "Upgrade": "websocket", "Host": "logstream.3rdparty.com:443" } async with connect(uri="wss://logstream.3rdparty.com:443/v1/stream?cid=mycompany_hosted&type=message", extra_headers=headers) as websocket: while True: message = await websocket.recv() print(f"Received: {message[:20]}") asyncio.run(hello())
原Dockerfile
FROM python:3.10 ENV ENV=dev \ TOPIC_PROJECT_ID=project_id \ TOPIC_NAME=dev-topic_name \ API_KEY=API_KEY \ \ PORT=8765 \ HOSTNAME=0.0.0.0 EXPOSE 8080 COPY . /workdir WORKDIR /workdir RUN pip install -r requirements.txt ENTRYPOINT ["python", "main.py"]
解决方案
Cloud Run的就绪检测默认会向容器的8080端口发送HTTP请求,只要进程能监听该端口并响应请求,就会被标记为就绪。我们可以通过添加一个轻量的HTTP服务来满足这个要求,同时不影响WebSocket客户端的正常运行。
1. 修改客户端脚本,添加HTTP监听服务
调整脚本,使用asyncio同时运行两个任务:WebSocket客户端逻辑和一个简易HTTP服务器。示例代码如下:
import asyncio import os from websockets.client import connect from http.server import BaseHTTPRequestHandler, HTTPServer # 简易HTTP请求处理器,仅响应200状态 class HealthCheckHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header('Content-type', 'text/plain') self.end_headers() self.wfile.write(b'Ready') # 关闭日志输出,避免干扰WebSocket日志 def log_message(self, format, *args): pass async def run_http_server(port): server = HTTPServer(('0.0.0.0', port), HealthCheckHandler) # 用asyncio包装同步的HTTP服务器 await asyncio.get_event_loop().run_in_executor(None, server.serve_forever) async def websocket_client(): headers = { "Authorization": "Bearer " + os.getenv('API_KEY'), "Sec-WebSocket-Version": "13", "Connection": "Upgrade", "Upgrade": "websocket", "Host": "logstream.3rdparty.com:443" } async with connect(uri="wss://logstream.3rdparty.com:443/v1/stream?cid=mycompany_hosted&type=message", extra_headers=headers) as websocket: while True: message = await websocket.recv() print(f"Received: {message[:20]}") async def main(): # 获取Cloud Run指定的端口,默认8080 port = int(os.getenv('PORT', 8080)) # 同时运行HTTP服务器和WebSocket客户端 await asyncio.gather( run_http_server(port), websocket_client() ) if __name__ == "__main__": asyncio.run(main())
2. 调整Dockerfile配置
清理无用环境变量,确保端口配置与脚本一致:
FROM python:3.10 ENV API_KEY=API_KEY \ PORT=8080 \ HOSTNAME=0.0.0.0 EXPOSE 8080 COPY . /workdir WORKDIR /workdir RUN pip install -r requirements.txt ENTRYPOINT ["python", "main.py"]
关键说明
- 新增的HTTP服务器仅用于响应Cloud Run的就绪检测请求,不会消耗过多资源
- 确保脚本监听的端口与Dockerfile中
EXPOSE的端口、环境变量PORT一致,Cloud Run默认使用8080端口 - 若需要自定义就绪检测路径,可以修改
HealthCheckHandler的do_GET方法,处理特定路径的请求
内容的提问来源于stack exchange,提问作者Rudolph Sargenti
相关产品推荐
相关产品推荐

