冗長構成のCloud SQLとGKEの接続方法

最近仕事でGCPを触りはじめ、特にGKEを使ったアプリケーションの構築に興味を持っています。基本的には、まず公式ドキュメントやチュートリアルで理解を深めているのですが、それだけでは分からなかった点があったので、まとめました。
今回は、冗長構成したCloud SQLに対して、GKE上のコンテナから接続する方法を紹介します。一般的に高可用性や負荷分散を目的として、データベースを冗長構成することがあると思います。Cloud SQLの場合、Masterインスタンスに対して、Failover Replicaを作成することで、耐障害性と負荷性能を高める構成をとることができます。GKEからCloud SQLインスタンスに接続するには、Cloud SQL Proxy Docker イメージを使うことが一般的で、単一のCloud SQLインスタンスに接続する方法は、[公式ドキュメント](https://cloud.google.com/sql/docs/mysql/connect-container-engine?hl=ja)にも記載されていますが、複数のインスタンスへの接続設定はなかったため、実際に試した設定をまとめました。
# サービス構成
- 最終的に以下の構成を構築します
- GKE
    - 接続の検証のために、mysql-clientコンテナを立てます
    - Cloud SQLに接続するために、cloudsql-proxyコンテナを立てます
- Cloud SQL
    - Master, Failover Replica, Read Replicaの3種類があります
    - Failover ReplicaはRead Replicaとしても使うことができ、ゾーン障害時にはMasterに昇格します
    - 耐障害性と負荷性能を高めるため、Master（write専用）とFailover Replica（read専用）の構成としました

![構成_20171130_03.JPG](https://qiita-image-store.s3.amazonaws.com/0/211033/d6c3fa0e-ec89-a7f3-ae13-77c0c9c9488f.jpeg)


# 構築手順
## Cloud SQLの設定
- 公式ドキュメントを参考に、Masterインスタンスを作成
    - https://cloud.google.com/sql/docs/mysql/create-instance?hl=jaCloud
    - 設定オプションを表示＞自動バックアップと高可用性の有効化　からフェイルオーバーレプリカの作成にチェックを入れると、自動でFailover Replicaが生成される
![CloudSQL_FailoverReplica_01.JPG](https://qiita-image-store.s3.amazonaws.com/0/211033/2ec4d3a3-9423-5163-d21f-096becde87fc.jpeg)

## GKEの設定
### Cluster作成
- 公式ドキュメントを参考にClusterを作成
    - https://cloud.google.com/container-engine/docs/clusters/operations?hl=ja
- 今回の構成を作成するにあたっては、zoneは適宜選択してよい
    - GPCではデフォルトのVPCネットワークが用意されているので、指定しなければデフォルトのVPCに構築され、ファイヤウォールルールも適用される
    - 今回は外部にアプリケーションを公開する想定はないので、ネットワークに関しても気にする必要はない
    
### Cloud SDKインストール
- 公式ドキュメントを参考にCloud SDKをインストール
    - https://cloud.google.com/sdk/?hl=ja
- Webブラウザ上のcloud Shellからもgcloudコマンドは使えるが、後続の設定でローカルでの作業が必要になるため、用意しておく
    - `gcloud init`でgcloudコマンドを使用できるようにする
    
### 操作するクラスターの指定とkubectlコマンドの取得
- 以下のコマンドをCloud SDKで実行

```
$ gcloud config set container/cluster [NAME]
$ gcloud container clusters get-credentials [NAME] --zone=[zone name]
$ gcloud auth application-default login
```
### 接続のための認証情報設定
- 公式ドキュメントを参考に、1. APIを有効にする から 5. シークレットの作成　まで実施
    - https://cloud.google.com/sql/docs/mysql/connect-container-engine?hl=ja
- コマンドは全てインストールしたCloud SDKで実行する
    
## Dockerイメージのデプロイ
- デプロイするイメージは以下の2つ
    - mysql-client：接続を確認するためのDockerイメージ
    - cloudsql-proxy：Cloud SQL Proxy Docker イメージ　※公式のイメージを使う
    
### mysql-clientのイメージを作成
- Dockerfileからイメージを作成する

```:Dockerfile
FROM mysql

ENTRYPOINT ["tail", "-f", "/dev/null"]
```

- pullしたイメージをContainer registoryにpushする
   
```
$ docker tag [image_id] asia.gcr.io/[project_id]/[image]:tag
$ gcloud docker -- push asia.gcr.io/[project_id]/[image]:tag
```
### イメージのデプロイ
- GKEにイメージをデプロイする際には、Kubernetesのコマンドを使用する
- Kubernetesにはコンテナの集合体であるPodという概念があり、Podを作成するために、以下のyamlファイル（Deployment）を作成する
    - cloudsql-proxyの接続先をカンマ区切りで並べ、ポートは違うものにするのがポイント

```yaml:test-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: gke-sql-test
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: gke-sql-test
    spec:
      imagePullSecrets:
      - name : gcp-registry-key
      containers:
      - image: asia.gcr.io/[project_id]/[image]:tag
        name: mysql-client
      - image: gcr.io/cloudsql-docker/gce-proxy:1.11
        name: cloudsql-proxy
        command: ["/cloud_sql_proxy", "--dir=/cloudsql",
                  "-instances={Master接続名}=tcp:3306,{Failover Replica接続名}=tcp:3307",
                  "-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:
```

- 以下のコマンドを実行する

```
$ kubectl create -f test-deployment.yaml
```
以上で設定は終了です。
最後に実際にインスタンスに接続することができるか、mysql-clientコンテナにログインして確認を行いたいと思います。

## 検証
- mysql-clientコンテナにログイン

```
$ kubectl exec -it gke-sql-test -c mysql-client /bin/bash
```

- mysqlのコマンドで接続を確認する

```
$ mysql -h 127.0.0.1 -P 3306 -u [user-name] -p
$ mysql -h 127.0.0.1 -P 3307 -u [user-name] -p
```