はじめに
Node.js+Express(TypeScript)プロジェクトをGoogle Cloud Run で動かしつつ、TypeORMでGoogle Cloud SQLに接続するするのに少し詰まったため、ポイントを簡単にまとめてみました。
本記事の内容に入る前に公式ドキュメントの「Cloud Run を構成する」のセクションまで行ってください。本記事はこのドキュメント内の「Cloud SQL への接続」と同じ作業をTypeORM向きに書いたものです。
DBエンジンはMySQLを前提としています。
TypeORMについては以下も合わせて参照してください。
結論
TypeORMのDataSourceオブジェクトに渡すオプションに以下を追加し、host
とport
の2つのプロパティを削除することで、ソケット接続ができました。host
とport
のいずれか片方でも設定している(undefined
でない)とsocketPath
は無視され127.0.0.1:3306
を標準値としたIPアドレスでの接続になってしまうようです。
{
socketPath: `/cloudsql/{Cloud SQLインスタンスの接続名}`,
}
つまり、以下のようにすればOK。(もちろんsocketPath
以外の項目は各自の環境に合わせて適切なものにしてください。)
const options: DataSourceOptions = {
type: "mysql",
synchronize: true,
logging: true,
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
entities: [path.join(__dirname, "/entity/*.ts")],
socketPath: `/cloudsql/{Cloud SQLインスタンスの接続名}`,
};
const dataSource = new DataSource(options);
dataSource.initialize(); // 接続
環境
package.jsonから関係するものだけ抜粋しました。TypeORMはバージョン0.3.6
、MySQLドライバーは2.18.1
です。
"dependencies": {
"@types/express": "^4.17.13",
"@types/node": "^17.0.41",
"express": "^4.18.1",
"mysql": "^2.18.1",
"ts-node": "^10.8.1",
"typeorm": "^0.3.6",
"typescript": "^4.7.3",
}
Cloud Run から Cloud SQl への接続
公式ドキュメントによれば、ローカルからアクセスする時(ipとポートを指定してhttp接続)と異なりUnix ソケット経由での接続になるようです。
パブリック IP パスの場合は、Cloud Run によって暗号化が行われ、Cloud SQL Auth Proxy を使用して Unix ソケット経由で接続します。
ローカルからCloud SQLへアクセスする場合、SSLを用いていればTypeORMの接続設定は概ね以下のようになっているかと思います。(ユーザー名やPWなどの関係ないプロパティは省略しています。)
const options: DataSourceOptions = {
type: "mysql",
host: "123.123.123.123",
port: 3306,
ssl: {
// Cloud SQLのコンソールから発行したSSL接続用の証明書類
ca: fs.readFileSync(path.join(__dirname, "/server-ca.pem")),
cert: fs.readFileSync(path.join(__dirname, "/client-cert.pem")),
key: fs.readFileSync(path.join(__dirname, "/client-key.pem")),
}
//...ユーザー名やPWなど
}
しかしCloud Run内からのアクセスの場合、SSLに必要な証明書類を持っていくことなくセキュアな環境でソケット接続によって通信が可能になっているようです。
ソケット通信を利用するために、TypeORMの設定(DataSourceOptions)を以下のように書き換えてください。
host
とport
の2つのプロパティを削除(undefined
)にしておくのがポイントです。これらに値が入ったままだとソケット接続になりません。ssl
もundefined
にしておきましょう。
const options: DataSourceOptions = {
type: "mysql",
socketPath: `/cloudsql/{Cloud SQLインスタンスの接続名}` // 追加
//...ユーザー名やPWなど
};
Cloud SQLインスタンスの接続名
Cloud SQLインスタンスの接続名はCloud SQLの管理画面に出てくる「このインスタンスとの接続」の「接続名」の部分に置き換えてください。
最後に
ググっていると、以下のようにextends
にネストさせないとダメという情報を見かけましたが、バージョン0.3.6
の時点ではその必要は無いようです。
const options: DataSourceOptions = {
extends:{
socketPath: `/cloudsql/${process.env.DB_HOST}`,
}
}
TypeORMのソースを見たところ、DataSourceOptions(共用体型/union)のうち1つであるMysqlConnectionOptions
の継承元のMysqlConnectionCredentialsOptions
にsocketPath
というプロパティがちゃんと定義されていました。
ソースはこちら。