You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将GitLab CI变量传入Sinatra应用以访问Google Cloud Datastore

解决GitLab CI/CD服务账号传递到Sinatra+GAE的问题

嘿,我明白你的困扰——Heroku的config vars确实方便,但GCP这边有自己的玩法,不过我们可以搞定这个问题,把GitLab里的$SERVICE_ACCOUNT安全地传到你的Sinatra应用里作为Datastore的credentials。

首先先澄清个小细节:你贴的那个名为app.yaml的文件其实是GitLab CI的配置文件(标准命名应该是.gitlab-ci.yml),而Google App Engine的部署配置文件也叫app.yaml,别搞混啦,下面我会分别指代这两个文件。

方案一:直接通过环境变量传递(快速实现)

这个方法适合快速验证,把GitLab里的服务账号JSON字符串直接注入到GAE应用的环境变量中:

1. 修改GitLab CI配置(.gitlab-ci.yml)

在deploy_production的script里,给gcloud app deploy添加设置环境变量的参数,把$SERVICE_ACCOUNT传到GAE应用的GOOGLE_APPLICATION_CREDENTIALS_JSON环境变量里:

deploy_production:
  stage: deploy
  environment: Production
  only:
    - production
  script:
    - echo $SERVICE_ACCOUNT > /tmp/$CI_PIPELINE_ID.json
    - gcloud auth activate-service-account --key-file /tmp/$CI_PIPELINE_ID.json
    # 新增:传递服务账号JSON到GAE环境变量
    - gcloud --quiet --project $PROJECT_ID app deploy app.yaml --set-env-vars GOOGLE_APPLICATION_CREDENTIALS_JSON="$SERVICE_ACCOUNT"

2. 修改Sinatra应用代码(foobar.rb)

在生产环境初始化Datastore客户端时,读取这个环境变量,解析成JSON哈希后传入:

require "google/cloud/datastore"
require "json" # 记得引入JSON库

class App < Sinatra::Application
  if settings.production?
    # 从GAE环境变量读取服务账号JSON字符串并解析
    service_account_hash = JSON.parse(ENV["GOOGLE_APPLICATION_CREDENTIALS_JSON"])
    data_store = Google::Cloud::Datastore.new(
      project: 'foobar',
      credentials: service_account_hash
    )
    query = data_store.query "kindoffoobar"
    results = data_store.run query
    # 将每个结果设置为环境变量
    results[0].properties.to_h.each do |key, value|
      ENV[key]= value
    end
  end
  # 其余应用代码...
end

方案二:用GCP Secret Manager管理(更安全,推荐)

直接把JSON字符串放在环境变量里不够安全,GCP的Secret Manager是更符合最佳实践的方式,步骤如下:

1. 在GitLab CI中创建Secret Manager密钥

修改.gitlab-ci.yml的deploy_production脚本,把$SERVICE_ACCOUNT存入Secret Manager:

deploy_production:
  stage: deploy
  environment: Production
  only:
    - production
  script:
    - echo $SERVICE_ACCOUNT > /tmp/$CI_PIPELINE_ID.json
    - gcloud auth activate-service-account --key-file /tmp/$CI_PIPELINE_ID.json
    # 创建或更新Secret Manager密钥
    - echo "$SERVICE_ACCOUNT" | gcloud secrets create SERVICE_ACCOUNT_CREDENTIALS --data-file=- --project $PROJECT_ID || gcloud secrets versions add SERVICE_ACCOUNT_CREDENTIALS --data-file=- --project $PROJECT_ID
    # 部署GAE应用并挂载密钥
    - gcloud --quiet --project $PROJECT_ID app deploy app.yaml

2. 修改GAE部署配置(app.yaml)

在真正的GAE app.yaml里,配置挂载Secret Manager的密钥到应用的文件系统,并设置环境变量告诉Google客户端密钥路径:

# 假设你用的是GAE标准环境Ruby运行时,根据实际情况调整
runtime: ruby
env: standard

# 配置环境变量,指向挂载的密钥文件
env_variables:
  GOOGLE_APPLICATION_CREDENTIALS: /secrets/service_account.json

# 挂载Secret Manager的密钥到应用文件系统
secrets:
- secret: SERVICE_ACCOUNT_CREDENTIALS
  path: service_account.json

3. 简化Sinatra应用代码(foobar.rb)

现在Google Cloud客户端会自动读取GOOGLE_APPLICATION_CREDENTIALS环境变量指向的密钥文件,不需要手动传入credentials:

require "google/cloud/datastore"

class App < Sinatra::Application
  if settings.production?
    # 客户端自动读取密钥文件,无需手动指定credentials
    data_store = Google::Cloud::Datastore.new(
      project: 'foobar'
    )
    query = data_store.query "kindoffoobar"
    results = data_store.run query
    # 将每个结果设置为环境变量
    results[0].properties.to_h.each do |key, value|
      ENV[key]= value
    end
  end
  # 其余应用代码...
end

补充说明

  • 为什么不像Heroku那样简单?Heroku的config vars是直接注入应用环境的轻量方案,而GCP更推荐用Secret Manager这类专门的密钥管理服务来处理敏感信息,虽然步骤多一点,但安全性更高。
  • 确保GitLab CI里的$SERVICE_ACCOUNT是正确的JSON格式,没有额外的换行或转义问题。

内容的提问来源于stack exchange,提问作者Robert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:34:32