VPC Direct Egress で Cloud Run から直接 Cloud SQL にアクセス
こんにちは。すらぼです。好みの構成はシンプルな構成です。
以前、ブログ記事で Cloud Run functions から Cloud SQL に接続する方法として、サーバレスVPCコネクタを使用した方法を紹介しました。
ただ、より良い方法として VPC Direct Egress というものがあり、費用やパフォーマンスなど様々な面で有利な方法となります。
今回は、 VPC Direct Egress の方法での接続方法を紹介していきます。
VPC Direct Egress とは?
VPC Direct Egress は、Cloud Run サービスが VPC ネットワークに直接接続できる機能です。従来のサーバーレス VPC コネクタのような中間のコンポーネントを必要とせず、Cloud Run から VPC 内のリソースに直接アクセスできます。
サーバーレス VPC コネクタと VPC Direct Egress の違い
両者の主な違いを表にまとめました。
| 項目 | サーバーレスVPCコネクタ | VPC Direct Egress |
|---|---|---|
| 対応サービス | Cloud Run、Cloud Functions、App Engine | Cloud Runのみ |
| アーキテクチャ | 専用のコネクタインスタンス経由で接続 | Cloud Run が直接 VPC に接続 |
| 必要なIPアドレス数 | 少ない | 多い |
| レイテンシ | 高い | 低い |
| 固定費 | あり(約$6.10~/月) | なし |
| データ転送料金 | $0.12/GB | $0.01/GB(約92%安い) |
| スループット上限 | コネクタ全体で最大10Gbps | インスタンスあたり最大1Gbps |
スループットについて補足すると、サーバーレスVPCコネクタは複数のサービスで共有できるため、合計トラフィックが多い場合に有利です。一方、VPC Direct Egressは各インスタンスが独立して1Gbpsを使えるため、インスタンスが多くなると最終的なスループットでは勝るケースもあります。
後発ということもあり、基本的には VPC Direct Egress に軍配が上がる項目が多いですが注意点もあります。
それは、IPアドレス範囲を多めに確保しておく必要がある という点です。
VPC Direct Egress はサブネットから IP アドレスを割り振りますが、スケーリング時にはインスタンス数分の IP アドレスが必要となります。
公式ドキュメントには「十分な IP アドレスを確保するためにサブネットのアドレス範囲を /26 以上にする必要がある」という記述があります。
トラフィックの急増時に迅速にスケールアップできるように、Cloud Run は 16 個(28 サブネット マスク)のブロックで IP アドレスを予約します。Cloud Run が割り振った IP アドレスを確認する。Cloud Run 全体で使用できる十分な IPv4 アドレスを確保するには、サブネットの IPv4 アドレス範囲を /26 以上にする必要があります。
https://cloud.google.com/run/docs/configuring/vpc-direct-vpc?hl=ja#scale_up_and_scale_down
また、対応サービスは現時点では Cloud Run のみとなっています。App Engine のような非対応のサービスの場合は、サーバーレスVPCコネクタを利用する必要があります。
その他の制限事項については、以下の公式ドキュメントをご確認ください。
コストの具体例
月100GBのデータ転送がある場合の比較です。
サーバーレスVPCコネクタの場合
- コネクタインスタンス料金:$6.10/月
- データ転送料金:100GB × $0.12 = $12
- 合計:$18.10/月
VPC Direct Egressの場合
- 固定費:$0
- データ転送料金:100GB × $0.01 = $1
- 合計:$1/月
この例では約94%のコスト削減が可能です。特に、固定費として大部分を占めるVMの起動時間料金が減ることで、開発環境などでは大幅なコスト削減効果があります。
どちらを選ぶべきか
VPC Direct Egress を選ぶべき場合
- Cloud Run を使用している
- コストを最小化したい
- より低いレイテンシが必要
- シンプルな構成を好む
サーバーレスVPCコネクタを選ぶ必要がある場合
- Cloud Functions や App Engine など、Direct Egress 非対応のサービスを利用している。
Cloud Run で新規に接続を作成する場合、特別な理由がない限り VPC Direct Egress を選択することをお勧めします。
設定方法
設定自体は非常に簡単です。
- Cloud SQL と、プロジェクト内の VPC との間で PSA(プライベートサービスアクセス)を確立する。
- Cloud Run の設定で、 PSA で接続されている VPC に対して Direct VPC Egress を設定する。
以上です。設定自体もシンプルなので、早速紹介していきます。
やってみる
ではまず、Cloud SQL インスタンスで PSA を有効化し、自分のプロジェクトの VPC との接続を確立します。この設定自体は、サーバレスVPCアクセスでも行う設定なので、設定済みの場合はスキップしても問題ありません。
Cloud SQL インスタンスの編集画面の「接続」から、「プライベートIP」にチェックを入れ、「プライベートサービスアクセスの設定」からプロジェクト内のVPCを選択します。

