GKEからCloud SQLに接続する方法

Deisのpostgresをoff-clusterにする(Cloud SQLを利用) - まーぽんって誰がつけたの?Deisのpostgresをoff-clusterにする(postgresql on GCEを利用) - まーぽんって誰がつけたの?でCloud SQLをdeisのdatabaseとしようともがいてたけど解決した話。

Cloud SQLはRDSと違う

Cloud SQLAWSでいうRDS的なやつ。ただちょっと違うのが、同じVPC的な論理的に同じネットワーク内に存在することができずに、別ネットワークになってしまう。 なので、GKE(Google Container Engine)のネットワークとCloud SQLはインターネットを経由しないとつながらないということになる。

GCPが用意してるCloud SQL接続方法

1. 接続してくるグローバルIPアドレスを許可する

GKEのCluster内に存在するNodeは単なるGCEのインスタンスなので一つ一つはグローバルIPを持っている。なので、このIPを指定してあげる。 ただ、Nodeが増えたり減ったりしたときに常にIPアドレスを管理しないといけずあまりよい方法とはいえない :no_good:

2. SSLで接続する

IPアドレスを許可しない場合、SSL証明書を使って接続する。 基本的にdriverはSSL接続は対応してるからまぁこれでもいいんだけど、たまに対応してないミドルウェアなんかがあって取り扱いがちょっと面倒。特にDeisの場合、そういうオプションは用意されてないので、PRをして変更を受け入れてもらわないといけないという状況だった :rolling_eyes:

3. CloudSQL Proxyを使う

これが一番よい方法。Googleが用意してるProxyで、binaryやDocker Imageでinstallして起動するだけで接続できるようになる。Cloud SQL Proxyを起動する際に、Cloud SQLに接続可能なAPI Key的なものと、Cloud SQLインスタンス名を渡してあげるだけで接続をproxyしてくれる。 あとは、普通にproxyが起動しているインスタンス上で、127.0.0.1に対して接続しにいけばCloud SQLにつながってくれる :100:

ただ、単純なVMインスタンスであればこれでいいが、GKE(Kubernetes)上で使う場合は、ちょっと一工夫がいる :wrench:

公式で紹介されてるGKEからCloud SQLに接続しに行く方法

Kubernetesでは、PodというのがContainerの集まりで、それらを何個起動するかとかRolling Updateリリースとかを管理しているDeploymentというリソースがある。 で、公式で紹介されてるのは、DeploymentのPodにCloudSQL ProxyをDocker Imageからcontainerを立てる方法。

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

こんな風に、podの中にwordpressっていうimageでcontainerを起動させてるとしたら、そこに、cloud sqlのproxyのimageを追記する。 そうすると、wordpressのcontainerからは、127.0.0.1で接続しにいける。ただ、これだと、Deis本体に手を入れる必要がある。

- image: wordpress:xxx
  name: wordpers
    ・ 略
    ・
- image: gcr.io/cloudsql-docker/gce-proxy:1.09
  name: cloudsql-proxy
  command: ["/cloud_sql_proxy", "--dir=/cloudsql",
            "-instances=[INSTANCE_CONNECTION_NAME]=tcp:[PORT]",
            "-credential_file=/secrets/cloudsql/credentials.json"]
  volumeMounts:
    - name: cloudsql-instance-credentials
      mountPath: /secrets/cloudsql
      readOnly: true
    - name: ssl-certs
      mountPath: /etc/ssl/certs
    - name: cloudsql
      mountPath: /cloudsql
volumes:
  - name: cloudsql-instance-credentials
    secret:
      secretName: cloudsql-instance-credentials
  - name: ssl-certs
    hostPath:
      path: /etc/ssl/certs
  - name: cloudsql
    emptyDir:

で、実際に、DeisのChartという設定ファイルを書き換えることで、proxy経由で無事接続することができた🎉 これはPRチャンスということで、Contribution.md読むと、PR出す前にSlackで一言相談してみてねとのことで、入ろうとするがlimitエラーかなんかでジョインできない。Deisの問い合わせから頼む入れてくれって送って入れてもらった。

これはDeisにPRチャンス!! 意気揚々とチャンネルに書き込んだ😎

f:id:masato47744:20170422024919p:plain

すると、フィーチャーフラグとかつけてくれたらいいよ!でも、なんでわざわざそんなことするの?みたいに言われて、あっさり別の解決策を教えてもらった。わざわざ同じpod内に作る必要なんてないとのこと。

f:id:masato47744:20170422024931p:plain

Cloud SQL Proxyを単に一つのDeploymentとServiceとして起動する

Kubernetes上で、あるPodから別のDeploymentのPodには接続しにいけないのかなーって思ってたのが間違いだった。実は、Kubernetes上では、Pod間の通信はServiceを利用すれば簡単にできる。しかもNameSpaceをまたがっていても!

KubernetesがCluster内のDNSもいい感じに設定していてくれて、Service名.NameSpace名というホスト名でつながることができる!!

最終的な構成はこういう感じ。

NameSpace deis
                       <host: pg-sqlproxy.sql-proxy>
 | deis-controller |-----------|
                               |
-------------------------------|---
NameSpace sql-proxy            |
                               ▼
                         | Service: pg-sqlproxy |
                               |
                               ▼
                         | Pod: gce-proxy |
                               |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~
Cloud SQL                      |
                               ▼
                         | PostgreSQL |

この概念を利用すれば、Deisの1アプリとして、Cloud SQL Proxyをdeployしたっていい。Communityではそういうやり方も教えてもらった。

f:id:masato47744:20170422025008p:plain

まとめ

Deisのことを調べていくとKubernetesのことを知っていかないといけないんだけど、知れば知るほど奥が深いというか至れり尽せりな機能が用意されててほんとすごい🚢