GCPのCloud Run - Cloud SQLでデプロイしたらびっくりするほど詰まった

初めてGCPを使用してみて、SpringBootのアプリケーションをCloud RunとCloud SQLの構成でデプロイを試みたところ、Cloud SQLに接続するための情報が少くかなり苦労したので、備忘録として久々に記事を書こうと思いました

とりあえず動けばいい精神で構築しており、細かいことは間違っている可能性がありますので、公式ドキュメントなども合わせてご参照ください

## 使用技術など
- Spring Boot 2.7.1
- Java 11
- Gradle 7.4.1
- MySQL 8.0

## Cloud Runにデプロイする
こちらはすんなりデプロイできました

Cloud Runで動かす方法はかなり方法があるかと思いますが、私は以下の方法で行いました

![1cloud_run.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110704/a85a4000-9e30-9645-34f6-eeb37794c3b0.png)

1. Cloud Buildというサービスを使用し、GitHubのリポジトリにあるDockerfileからビルド(GitHubの特定のブランチへのプッシュをトリガーに以降のフローを自動で行うこともできます)
    ```dockerfile
    FROM openjdk:11
    WORKDIR /app
    COPY . .
    RUN sh gradlew build -x test
    ENTRYPOINT java -jar build/libs/project-api-0.0.1-SNAPSHOT-1.0.jar
    ```
1. Artifact Resistryにイメージを保管
1. ↑に保存されたイメージをCloud Runで実行

以上で、正常に実行されると生成されたURLにで確認できると思います(Cloud Runだとデフォルトでhttpsで発行してくれるんですね)

参照：[qiita.com: Google Cloud BuildをGitHubリポジトリで動かしてHello, World!
](https://qiita.com/suzuki-navi/items/0373f479f5c6e4d98c80)

Cloud SQLの接続のため、`Cloud Runのコンソール画面 > コンテナ > 変数とシークレット`で後半でいくつか環境変数を設定します

## Cloud SQLに接続する
情報がなくて一番苦労しました
Pythonなどは以下の公式ドキュメントを参照して接続できるかもしれませんが、SpringBoot上から接続するための情報がなく、調べまくる中でなんとか接続までこじつけることができました


[cloud.google.com: Cloud SQL 接続について](https://cloud.google.com/sql/docs/mysql/connect-overview?hl=ja)

### Cloud RunからCloud SQLへの接続方法について

一般的なクラウドサービスの接続は以下になるかと思います<br>
Cloud SQLをプライベートサブネットに配置し、パブリックサブネット経由でアクセスする

![2cloudSql_private.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110704/8edb4282-6baa-846d-5ce4-2833fa262a9a.png)

一方で今回は、Cloud SQL Auth Proxyを利用し、UnixSocket経由で接続を試みます

![cloudSql_auth_proxy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110704/b41dc422-bb83-a232-2ddc-7f396e6cb20b.png)

### 接続設定
#### application.propertiesの記載
ローカルで開発する時などは以下の設定になるかと思います
```application.properties
spring.datasource.url=jdbc:mysql://${DATABASE_HOST}:3306/${DATABASE_NAME}
spring.datasource.username=${DATABASE_USER_NAME}
spring.datasource.password=${DATABASE_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.configuration.map-underscore-to-camel-case=true
spring.test.context.cache.maxSize=128
```

一方で、今回の設定は以下になります
```diff
- spring.datasource.url=jdbc:mysql://${DATABASE_HOST}:3306/${DATABASE_NAME}
+ spring.datasource.url=jdbc:mysql://google/${DATABASE_NAME}\
+   ?cloudSqlInstance=${INSTANCE_CONNECTION_NAME}\
+   &unixSocketPath=${INSTANCE_UNIX_SOCKET}\
+   &socketFactory=com.google.cloud.sql.mysql.SocketFactory
spring.datasource.username=${DATABASE_USER_NAME}
spring.datasource.password=${DATABASE_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.configuration.map-underscore-to-camel-case=true
spring.test.context.cache.maxSize=128
```

datasouce urlのアップデートを行います<br>
- `${DATABASE_HOST}:3306`を`google`に変更
- `cloudSqlInstance`にCloud SQLコンソール画面の<strong>接続名</strong>を追加(`プロジェクトID:リージョン:インスタンス`の形式になっています)
- `unixSocketPath`に、`/cloudsql/{接続名}`を追加
    - Cloud Runをコンソールで作成する際に、一番下に`Cloud SQL 接続`の項目があると思いますが、そこに接続したいインスタンスを設定すると`/cloudsql`のディレクトリにてUnixSocketのコネクションが開始します
- `socketFactory`に`com.google.cloud.sql.mysql.SocketFactory`を追加

#### build.gradleの記載を追加
```
dependencies {
	implementation 'com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.15.2'
}
```
:::note info
詳しくは以下を参照し、バージョンなどは調整して下さい
[mvnrepository.com: gradleの設定](https://mvnrepository.com/artifact/com.google.cloud.sql/mysql-socket-factory-connector-j-8/1.15.2)
:::

ここでCloud SQL Auth ProxyのSocket Factoryを使用できるように設定します<br>
ローカルにAuth Proxyをインストールし、MySQLコマンドで接続する場合は`mysql -u DATABASE_USER_NAME -p"DATABASE_PASSWORD" -S cloudsql/{接続名}`を指定することになりますが、`-S`の部分を使えるようにしているんだと思います

### 最後に
以下のリポジトリに、MySQLの他にPostgresSQLの接続設定などもありましたので、ご参考までに
[github.com/GoogleCloudPlatform](https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory/blob/main/docs/jdbc.md)

#### 参照情報
[cloud.google.com: Cloud Runから接続する](https://cloud.google.com/sql/docs/mysql/connect-instance-cloud-run?hl=ja#java)
[cloud.google.com: Cloud SQL Auth Proxyについて](https://cloud.google.com/sql/docs/mysql/sql-proxy?hl=ja)