GKEからCloud SQLにCloud SQL Proxy経由で接続する方法

thumnail
2020-07-16

背景

GKEで立ち上げたアプリケーションからCloud SQLに接続する実装をやる機会があったので、そのやりかたを備忘録としてこの記事にまとめておく。

Cloud SQL Proxyを経由させる

GKEからCloud SQLへの通信を行う際、間にCloud SQL Proxyを挟む事が推奨されている。Cloud SQL Proxyは名前の通りProxyで、GKE内のアプリケーションがDBに接続を試みたい場合、初めにCloud SQL Proxyに対してリクエストを送信、そのリクエストを受け立ったCloud SQL ProxyがDBに対して代理でリクエストを送信する。公式のブログによるとCloud SQL Proxyを利用するメリットは次の2点と記載されていた。

  • 暗号化通信
  • 接続管理の簡略化

1つ目の「暗号化通信」はDBとCloud SQL Proxyの通信が暗号化される。これによりセキュアなDB接続が可能になる。2つ目の「接続管理の簡略化」はCloud SQL Proxy自体がCloud SQLとの認証を行ってくれるので、静的なIPアドレスをDBに割り当てなくても良い。

https://cloud.google.com/sql/docs/mysql/sql-proxy?hl=ja

認証情報はSecretに定義

MySQLのパスワードなどはSecretという仕組みを使う。こいつを使えばGKEで動くアプリケーションに安全に環境変数を渡す事ができる。

$ kubectl create secret generic <YOUR-DB-SECRET> \
--from-literal=db_user=root \
--from-literal=db_password=hoge123 \
--from-literal=db_name=hoge-db
secret/<YOUR-DB-SECRET> created

secretが追加されたかどうかを確認したい場合は、GCPのコンソール画面の「Kubernetes Engine→設定」を見れば確認できる。

sidecarコンテナを立ち上げる

アプリケーションのコンテナと並列にsidecarコンテナパターンという手法を使ってCloud SQL Proxyのコンテナを立ち上げる。このsidecarコンテナパターンっていうのは1つのPodの中に主たるコンテナ、Webサーバー・APIサーバーなどとは別にログを転送したり、コンテンツを取り込んだりするコンテナを並列で立ち上げるパターンのことを指す。詳しくは以下のQiitaの記事を読むと良いかも。

https://qiita.com/MahoTakara/items/03fc0afe29379026c1f3

サービスアカウントキーファイルを利用する

Cloud SQL Proxyに対してサービスアカウントを提供する必要がある。サービスアカウントはGCPのサービスアカウントのこと。GASとも言ったりする。これからすることの大枠を話すと、GKEに対して、GASを連携させる必要があり、一度、GASの情報をJSON形式に落として、これをGKEのsecretに変換することを行う。サービスアカウントの一覧は次のコマンドで確認することができる。

$ gcloud iam service-accounts list
NAME                                EMAIL                                               DISABLED
hoge-account                 hoge@developer.com  False

このサービスアカウントのkeyは次のコマンドを生成することができる。<一意のID>は「IAMと管理→サービスアカウント→サービスアカウントの詳細」に記載されている。

$ gcloud iam service-accounts keys create ./key.json \
  --iam-account <一意のID>>@project-id.iam.gserviceaccount.com
  
created key [ハッシュ値] of type [json] as [./key.json] for [<一意のID>]
$ kubectl create secret generic <YOUR-SA-SECRET> \
--from-file=service_account.json=./key.json
secret/<YOUR-SA-SECRET> created

ワークロードを生成する

Deploymentの定義をymlファイルに記述する

Deploymentはclusterにアプリケーションをデプロイする為の司令塔の役割を持つ。deployment.ymlにデプロイするアプリケーションコンテナの定義を記述して、GKEサービスにapplyするとそれらのPodをclusterにデプロイする為のワークロードが生成される。ワークロードは主にKubenrnetes上にコンテナをデプロイ、管理、スケジュールを行ってくれるものだ。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <YOUR-DEPLOYMENT-NAME>
spec:
  selector:
    matchLabels:
      app: <YOUR-APPLICATION-NAME>
  template:
    metadata:
      labels:
        app: <YOUR-APPLICATION-NAME>
    spec:
      containers:
      - name: <YOUR-APPLICATION-NAME>
        # ... other container configuration
        env:
        - name: DB_USER
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: db_user
        - name: DB_PASS
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: db_password
        - name: DB_NAME
          valueFrom:
            secretKeyRef:
              name: <YOUR-DB-SECRET>
              key: db_name
      - name: cloud-sql-proxy
        # It is recommended to use the latest version of the Cloud SQL proxy
        # Make sure to update on a regular schedule!
        image: gcr.io/cloudsql-docker/gce-proxy:1.17
        command:
          - "/cloud_sql_proxy"

          # Replace DB_PORT with the port the proxy should listen on
          # Defaults: MySQL: 3306, Postgres: 5432, SQLServer: 1433
          - "-instances=<INSTANCE_CONNECTION_NAME>=tcp:<DB_PORT>"

          # This flag specifies where the service account key can be found
          - "-credential_file=/secrets/service_account.json"
        securityContext:
          # The default Cloud SQL proxy image is based on distroless, which
          # runs as the "nonroot" user (uid: 65534) by default.
          runAsNonRoot: true
        volumeMounts:
        - name: <YOUR-SA-SECRET-VOLUME>
          mountPath: /secrets/
          readOnly: true
      volumes:
      - name: <YOUR-SA-SECRET-VOLUME>
        secret:
          secretName: <YOUR-SA-SECRET>

,,,は名前を自由に決めてしまって構わない。には前半で生成したsecretに付与した名前を記述する。<INSTANCECONNECTIONNAME>, <DB_PORT>はCloud SQLインスタンスの接続名とポートを記述する。接続名はコンソール画面の「SQL→対象のSQL→概要」に記載されているのでそちらを見ればよい。は上で作成したGASのsecretを指定すれば良い。

Deploymentをapplyする

次のコマンドを実行するとGKEにDeploymentがapplyされ、ワークロードが生成される。

$ kubectl apply  -f deployment.yaml

ワークロードでエラーが発生した場合のデバック方法

Deploymentに記述した内容が誤っていた場合(secretの指定をtypoしていた...etc)、ワークロードでpodのデプロイに失敗したというエラーが発生する。この時、podが吐いたエラーを確認することができる。まずはエラーを吐いたpodを次のコマンドで特定する。

$ kubectl get pods
NAME                          READY   STATUS                       RESTARTS   AGE
hoge-server-59797f8dc5-x6qzr   2/3     CreateContainerConfigError   6          8m21s

podのNAMEがわかったら次のコマンドにNAMEを指定し、実行する。

$ kubectl describe pod hoge-server-59797f8dc5-x6qzr

こうすることで、どこでエラーが起きていたかを把握できるので、podがエラーを吐いてデプロイできない時は活用するとよい。

参考サイト

https://cloud.google.com/sql/docs/mysql/connect-kubernetes-engine

profile

KATUO

web developer

六本木で月間利用者数数千万のサービスを運営するミドルベンチャーでWeb系エンジニアをやってます。フロントエンドはVue.js/Nuxt.js,サーバーサイドはGolang, クラウドはAWS, GCPを良く扱います。お仕事・イベント等の依頼はContactのフォームからお願いします。

KATUBLO

Copyright since 2018 KATUO All Rights Reserved.