GCE から Google Cloud SQL への接続方法


## 要約

- Google Cloud SQL Second Generation がリリース
- GCE インスタンスから接続するには Cloud SQL Proxy を使用する
	- サービスアカウントを使用すると安全
		- GCE デフォルトサービスアカウントが使える
	- 2種類の接続方法に対応
		- Unix Domain Socket
		- TCP Socket

## はじめに

Beta だった Google Cloud SQL Second Generation が 2016/8/16 に GA になった。

Google Cloud Platform では長らくマネージドな RDBMS を提供するサービスが AWS の RDS と比べて弱かったが、 Google Cloud SQL の Second Generation は RDS/MySQL や GCE インスタンス上の MySQL からの乗り換える選択肢になりうるサービスとなっている。今回は Google Cloud SQL に対する GCE からの接続方法をまとめる。

## 環境情報

Client: OS X El Capitan (10.11.5)
Google Cloud SDK: 121.0.0
Cloud SQL Proxy: 1.05

今回はプロジェクト名を cloud-sql-test とする。 gcloud config は適切に設定されているものとして進める。また、コンソールから Google Compute Engine API, Google Cloud SQL API をそれぞれ有効にする。

## 環境構築

### Cloud SQL インスタンスの作成

Google Cloud SDK に含まれる `gcloud` コマンドから Cloud SQL を使用するには `gcloud sql` サブコマンドを使う。
Second Generation では `--activation-policy` の指定は必須だが、Second Generation は使用に対する従量課金なので常に `ALWAYS` を指定して良いだろう。( 参照 [Which activation policy should I use?](https://cloud.google.com/sql/faq#activation_policy) )

```bash:
gcloud beta sql instances create sql-instance --database-version=MYSQL_5_7 --tier=db-f1-micro --activation-policy=ALWAYS --region=asia-east1
```

( 注: 2016/8/17 現在リリースされている Cloud SDK 121.0.0 では `gcloud sql` は `--database-version=MYSQL_5_7` に対応していないため `gcloud beta sql` サブコマンドを使っている。)


### 接続するクライアントとしての GCE インスタンスの作成

Cloud SQL に接続するには グローバル IP アドレスによるホワイトリストか Cloud SQL Proxy が必要となる。オートスケーリングなどを考慮すると接続元インスタンスの IP アドレスを管理することは一般的に難しいこともあり、Cloud SQL Proxy を使用することが推奨されている。Cloud SQL Proxy の使用には適切な権限が必要である。今回はインスタンスに GCE デフォルトサービスアカウントの sql-admin スコープを設定することで解決する。

```bash:
gcloud compute instances create sql-client --scopes=sql-admin --machine-type=f1-micro
```


## 接続

クライアントのインスタンスに SSH でログインする。今回は debian ユーザを用いる。

```bash:
gcloud compute ssh debian@sql-client
```

cloud_sql_proxy コマンドを実行可能な状態にする。

```bash:
curl https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -o cloud_sql_proxy
chmod +x cloud_sql_proxy
sudo mkdir /cloudsql; sudo chmod 777 /cloudsql
```


動作確認のため mysql コマンドをインストールする。

```bash:
sudo apt-get install mysql-client
```

接続方法はいくつかあるが、大きく分けて Unix Domain Socket と TCP Socket の2通りがある。

今回説明していないものも含む接続情報の詳細については下記に書かれている。
https://cloud.google.com/sql/docs/sql-proxy#instances-options

接続先情報は `[PROJECT]:[REGION]:[INSTANCE_ID]` の形式となる。以下では `cloud-sql-test:asia-east1:sql-instance` として説明する。

### Unix Domain Socket を使った接続

MySQL は localhost への接続方法としてデフォルトで Unix Domain Socket を使用する。TCP Socket よりオーバーヘッドが少ないため性能にも優れるとされている。Unix Domain Socket の使用方法はいくつかあるが、今回は -fuse オプションを使用する。

```bash:
sudo apt-get install fuse

sudo ./cloud_sql_proxy -dir=/cloudsql -fuse

mysql --user root --socket /cloudsql/cloud-sql-test:asia-east1:sql-instance
```

fuse オプションを使用するメリットは Unix Domain Socket のファイル名を開こうとするまで接続先の指定を遅延できることである。これは cloud_sql_proxy コマンドのオプションではなくアプリケーション側に接続に関する情報を集約できるという点で優位性がある。

### TCP Socketを使った接続

Unix Domain Socket に対応していないライブラリもしくはプログラムから MySQL に接続する必要がある場合は TCP Socketを通して接続することができる。

TCP Socketを listen する段階で cloud_sql_proxy に接続情報を指定する必要がある。

```bash
sudo ./cloud_sql_proxy -dir=/cloudsql -instances='cloud-sql-test:asia-east1:sql-instance=tcp:3306'

mysql --user root --host 127.0.0.1

# localhost を指定する場合は protocol を TCP に強制する必要がある。(--port 3306 としても unix socket に繋げにいくのは変わらない)

mysql --user root --host localhost --protocol TCP

```


## 今回の構成の Deployment Manager 版

今回動作確認のために gcloud コマンドで構成した環境は下記ファイルで構成できる。

```yaml:cloudsql.yaml
resources:
- type: sqladmin.v1beta4.instance
  name: sql-instance
  properties:
    region: asia-east1
    databaseVersion: MYSQL_5_7
    settings:
      tier: db-f1-micro
      activationPolicy: ALWAYS
- type: compute.v1.instance
  name: sql-client
  properties:
    zone: asia-east1-a
    machineType: zones/asia-east1-a/machineTypes/f1-micro
    serviceAccounts:
    # email of Compute Engine default service account
    - email: XXXXXXXXXXXX-compute@developer.gserviceaccount.com
      scopes:
      - https://www.googleapis.com/auth/sqlservice.admin
    disks:
    - deviceName: boot
      type: PERSISTENT
      boot: true
      autoDelete: true
      initializeParams:
        sourceImage: projects/debian-cloud/global/images/family/debian-8
    networkInterfaces:
    - network: global/networks/default
      accessConfigs:
      - name: External NAT
        type: ONE_TO_ONE_NAT
```

`XXXXXXXXXXXX-compute@developer.gserviceaccount.com` は下記コマンドで確認した `Compute Engine default service account` のアドレスに書き換える必要がある。

```
gcloud iam service-accounts list
```

下記の例のように実行できる。

```bash
gcloud deployment-manager deployments create --config cloudsql.yaml cloudsql
```