无法从 Google Kubernetes Engine 集群访问 Google Cloud Datastore

Can't access Google Cloud Datastore from Google Kubernetes Engine cluster

我有一个简单的应用程序,可以从数据存储中获取和放入信息。

它无处不在,但是当我从 Kubernetes Engine 集群内部 运行 它时,我得到了这个输出:

Error from Get()
rpc error: code = PermissionDenied desc = Request had insufficient authentication scopes.
Error from Put()
rpc error: code = PermissionDenied desc = Request had insufficient authentication scopes.

我正在使用 cloud.google.com/go/datastore 包和 Go 语言。

我不知道为什么会收到此错误,因为该应用程序在其他任何地方都可以正常工作。

更新:

为了寻找答案,我在 Google 组上找到了这条评论:

In order to use Cloud Datastore from GCE, the instance needs to be configured with a couple of extra scopes. These can't be added to existing GCE instances, but you can create a new one with the following Cloud SDK command:

gcloud compute instances create hello-datastore --project --zone --scopes datastore userinfo-email

这是否意味着默认情况下我不能使用来自 GKE 的 Datastore?

更新二:

我可以看到在创建我的集群时我没有启用任何权限(默认情况下对大多数服务是禁用的)。我想这就是导致问题的原因:

奇怪的是,我可以很好地使用 CloudSQL,即使它被禁用(使用 cloudsql_proxy 容器)。

所以我在调试这个问题的过程中了解到:

  • 在创建 Kubernetes 集群期间,您可以为将要创建的 GCE 节点指定权限。

  • 例如,如果您在创建期间在集群节点上启用数据存储访问,您将能够直接从 Pods 访问数据存储,而无需进行任何其他设置。

  • 如果您的集群节点权限像我一样对大多数事情(默认设置)禁用,您将需要为每个想要使用 GCP 资源(如数据存储)的应用程序创建一个适当的服务帐户。

  • 另一种方法是使用 gcloud 命令创建一个新的节点池,设置所需的权限范围,然后将所有部署迁移到新的节点池(相当繁琐)。

所以在一天结束时,我通过为我的应用程序创建服务帐户、下载 JSON 身份验证密钥、创建包含该密钥的 Kubernetes 秘密以及数据存储的情况解决了这个问题,我将 GOOGLE_APPLICATION_CREDENTIALS 环境变量设置为安装的秘密 JSON 密钥的路径。

这样当我的应用程序启动时,它会检查 GOOGLE_APPLICATION_CREDENTIALS 变量是否存在,并根据变量指向的 JSON 键验证数据存储区 API 访问权限。

部署 YAML 片段:

  ...
  containers:
  - image: foo
    name: foo
    env:
    - name: GOOGLE_APPLICATION_CREDENTIALS
      value: /auth/credentials.json
    volumeMounts:
    - name: foo-service-account
      mountPath: "/auth"
      readOnly: true
  volumes:
  - name: foo-service-account
    secret:
      secretName: foo-service-account

经过几个小时的努力,我也能够连接到数据存储。这是我的结果,大部分来自 Google Docs:

  1. 创建服务帐户

    gcloud iam service-accounts create [SERVICE_ACCOUNT_NAME]

  2. 获取完整的iam账户名

    gcloud iam service-accounts list

    结果将如下所示:

    [SERVICE_ACCOUNT_NAME]@[PROJECT_NAME].iam.gserviceaccount.com

  3. 为服务帐户授予所有者访问项目的权限

    gcloud projects add-iam-policy-binding [PROJECT_NAME] --member serviceAccount:[SERVICE_ACCOUNT_NAME]@[PROJECT_NAME].iam.gserviceaccount.com --role roles/owner

  4. 创建密钥文件

    gcloud iam service-accounts keys create mycredentials.json --iam-account [SERVICE_ACCOUNT_NAME]@[PROJECT_NAME].iam.gserviceaccount.com

  5. 创建app-key秘密

    kubectl create secret generic app-key --from-file=credentials.json=mycredentials.json

    app-key 秘密随后将安装在 deployment.yaml

  6. 编辑部署文件

deployment.yaml:

...
spec:
 containers:
 - name: app
   image: eu.gcr.io/google_project_id/springapplication:v1
   volumeMounts:
   - name: google-cloud-key
     mountPath: /var/secrets/google
   env:
   - name: GOOGLE_APPLICATION_CREDENTIALS
     value: /var/secrets/google/credentials.json
   ports:
   - name: http-server
     containerPort: 8080
 volumes:
 - name: google-cloud-key
   secret:
     secretName: app-key

我使用的是简约的 Docker 文件,例如:

FROM SCRATCH
ADD main /
EXPOSE 80
CMD ["/main"]

这让我的 go 应用程序在尝试连接到 GCP 数据存储时处于不确定的 "hanging" 状态。玩了很多次之后,我发现 SCRATCH Docker 图像可能缺少 Google 云库所需的某些环境工具/变量/库。现在可以使用此 Docker 文件:

FROM golang:alpine
RUN apk add --no-cache ca-certificates
ADD main /
EXPOSE 80
CMD ["/main"]

不需要我提供 google credentials 环境变量。该库似乎自动了解它在 运行 中的位置(可能来自 context.Background() ?)并自动使用默认服务帐户,当您在 GKE 上创建集群时,该帐户 Google 会为您创建.