GKE とCloudSQL を組み合わせたい

k8s の中にRDB コンテナをデプロイして管理するもよいと思いますが、
RDB だけフルマネージドサービスを使うパターンもあるかと思います。

アプリケーションコンテナはGKE で、RDB はCloudSQL で動かすにはどうしようと考えていたところ、Google Cloud のドキュメントの中に Running Django on Google Kubernetes Engine というまさにやりたいことを実践しているドキュメントがあったので、やってみました。

ドキュメントは↓を参照してください。

Running Django on Google Kubernetes Engine  |  Python  |  Google Cloud

Google Cloud のドキュメントは結構和訳されているものがあるのですが、
今回の記事は英語だったのと、途中で少し躓くところもあったので、やったことを忘備録がてらメモを残そうかと思います。

誰かの参考になれば幸いです。

事前ノート

基本的にはドキュメントに記載されているコマンドスクリプトをそのままやるという感じなので、
部分的にしか書いていません。

また、今回はPostgreSQL instanse を使っているので、 psql コマンドで接続します。なので、事前に psql を使えるようにしておく必要があります。

MySQL の場合は検証してないですが、 基本的な操作は変わらないかと思うので、適宜MySQL に置換していただければと思います。

途中で設定しているパスワードなどは参考なので、各自適当な値を設定するようにしてください。

あしからず。

やったこと

デプロイするサービスはすでに用意されているものをpull してきて、それをビルドしました。

git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git
cd python-docs-samples/kubernetes_engine/django-tutorial

次にCloud SQL Proxy を使って、RDB インスタンスの生成と接続などなどやりました。インスタンス名は、一通り実行した感じだと、ドキュメント通りである必要はなく、適当で大丈夫だと思います。

gcloud services enable sqladmin

# Mac 用のCloud SQL Proxy をダウンロード
curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64

chmod +x cloud_sql_proxy

# ターミナルからinstance を生成
# 今回はpoll-instance という名前で作成
gcloud sql instances create poll-instance --database-version=POSTGRES_11 --tier db-f1-micro --region=asia-northeast1

ドキュメントには、 gcloud sql instances describe [YOUR_INSTANCE_NAME]というコマンドを使い、接続名を取得するという一文があります。

これは、 gcloud sql instances describe の結果に対して、grep grep connectionName とすることで適切な部分が取得できます。取得した値を [YOUR_INSTANCE_CONNECTION_NAME] として表現されています。

# connection name を調べる
gcloud sql instances describe poll-instance | grep connectionName

このconnection name とダウンロードしたcloud_sql_proxy を使ってlocal からinstance への接続を可能にします。

./cloud_sql_proxy -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:5432

おそらく、上記のコマンドを実行しても終了などしないと思います。 これは、当たり前といえば当たり前なのですが、ローカルPC とCloud SQL instance との間で接続が確立されているので、切れなくて問題ないです。

なので、バックグラウンドで実行しておくとかも方法はありますが、僕は、次のコマンドからは新しいターミナルのパネルを開いて実行しました。

ここからは、ローカルからCloud SQL instanse に対して操作を行います。

psql --host 127.0.0.1 --user postgres --password

つまづきポイント①
ここでのパスワードってなんだ?ってなりました。
なぜなら、ドキュメントには Use the Postgres client or similar program to connect to your instance. When prompted, use the root password you configured.とありますが、
作成したインスタンスに対して特にパスワードを設定した覚えがないからです。
ここでのパスワードは、console 画面のCloud SQL 画面で確認して入力すれば接続できました。

接続したら、DB の操作を行います。 ここでは、サービスを実行するのに必要な DATABASE の作成や DATABASETABLE に対する権限の設定を行います。

ここの操作はドキュメントにある通り実行するがよいと思います。 ただし、ユーザとそのパスワードは適宜設定できるので、任意の値を設定してください。 今回は、 [POSTGRES_USER] には、 poll_user[POSTGRES_PASSWORD] には、 poll_pw を設定しました。

CREATE DATABASE polls;
CREATE USER poll_user WITH PASSWORD 'poll_pw';
GRANT ALL PRIVILEGES ON DATABASE polls TO poll_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO poll_user;

