Heroku生产环境无法连接Google Cloud Bucket但本地正常的问题求助
问题描述
我手里有个Rails应用,用Rake任务来访问Google Cloud Bucket。本地跑这个任务完全没问题,但部署到Heroku生产环境后就报错了,错误信息如下:
/app/vendor/ruby-3.1.2/lib/ruby/3.1.0/socket.rb:1214:in __connect_nonblock': Failed to open TCP connection to 169.254.169.254:80 (Operation already in progress - connect(2) for 169.254.169.254:80) (Errno::EALREADY)
我已经确认服务账号密钥加载正常,甚至在Cloud Console的Bucket面板里能看到请求确实打到了Bucket上,但就是会抛出这个错误,实在摸不着头脑。ChatGPT提示这可能和Google的元数据服务器有关?
附上相关的服务代码片段:
require "base64" require "google/cloud/storage" class GoogleCloudBucketService def initialize(bucket_name) @bucket_name = bucket_name decoded_json_key = Base64.decode64(ENV['GCP_SERVICE_ACCOUNT_KEY']) # 后续的初始化逻辑 end # 其他相关方法 end
问题分析与解决建议
你猜的没错,169.254.169.254就是Google云的元数据服务器地址。Google的SDK默认会自动尝试从这个地址获取凭证,哪怕你已经手动提供了服务账号密钥。在Heroku环境里,这种自动检测逻辑和你手动加载密钥的操作撞车了,导致重复发起连接请求,就触发了Errno::EALREADY这个错误。
给你几个可以尝试的解决方向:
显式禁用自动凭证检测
在初始化Google::Cloud::Storage的时候,明确指定使用你解码后的服务账号密钥,同时加上disable_gce_metadata: true参数,直接阻止SDK去访问元数据服务器。修改后的初始化代码大概是这样:def initialize(bucket_name) @bucket_name = bucket_name decoded_json_key = Base64.decode64(ENV['GCP_SERVICE_ACCOUNT_KEY']) @storage = Google::Cloud::Storage.new( credentials: JSON.parse(decoded_json_key), disable_gce_metadata: true ) @bucket = @storage.bucket(@bucket_name) end排查Heroku网络限制
虽然你能看到请求记录,但Heroku的网络环境本来就访问不了Google的内部元数据服务器,SDK反复尝试连接这个地址就会出问题。你可以在Heroku上跑个命令测试下:heroku run curl 169.254.169.254,大概率是访问不通的,这也验证了我们的推测。确认服务账号权限完整性
有时候哪怕请求能到Bucket,但如果部分操作权限不足,SDK会自动 fallback 去元数据服务器尝试获取其他凭证,进而引发连接错误。你可以检查下服务账号是否拥有Bucket所需的完整权限,比如storage.objects.get、storage.objects.create这些核心权限。
备注:内容来源于stack exchange,提问作者Kyle Pendergast

