Cloud Run调用Cloud Build webhook触发构建报443端口连接超时
问题描述
在Cloud Run中通过webhook向Cloud Build触发器发送POST请求时执行失败,返回错误:curl: (7) Failed to connect to cloudbuild.googleapis.com port 443: Connection timed out
先后尝试Python requests库、Python调用curl两种实现,请求均无法正常发起,但完全相同的请求在本地环境、GCP VM实例中可正常运行。
当前测试代码如下:
import subprocess import shlex import json header="Content-Type: application/json" data=json.dumps('{"substitutions":{"_MODEL_DATE":"2022-06-27_12:00", "_TAG":"test"}}') url="https://cloudbuild.googleapis.com/v1/projects/tdp-build-prod-6e0ca1/triggers/tdp-sandbox-vertex-training-build-image:webhook?key=xxxxxx&secret=xxxxxx" gcp=f"curl -v -X POST -H {header} --data {data} {url}" print(gcp) subprocess.run(shlex.split(gcp))
故障原因
- 连接超时的核心原因是Cloud Run出口网络配置错误:如果服务配置为仅VPC出口、或VPC出口规则设置为转发所有流量到VPC,但VPC没有开启Private Google Access、也没有配置Cloud NAT,服务就无法路由到
cloudbuild.googleapis.com这类Google公共API域名,最终触发连接超时。本地和VM能正常访问,是因为这两个环境默认有公网出口路由。 - 现有代码存在额外逻辑问题:传入
json.dumps的参数本身就是JSON格式字符串,二次序列化会导致请求体格式错误,网络问题修复后如果不调整这部分,请求会返回参数错误。
修复步骤
1. 修复网络配置(解决超时核心问题)
根据自身部署场景选择对应配置:
- 无需VPC接入的场景:进入Cloud Run服务编辑页,找到「连接-网络」配置项,将出口流量规则设置为允许直接访问公网,取消所有流量强制路由到VPC的配置,保存后重新部署服务即可。
- 需要VPC接入的场景:
- 给服务所在的VPC子网开启Private Google Access,该配置允许VPC内资源无需公网IP即可访问Google公共API
- 如果服务还需要访问Google以外的公网资源,额外为VPC配置Cloud NAT网关,提供公网出口能力
- 检查VPC出站防火墙规则,确认没有拦截443端口到Google API服务地址段的请求
2. 修复代码逻辑
修正JSON构造的冗余序列化问题,同时给shell命令参数增加转义避免特殊字符解析异常,修正后的curl调用代码:
import subprocess import shlex import json header = "Content-Type: application/json" # 直接构造字典做JSON序列化,不要对字符串二次dumps data = json.dumps({ "substitutions": { "_MODEL_DATE": "2022-06-27_12:00", "_TAG": "test" } }) url = "https://cloudbuild.googleapis.com/v1/projects/tdp-build-prod-6e0ca1/triggers/tdp-sandbox-vertex-training-build-image:webhook?key=xxxxxx&secret=xxxxxx" gcp = f"curl -v -X POST -H {shlex.quote(header)} --data {shlex.quote(data)} {shlex.quote(url)}" print(gcp) subprocess.run(shlex.split(gcp))
更推荐直接用requests库实现,不需要处理shell转义逻辑,代码更简洁:
import requests url = "https://cloudbuild.googleapis.com/v1/projects/tdp-build-prod-6e0ca1/triggers/tdp-sandbox-vertex-training-build-image:webhook?key=xxxxxx&secret=xxxxxx" payload = { "substitutions": { "_MODEL_DATE": "2022-06-27_12:00", "_TAG": "test" } } resp = requests.post(url, json=payload, timeout=30) print(resp.status_code, resp.text)
内容的提问来源于stack exchange,提问作者forfun
相关产品推荐
相关产品推荐