次にサービスアカウントを作成します。
このサービスアカウントは、k8s クラスタからCloud SQL インスタンスに接続したり、クエリを投げるためのサービスアカウントになります。 設定する権限はドキュメント通り、以下の3つで十分でした。

  • Cloud SQL クライアント
  • Cloud SQL 編集者
  • Cloud SQL アドミン(管理者)

鍵を生成する必要があるので json フォーマットの鍵を作成してダウンロードしておきます。

ここからはローカルで一度動作確認し、その次にGKE インスタンスにpod を展開していきます。
このあたりは特にハマったポイントはなかったのと、個人的には k8s ⇔ Cloud SQL 間の通信ができているのか?を確認するほうが重要だったので、一部割愛しています。

export DATABASE_USER=poll_user
export DATABASE_PASSWORD=poll_pw

# GKE クラスタを作成
gcloud container clusters create polls \\n  --scopes "https://www.googleapis.com/auth/userinfo.email","cloud-platform" \\n  --num-nodes 4 --zone "us-central1-a"

# 作成したクラスタのクレデンシャルをkubectl にセット
gcloud container clusters get-credentials polls --zone "us-central1-a"

# クレデンシャルをkubectl コマンドに設定
kubectl create secret generic cloudsql-oauth-credentials --from-file=credentials.json=/path/to/service-account.json

# PostgreSQL のuser password を設定する
kubectl create secret generic cloudsql --from-literal=username=poll_user --from-literal=password=poll_pw

docker pull b.gcr.io/cloudsql-docker/gce-proxy

# ローカル環境でコンテナをbuild
docker build -t gcr.io/hatch-sydney/polls .

# gke にpush するためにauth の設定をして、push
gcloud auth configure-docker
docker push gcr.io/hatch-sydney/polls

# k8s クラスタに向けてデプロイ
kubectl create -f polls.yaml

ここまでの操作でpod をデプロイできました。 ハマリポイントはないと書きつつ、ハマリポイントが一つありました。

つまづきポイント②
kubectl コマンドでPostgreSQL の秘密情報を登録するコマンド

kubectl create secret generic cloudsql --from-literal=username=poll_user --from-literal=password=poll_pw

でどのユーザを設定するか悩みました。
なぜなら、ドキュメントには [PROXY_USERNAME] [PASSWORD] と書かれており、これどこで設定した?という気持ちになったためです。
実行したコマンドの通り、ローカルからCloud SQL Proxy を通じてDB 操作を行ったときのuser とpassword を設定するのが正しいかと思います。
僕はこれで問題なく接続できました。

残りは、pod のログを取ったり、実際にexternal ip で接続してみたりするだけです。

# deploy したpod のstatus やid を調べる
kubectl get pods

# polls pod のログを見る。 以下では見られない。
kubectl logs polls-fd676657d-9qfnw

# application のログを見たい場合は -c polls-app を指定する
kubectl logs polls-fd676657d-9qfnw -c polls-app
# Cloud SQL のログを見たい場合は -c cloudsql-proxy を指定する
kubectl logs polls-fd676657d-9qfnw -c cloudsql-proxy

# EXTERNAL-IP を調べて接続してみる
kubectl get services polls

最後のコマンドで得られたexternal ip に接続するとページが見られるかと思います。
そして、最後のハマリポイントです。

つまづきポイント③
kubectl logs <pod-id> だけではログは見られませんでした。この理由としては今回のpod には複数のコンテナが含まれており、その場合、どのコンテナを見るか?を指定する必要があります。
このことをすっかり忘れていたため、地味にハマりました。

コマンドのチートシートがあるので、忘れないために載せておきます。

kubernetes.io

まとめ

今回の気づきをまとめるとしたら、以下の3点でしょうか。

  • GKE とCloud SQLを組み合わせたdjango アプリをデプロイしたよ
  • いくつかハマリポイントあったよ
  • GKE とCloud SQL を接続する上では、Cloud SQL の権限を設定したサービスアカウントをkubectl に設定することでpod から接続できるみたいだよ

まだまだ勉強することがたくさんありそうです。