如何在通过Kubernetes运行的GKE上设置GOOGLE_APPLICATION_CREDENTIALS

23

借助Kubernetes的帮助,我正在GKE上运行每日作业。基于在Kubernetes中配置的cron,每天都会启动一个新容器,并尝试将某些数据插入到BigQuery中。

我们的设置是在GCP中有2个不同的项目,一个项目中我们维护BigQuery中的数据,在另一个项目中我们运行所有的GKE,因此当GKE必须与不同的项目资源进行交互时,我的猜测是我必须设置一个名为GOOGLE_APPLICATION_CREDENTIALS的环境变量,它指向一个服务账户JSON文件,但由于每天Kubernetes都会启动一个新容器,我不确定应该在何处设置此变量。

提前致谢!

注意:此文件由drone-gke插件解析为golang模板。

---
apiVersion: v1
kind: Secret
metadata:
  name: my-data-service-account-credentials
type: Opaque
data:
  sa_json: "bas64JsonServiceAccount"
---
apiVersion: v1
kind: Pod
metadata:
  name: adtech-ads-apidata-el-adunit-pod
spec:
  containers:
  - name: adtech-ads-apidata-el-adunit-container
    volumeMounts:
    - name: service-account-credentials-volume
     mountPath: "/etc/gcp"
     readOnly: true
  volumes:
  - name: service-account-credentials-volume
    secret:
      secretName: my-data-service-account-credentials
      items:
      - key: sa_json
        path: sa_credentials.json

这是我们用于加载广告单元数据的定时作业


apiVersion: batch/v2alpha1
kind: CronJob
metadata:
  name: adtech-ads-apidata-el-adunit
spec:
  schedule: "*/5 * * * *"
  suspend: false
  concurrencyPolicy: Replace
  successfulJobsHistoryLimit: 10
  failedJobsHistoryLimit: 10
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: adtech-ads-apidata-el-adunit-container
            image: {{.image}}
            args:
            - -cp
            - opt/nyt/DFPDataIngestion-1.0-jar-with-dependencies.jar
            - com.nyt.cron.AdUnitJob
            env:
              - name: ENV_APP_NAME
                value: "{{.env_app_name}}"
              - name: ENV_APP_CONTEXT_NAME
                value: "{{.env_app_context_name}}"
              - name: ENV_GOOGLE_PROJECTID
                value: "{{.env_google_projectId}}"
              - name: ENV_GOOGLE_DATASETID
                value: "{{.env_google_datasetId}}"
              - name: ENV_REPORTING_DATASETID
                value: "{{.env_reporting_datasetId}}"
              - name: ENV_ADBRIDGE_DATASETID
                value: "{{.env_adbridge_datasetId}}"
              - name: ENV_SALESFORCE_DATASETID
                value: "{{.env_salesforce_datasetId}}"
              - name: ENV_CLOUD_PLATFORM_URL
                value: "{{.env_cloud_platform_url}}"
              - name: ENV_SMTP_HOST
                value: "{{.env_smtp_host}}"
              - name: ENV_TO_EMAIL
                value: "{{.env_to_email}}"
              - name: ENV_FROM_EMAIL
                value: "{{.env_from_email}}"
              - name: ENV_AWS_USERNAME
                value: "{{.env_aws_username}}"
              - name: ENV_CLIENT_ID
                value: "{{.env_client_id}}"
              - name: ENV_REFRESH_TOKEN
                value: "{{.env_refresh_token}}"
              - name: ENV_NETWORK_CODE
                value: "{{.env_network_code}}"
              - name: ENV_APPLICATION_NAME
                value: "{{.env_application_name}}"
              - name: ENV_SALESFORCE_USERNAME
                value: "{{.env_salesforce_username}}"
              - name: ENV_SALESFORCE_URL
                value: "{{.env_salesforce_url}}"
              - name: GOOGLE_APPLICATION_CREDENTIALS
                value: "/etc/gcp/sa_credentials.json"
              - name: ENV_CLOUD_SQL_URL
                valueFrom:
                  secretKeyRef:
                    name: secrets
                    key: cloud_sql_url
              - name: ENV_AWS_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: secrets
                    key: aws_password
              - name: ENV_CLIENT_SECRET
                valueFrom:
                  secretKeyRef:
                    name: secrets
                    key: dfp_client_secret
              - name: ENV_SALESFORCE_PASSWORD
                valueFrom:
                  secretKeyRef:
                    name: secrets
                    key: salesforce_password


          restartPolicy: OnFailure

1个回答

59

因此,如果您的GKE项目是 my-gke,包含GKE容器需要访问的服务/资源的项目是 my-data,则一种方法是:

  • my-data 项目中创建一个服务账号,并授予其所需的 GCP 角色/权限(例如,如果您有一些 BigQuery 表格需要 my-gke GKE 容器读取,则授予 roles/bigquery.dataViewer 权限)。
  • 为那些服务账号凭据创建一个 Kubernetes 密钥资源。它可能看起来像这样:

    apiVersion: v1
    kind: Secret
    metadata:
      name: my-data-service-account-credentials
    type: Opaque
    data:
      sa_json: <contents of running 'base64 the-downloaded-SA-credentials.json'>
    
  • 将凭证安装在需要访问的容器中:

  • [...]
    spec:
      containers:
      - name: my-container
        volumeMounts:
        - name: service-account-credentials-volume
          mountPath: /etc/gcp
          readOnly: true
    [...]
      volumes:
      - name: service-account-credentials-volume
        secret:
          secretName: my-data-service-account-credentials
          items:
          - key: sa_json
            path: sa_credentials.json
    
  • 在容器中设置GOOGLE_APPLICATION_CREDENTIALS环境变量,使其指向挂载凭据的路径:

  • [...]
    spec:
      containers:
      - name: my-container
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /etc/gcp/sa_credentials.json
    

因此,任何官方的GCP客户端(例如GCP Python客户端、GCP Java客户端、gcloud CLI等)都应该尊重GOOGLE_APPLICATION_CREDENTIALS环境变量,并在进行API请求时自动使用您创建并挂载凭据.json文件的my-data服务帐户的凭据。


GOOGLE_APPLICATION_CREDENTIALS 如果只是作为环境变量提供,是否也能正常工作,还是必须指向已挂载的文件? - pkaramol
我相信 GOOGLE_APPLICATION_CREDENTIALS 环境变量的值必须始终是指向凭据文件的路径才能正常工作。也就是说,将凭据的 base64 编码或其他表示直接作为 GOOGLE_APPLICATION_CREDENTIALS 环境变量的值是行不通的。 - RochesterinNYC
如果我们想要放置GCP服务帐户JSON文件的文本,那么请将我们的Secret中的"data"替换为"stringData"。 - handaru
stringData: sa_json: |- { "type": "service_account", "project_id": "<project_id>", "private_key_id": "<private_key_id>", "private_key": "<private_key>", "client_email": "<client_email>", "client_id": "<auth_uri>", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "<client_x509_cert_url>" } - handaru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接