Cloud RunにデプロイしようとしたKtor + Exposedのアプリケーションイメージが、Cloud SQLへ接続できないことが原因で何度もデプロイに失敗してしまった。解決までに数時間要してしまい、ネットを探してもExposedを使った時のCloud SQLへの接続方法を記した記事が日本語と英語も含めてほとんど見つからなかった。なので忘備録として残しておこうと思う。
まずローカルでCloud SQL Auth Proxyを立ち上げてCloud SQLに接続する場合、次のようなURLを構築すると思う。
val jdbcURL = "jdbc:postgresql://0.0.0.0:3306/postgres"
これに倣って、Cloud SQLの公開IPアドレスと取り替えてCloud SQLに接続しようとしてみた。
val jdbcURL = "jdbc:postgresql://公開IPアドレス/postgres"
次のようなエラーが発生した。
org.postgresql.util.PSQLException: The connection attempt failed. at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:331) at
Cloud RunからCloud SQLに接続する方法として、TCPで接続する方法とUnixドメインソケットを使って接続する方法がある。各URLのフォーマットは次の通り。
TCPで接続する場合
val jdbcURL = "jdbc:postgresql:///$databaseName?cloudSqlInstance=$instanceConnectionname&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=$user&password=$password"
val jdbcURL = "jdbc:postgresql:///$databaseName?unixSocketPath=$unixSocketPath&cloudSqlInstance=$instanceConnectionname&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=$user&password=$password"
Unixドメインソケットを使って接続する場合は、unixSocketPath
クエリーパラメーターを渡す必要があるので注意する。
各変数にどんな値を代入すれば良いかは次の通り。
databaseName
- 接続したいデータベース名
- postgres (例
- 接続したいデータベース名
instanceConnectionName
socketFactory
cloud-sql-jdbc-socket-factory
ライブラリにあるクラス。com.google.cloud.sql.postgres.SocketFactory
を渡す。
unixSocketPath
- ソケットへのパス
/cloudsql/接続名(instanceConnectionName変数と同じ値)
- ソケットへのパス
user
- データベースのユーザー名
password
- データベースのパスワード
Socket Factoryを使えるようにするためにcloud-sql-jdbc-socket-factory
を依存関係として追加する。
dependencies { implementation("org.postgresql:postgresql:$postgresql_version") ... implementation("com.google.cloud.sql:postgres-socket-factory:1.7.2") }
依存関係を追加しないでクラス名だけ指定した場合は次のようなエラーが発生する。
org.postgresql.util.PSQLException: The SocketFactory class provided com.google.cloud.sql.postgres.SocketFactory could not be instantiated. at org.postgresql.core.SocketFactoryFactory.getSocketFactory(SocketFactoryFactory.java:43) at org....
実際のコードは次の通り。
object DatabaseFactory { fun init( user: String = "", password: String = "", databaseName: String = "", instanceConnectionName: String = "", unixSocketPath: String = "", ) { val driverClassName = "org.postgresql.Driver" val jdbcURL = "jdbc:postgresql:///$databaseName?unixSocketPath=$unixSocketPath&cloudSqlInstance=$instanceConnectionName&socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=$user&password=$password" val database = Database.connect( url = jdbcURL, driver = driverClassName, user = user, password = password, ) .... } }
各変数の値は環境変数として展開して渡すようにする。そのために、application.conf
を設定する。
google { cloud_sql { username = "takagimeow" username = ${?DB_USER_NAME} password = "takagimeow_pass" password = ${?DB_USER_PASS} path = "postgres" path = ${?DB_PATH} database_name = "" database_name = ${?DATABASE_NAME} instance_connection_name = "" instance_connection_name = ${?INSTANCE_CONNECTION_NAME} unix_socket_path = "" unix_socket_path = ${?UNIX_SOCKET_PATH} } }
設定した環境変数はApplication.module()
で取得し、DatabaseFactory.init()
の呼び出し時に渡す。
fun Application.module() { DatabaseFactory.init( user = environment.config.property("google.cloud_sql.username").getString(), password = environment.config.property("google.cloud_sql.password").getString(), databaseName = environment.config.property("google.cloud_sql.database_name").getString(), instanceConnectionName = environment.config.property("google.cloud_sql.instance_connection_name").getString(), unixSocketPath = environment.config.property("google.cloud_sql.unix_socket_path").getString() ) ... }
それでも接続できない場合
Cloud SQL Admin APIが有効になっていない可能性があるので、必ず有効になっているかを確認する。
NestJS + Prisma + Cloud Run + Cloud SQLを試す
ソケットパスに関して公式ドキュメントでは次の様に書かれている。
注: PostgreSQL スタンダードでは、ソケットパスに .s.PGSQL.5432 接尾辞が含まれている必要があります。一部のライブラリではこの接尾辞が自動的に適用されますが、他のライブラリでは、ソケットパスを以下のように指定する必要があります。
なので、一度/.s.PGSQL.5432
をソケットパスの末尾につけて試してみる。
Connect from App Engine standard environment | Cloud SQL for PostgreSQL | Google Cloud
参考
App Engine から Cloud SQL に接続する - albatrosary's blog
クイックスタート: Cloud Run から Cloud SQL for PostgreSQL に接続する | Google Cloud
Cloud Run から接続する | Cloud SQL for PostgreSQL | Google Cloud
インスタンスの作成 | Cloud SQL for PostgreSQL | Google Cloud
Cloud Run を徹底解説! - G-gen Tech Blog
Identity-Aware Proxy(IAP)とCloud Armorを使用してCloud Runサービスへのアクセス制御を実装する - G-gen Tech Blog
Cloud SQL Auth Proxy を使用して Cloud Run から Cloud SQL に接続する - G-gen Tech Blog
ktor - How connect tot Google Cloud SQL via Exposed - Stack Overflow
I ve been using unix domain sockets in mac with ktor It s be | Ktor | Kotlinlang
Node.js+SequelizeでCloud RunからCloud SQLへ接続する方法
Java を使用してソケット接続を作成する | Cloud SQL for PostgreSQL | Google Cloud