GKEのGoアプリからCloud Sql Proxy経由でCloudSQL第2世代へ接続する

# 概要
GKEのDocker上GoアプリからCloud Sql Proxy経由でCloudSQL第2世代に接続させてみたので備忘録として残しておく


# 手順

## DB作成
google cloud console上でcloudSQLのdbを作成する
![1.png](https://qiita-image-store.s3.amazonaws.com/0/34039/691f408c-4906-1641-d228-1510659a87d8.png)
`第２世代`を選択する

DB名は`db-dev`にする

`フェールオーバレプリカの作成`にチェックを入れ、作成する
![2.png](https://qiita-image-store.s3.amazonaws.com/0/34039/00b5e7c1-36cb-2a3f-ff00-766616ed0dc1.png)

インスタンスが作成されたことを確認する
![3.png](https://qiita-image-store.s3.amazonaws.com/0/34039/c0e43166-0f20-d6ea-72f4-91be011ccd7c.png)

ユーザのパスワードを設定する
![4-1.png](https://qiita-image-store.s3.amazonaws.com/0/34039/e8563131-8da4-834f-f375-96953a764985.png)


## GKEからDB接続確認とユーザ権限作成
接続確認、ユーザ権限作成用のインスタンスを作成する

```
gcloud compute instances create sql-client --scopes=sql-admin --machine-type=f1-micro \
--network=lovelytokyo --subnet=lovelytokyo \
--zone=asia-northeast1-b  
```

接続する

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

cloud_sql_proxyをインストールする

```
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 clientをインストールする

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

cloud_sql_proxyを起動する

```
sudo ./cloud_sql_proxy -dir=/cloudsql -instances='lovelytokyo:asia-northeast1:db-dev=tcp:3306'
```

接続する

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

db作成する

```
CREATE DATABASE hawai DEFAULT CHARACTER SET utf8;
```

DB `hawai`にユーザ`cloudmaster` がproxy経由でアクセスした際の権限を設定する

```
GRANT SELECT,INSERT,UPDATE,DELETE ON hawai.* TO 'cloudmaster'@'cloudsqlproxy~%';
FLUSH PRIVILEGES;
```



## GKEのDocker上GOアプリから接続
### 1. サービスアカウントキーの作成

google cloud console上でサービスアカウントキーを作成する
![5-1.png](https://qiita-image-store.s3.amazonaws.com/0/34039/05c84199-cdf7-5ead-00b7-da3b763e734a.png)
![6-1.png](https://qiita-image-store.s3.amazonaws.com/0/34039/f934f766-175c-6a9b-c6b8-25bae3632df2.png)
![7.png](https://qiita-image-store.s3.amazonaws.com/0/34039/72b3926b-083b-acb1-912a-f57be5c03ce0.png)

作成された`Cloud SQL Service account`のjsonファイルをダウンロードし、以下に保存

```
/path/to/secrets/cloudsql/lovelytokyo-xxxx-xxx.json
```


### 2. インスタンスからCloudSQLへアクセスするためのsecret作成

この時、jsonファイルのパスは、1.で保存したパスにする

```
kubectl create secret generic cloudsql-oauth-credentials --from-file=credentials.json=/path/to/secrets/cloudsql/lovelytokyo-xxxx-xxx.json
```


### 3. データベース・アクセス時に使うユーザとパスワード作成

goアプリで使う

```
kubectl create secret generic cloudsql-master-user --from-literal=username=cloudmaster
kubectl create secret generic cloudsql-master-password --from-literal=password=masterpasswd
```

### GOアプリのdeployment.yaml

```
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name:app-sample
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        application: app-sample
        tier: app
    spec:
      imagePullSecrets:
      - name : gcp-registry-key
      containers:
      - image: gcr.io/lovelytokyo/app-sample
        name: app-sample
        ports:
        - containerPort: 8080
          protocol: TCP
        imagePullPolicy: Always
        env:
          - name: MASTER_USER
            valueFrom:
              secretKeyRef:
                name: cloudsql-master-user （3.で作成したものを参照する）
                key: username
          - name: MASTER_PASSWORD
            valueFrom:
              secretKeyRef:
                name: cloudsql-master-password  （3.で作成したものを参照する）
                key: password
      - image: b.gcr.io/cloudsql-docker/gce-proxy:1.05
        name: cloudsql-proxy
        command: ["/cloud_sql_proxy", "--dir=/cloudsql",
                  "-instances=lovelytokyo:asia-northeast1:db-dev=tcp:3306",
                  "-credential_file=/secrets/cloudsql/credentials.json"]
        volumeMounts:
          - name: cloudsql-oauth-credentials
            mountPath: /secrets/cloudsql
            readOnly: true
          - name: ssl-certs
            mountPath: /etc/ssl/certs
          - name: cloudsql
            mountPath: /cloudsql
      volumes:
        - name: cloudsql-oauth-credentials
          secret:
            secretName: cloudsql-oauth-credentials
        - name: ssl-certs
          hostPath:
            path: /etc/ssl/certs
        - name: cloudsql
          emptyDir:
```

### アプリでの接続サンプル

環境変数に設定した、ユーザ名とパスワードを使って接続する

```
user := os.Getenv("MASTER_USER")
  passwd := os.Getenv("MASTER_PASSWORD")
  db := "hawai"

  connStr := fmt.Sprintf("%s:%s@tcp(localhost:3306)/%s%s", user, passwd, db, option)
```