GKEからCloud SQLにアクセスする

Posted on Jul 16, 2021

KubernetesとGoogle Cloudの設定を行う

Kubernetesクラスタを更新する

Workload Identityを有効にしていなかったらまずその設定を行う。

gcloud container clusters update <cluster-name> \
--workload-pool=<project_id>.svc.id.goog

自分の場合の例

gcloud container clusters update trace-sample --workload-pool=trace-microservices-sample.svc.id.goog
Updating trace-sample...done.
Updated [https://container.googleapis.com/v1/projects/trace-microservices-sample/zones/us-west1-b/clusters/trace-sample].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-west1-b/trace-sample?project=trace-microservices-sample

Kubernetesのノードプールを変更する

新しいノードプールを作るか既存のノードプールを GKE_METADATA を使うように変更する。自分は既存のノードプールを変更した。

gcloud container node-pools update <nodepool_name> \
  --cluster=<cluster_name> \
  --workload-metadata=GKE_METADATA

自分の場合はこういう感じ

$ gcloud container node-pools update default-pool \
--cluster=trace-sample \
--workload-metadata=GKE_METADATA
Updating node pool default-pool... Updating default-pool, done with 0 out of 2 nodes (0.0%): 1 being process
ed...⠹
Updating node pool default-pool... Updating default-pool, done with 1 out of 2 nodes (50.0%): 1 being proces
sed, 1 succeeded...done.
Updated [https://container.googleapis.com/v1/projects/trace-microservices-sample/zones/us-west1-b/clusters/trace-sample/nodePools/default-pool].

Kubernetes Secretの作成

$ kubectl create secret generic cloud-sql-secret \
--from-literal=username=<Cloud SQL username> \
--from-literal=password=<Cloud SQL password> \
--from-literal=database=<Cloud SQL database>

自分の場合の例

$ kubectl create secret generic cloud-sql-secret \
--from-literal=username=postgres \
--from-literal=password=XXXXXXXXXXXXXXXX \
--from-literal=database=xxxxxxxxxxxxxxxx
secret/cloud-sql-secret created

これを作るとGKEのConfigurationsでSecretが作成されたことが確認できる。

Kubernetes Service Account (KSA) の作成

$ kubectl create namespace <namespace_name>
$ kubectl create serviceaccount <ksa_name> --namespace <namespace_name>

自分の場合は横着してdefaultネームスペースを使ってしまった

$ kubectl create serviceaccount cloud-sql-ksa --namespace default
serviceaccount/cloud-sql-ksa created

$ kubectl get serviceaccount --namespace default
NAME            SECRETS   AGE
cloud-sql-ksa   1         21s
default         1         10d

Google Cloud Service Account (GSA) の作成

まず新規Google Cloud Service Accountを作成する。

$ gcloud iam service-accounts create <gsa_name>

つづいて作ったGSAに対してCloud SQLのアクセス権限を付与する

$ gcloud projects add-iam-policy-binding <project_id> \
--member serviceAccount:<gsa_name>@<project_id>.iam.gserviceaccount.com \
--role roles/cloudsql.client

自分の例

$ gcloud iam service-accounts create cloud-sql-gsa
Created service account [cloud-sql-gsa].

$ gcloud projects add-iam-policy-binding trace-microservices-sample \
--member serviceAccount:cloud-sql-gsa@trace-microservices-sample.iam.gserviceaccount.com \
--role roles/cloudsql.client
Updated IAM policy for project [trace-microservices-sample].
bindings:
- members:
  ...(略)...
etag: BwXHNz0zmqE=
version: 1

GSAとKSAの紐付け

gcloud iam service-accounts add-iam-policy-binding \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:<project_id>.svc.id.goog[<kubernetes_namespace>/<ksa_name>]" \
<gsa_name>@<project_id>.iam.gserviceaccount.com

自分の場合の例

$ gcloud iam service-accounts add-iam-policy-binding \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:trace-microservices-sample.svc.id.goog[default/cloud-sql-ksa]" \
cloud-sql-gsa@trace-microservices-sample.iam.gserviceaccount.com
Updated IAM policy for serviceAccount [cloud-sql-gsa@trace-microservices-sample.iam.gserviceaccount.com].
bindings:
- members:
  - serviceAccount:trace-microservices-sample.svc.id.goog[default/cloud-sql-ksa]
  role: roles/iam.workloadIdentityUser
etag: BwXHN6fhkC0=
version: 1

KSAにアノテーションを追加する

kubectl annotate serviceaccount \
   <ksa_name> \
   iam.gke.io/gcp-service-account=<ksa_name>@<project_id>.iam.gserviceaccount.com

自分の場合

kubectl annotate serviceaccount \
   cloud-sql-ksa \
   iam.gke.io/gcp-service-account=cloud-sql-ksa@trace-microservices-sample.iam.gserviceaccount.com

serviceaccount/cloud-sql-ksa annotated

トラブル

Cloud SQL Proxy が 403で起動しない

KSAとGSAの紐付けを行っていて、GSAにちゃんとCloud SQLのクライアントのロールを与えているのに接続できなかった。

...(略)...
Waiting for deployments to stabilize...
 - deployment/appservice: waiting for rollout to finish: 0 of 1 updated replicas are available...
 - deployment/clientservice: waiting for rollout to finish: 0 of 1 updated replicas are available...
 - deployment/appservice: container cloud-sql-proxy terminated with exit code 1
    - pod/appservice-64ddff97b9-bdq7w: container cloud-sql-proxy terminated with exit code 1
      > [appservice-64ddff97b9-bdq7w cloud-sql-proxy] 2021/07/16 07:41:10 current FDs rlimit set to 1048576, wanted limit is 8500. Nothing to do here.
      > [appservice-64ddff97b9-bdq7w cloud-sql-proxy] 2021/07/16 07:41:13 errors parsing config:
      > [appservice-64ddff97b9-bdq7w cloud-sql-proxy]   googleapi: Error 403: The client is not authorized to make this request., notAuthorized
 - deployment/appservice failed. Error: container cloud-sql-proxy terminated with exit code 1.
...(略)...

よく確認するとKubernetesのマニフェストでサービスアカウント名をちゃんと指定していなかった。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: appservice
spec:
  selector:
    matchLabels:
      app: appservice
  template:
    metadata:
      labels:
        app: appservice
    spec:
      serviceAccountName: cloud-sql-ksa # <-- ここにちゃんとKSAを指定
      terminationGracePeriodSeconds: 5
      containers:
      - name: appservice
        image: appservice
        ports:
        - containerPort: 5000
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: cloud-sql-secret
              key: username
              ...(略)...

GCEメタデータが取得できない

上の設定を行ったら今度はまた別の問題が発生。

Waiting for deployments to stabilize...
 - deployment/appservice: waiting for rollout to finish: 0 of 1 updated replicas are available...
 - deployment/clientservice: waiting for rollout to finish: 0 of 1 updated replicas are available...
 - deployment/appservice: container cloud-sql-proxy terminated with exit code 1
    - pod/appservice-77748675fc-dwhvk: container cloud-sql-proxy terminated with exit code 1
      > [appservice-77748675fc-dwhvk cloud-sql-proxy] 2021/07/16 10:38:38 current FDs rlimit set to 1048576, wanted limit is 8500. Nothing to do here.
      > [appservice-77748675fc-dwhvk cloud-sql-proxy] 2021/07/16 10:38:42 errors parsing config:
      > [appservice-77748675fc-dwhvk cloud-sql-proxy]   Get "https://sqladmin.googleapis.com/sql/v1beta4/projects/trace-microservices-sample/instances/us-west1~shoe-hat-inventory?alt=json&prettyPrint=false": metadata: GCE metadata "instance/service-accounts/default/token?scopes=https%!A(MISSING)%!F(MISSING)%!F(MISSING)www.googleapis.com%!F(MISSING)auth%!F(MISSING)sqlservice.admin" not defined
 - deployment/appservice failed. Error: container cloud-sql-proxy terminated with exit code 1.

これはGKEのアドオンとしてConfig Connectorというものを追加してあげないといけないらしい。

gcloud container clusters update trace-sample --update-addons ConfigConnector=ENABLED
Updating trace-sample...done.
Updated [https://container.googleapis.com/v1/projects/trace-microservices-sample/zones/us-west1-b/clusters/trace-sample].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-west1-b/trace-sample?project=trace-microservices-sample

それでも同様のエラーが発生するのでこれを試してみた。

$ gcloud services enable sqladmin.googleapis.com

しかしこれでもだめ、よくよくドキュメントを見てみるとGKEからCloud SQLに接続する場合にはVPCネイティブじゃないとだめらしい。しかしこのクラスタはなっていない。

これはあとから変更できないのでクラスターを再構築するしか無い。

リソースが足りない

問題がConfig Connectorだと思ってデプロイしてみたらいろんなサービスが追加で入れられてリソースが足りなくなった。

最初クラスターを作り直そうかと思ったけど、せっかくなのでオートスケーリングでやってみる。

gcloud container clusters update trace-sample --enable-autoscaling --max-nodes 10

長くなったのでクラスターを再構築するところから始めます。

参考