設定が完了すると、以下のように表示されます。プライベートサービスアクセスが Enabled になっていることが確認できます。

次に、Cloud Run 側が先ほど設定した VPC に対してリクエストを送れるように設定します。
Cloud Run の編集画面から「ネットワーキング」タブを開き、以下のように設定します。
- アウトバウンドトラフィック用のVPCに接続する
- VPC に直接トラフィックを送信する
- Cloud SQL を接続した VPC を選択
- サブネットは
/26(64個分)以上のIPアドレス範囲を持っているものが推奨となります。
- プライベート IP へのリクエストのみを VPC にルーティングする
- VPC に直接トラフィックを送信する

これで、設定は完了です。
トラフィックルーティングについて少し補足します。
トラフィックルーティングで「すべてのトラフィック」を選択する場合、インターネットとの直接の通信が行えなくなります。そのため、 Cloud Run からインターネットへ通信する際には Cloud NAT を経由させる必要が出てきます。
利用するシーンとしては、以下のようなケースが考えられます。
- Cloud NAT によって固定IPによる通信を行いたい場合
- セキュリティ要件などによる通信の制御を行う場合
一方で、これらの要件がない場合は「プライベート IP へのリクエストのみ」で問題ありません。
なお、Cloud Run サービス間での通信で Ingress に「内部」を設定しているサービスに接続したい場合は「すべてのトラフィック」を選択する必要があります。その場合は追加の設定が必要になりますが、今回は割愛します。
動作確認
以下のコードを使用した Cloud Run functions をデプロイし、データベースへの接続を検証しました。参考までに添付しますが、もし利用する場合は環境変数の設定が必要となるのでご注意ください。
index.js
const functions = require('@google-cloud/functions-framework');
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const { Pool } = require('pg');
async function accessSecretVersion(projectId, secretId, versionId = 'latest') {
const client = new SecretManagerServiceClient();
const name = `projects/${projectId}/secrets/${secretId}/versions/${versionId}`;
const [version] = await client.accessSecretVersion({ name });
return version.payload.data.toString('utf8');
}
functions.http('connectDb', async (req, res) => {
let client;
try {
// Secret Managerからパスワードを取得
const password = await accessSecretVersion(
process.env.GOOGLE_CLOUD_PROJECT,
'cloudsql-password'
);
// Cloud SQL接続設定
const pool = new Pool({
host: process.env.DB_HOST, // Cloud SQLのプライベートIP
user: process.env.DB_USER,
password: password,
port: 5432,
database: process.env.DB_NAME
});
// データベースに接続
client = await pool.connect();
// クエリの実行例
const result = await client.query('SELECT NOW()');
res.status(200).json({
success: true,
message: 'Cloud SQLへの接続に成功しました',
data: result.rows[0]
});
} catch (error) {
console.error('データベース接続エラー:', error);
res.status(500).json({
success: false,
message: 'Cloud SQLへの接続に失敗しました',
error: error.message
});
} finally {
if (client) {
client.release();
}
}
});
package.json
{
"name": "cloudsql-secret-manager",
"version": "1.0.0",
"dependencies": {
"@google-cloud/functions-framework": "^3.0.0",
"@google-cloud/secret-manager": "^5.0.0",
"pg": "^8.11.0"
}
}
こちらを実行すると、以下のように成功メッセージが返ってきます。問題なく接続が確認できましたね。

おまけ: サーバーレス VPC コネクタから移行した場合
サーバーレス VPC コネクタから VPC Direct Egress に移行した場合は、不要になったコネクタは削除しましょう。
コネクタは削除しない限り、VMの起動料金がかかり続けます。
VPC の「サーバーレス VPC アクセス」画面からコネクタを選択し、削除しておきましょう。

終わりに
今回は VPC Direct Egress (ダイレクト VPC 下り(外向き))の設定を実際に試してみました。
Cloud Run のみサポートであったり、IPアドレスが多数必要といった注意点はあるものの、これらがクリアできた場合は非常に便利な接続方法となっています。
個人的には、コネクタという「自分で管理する必要があるリソース」が減らせることが非常に嬉しく思いました。また、セキュリティ・パフォーマンスなどの面でも非常に優れた機能となっているので、積極的に活用していきたい機能です。
以上、すらぼでした。






