🔥

Cloud Build から Cloud SQL(PSC 付き)に接続したい!

に公開

TL;DR

  • Google Cloud の VPC では、推移的接続ができない制約がある
  • 推移的接続する際は中継VMが必要なケースがある(本記事で解説)

はじめに

みなさん、こんにちは。クラウドエースの田中です。
田中という名前は弊社にそこそこいるので、LinkedIn のリンクをつけてみました。

普段はデータエンジニアとしてお仕事をしているので記事もそっち寄りなことが多いのですが、今回は毛色を変えてネットワーク寄りの記事を書いてみることにします。

というのも先日、クラウドエースの「ネットワークギルド」なるところに加入したからです。
こちらはクラウドエースの中でネットワークに興味のある人たちが集う、部署横断的なコミュニティとなっています。

ネットワークギルドから公開される初めての記事として今回は、わたしが業務で詰まったポイントの話をします。

Cloud Build でビルドしている中で Cloud SQL にアクセスするとき、推移的接続をしてくれなくて困ったときのことです。
わたしも同じ構成で詰まったので、この例を通して Google Cloud の VPC における推移的接続の制限とその回避法の 1 つをお伝えします。

前提知識

機能 解説
Cloud Build プライベートプール 利用者専用のプライベートなビルド実行環境
Cloud SQL Auth Proxy Cloud SQL インスタンスにセキュアに接続するためのコネクタ
Private Service Connect(以下、PSC) Google 管理のマネージドサービスなどにプライベートな経路で接続するためのサービス
Private Service Connect エンドポイント 利用者が PSC を使うときにアクセスするエンドポイント

上記のプロダクトの一部は、弊社の他エンジニアが記事にしております。
より詳しい説明については、よろしければそちらをご覧ください。

なお PSC についての解説記事は現在 (2025/03/28) 他のエンジニアが執筆中なので、完成次第リンクをつけておきます。

また Google Cloud の VPC については、こちらの記事も大変参考になります。

VPC における推移的接続

簡易構成図

VPC における推移的接続の制限とは、上の図でいう VPC-a と VPC-c の間には接続が確立されない、ということです。これを 2 ホップ制限ともいいます。

では、この制限をなんとかくぐり抜けるには、どうすればよいのでしょうか。

一般的な回避方法としては共有 VPCCloud VPN を使うことになるのでしょうが、今回は試したいことの性質を鑑みて別の方法を 2 つ試してみました。

失敗例:想定していた構成と落とし穴

ということで、やっと具体例の話です。

当初想定していたアーキテクチャでは、外部 IP を持たない Cloud Build から Private Service Access(PSA)を通して PSC エンドポイントに到達し、Cloud SQL インスタンスに接続する構成を考えていました。

この時は「Cloud Build から接続するのは Cloud SQL の PSC エンドポイントなのだから、推移的接続の制限に抵触しない」と思っていました。

図で表すと、以下のようになります。

構成図1

下準備

通信が行えるのかを検証するために必要なコンポーネントを用意していきます。

なお、わたしは Cloud Shell 上で gcloud CLI を利用して実行しています。
コマンド中に出てくる ${PROJECT_ID} はご自身の Google Cloud プロジェクトに読み替えてください。

その 1 VPC 作成

必要な API を有効化し、Cloud Build と通信するための VPC を構築します。
詳しい手順はこちらの公式ドキュメントを参照してください。

gcloud compute networks create test-for-build \
    --subnet-mode=custom \
    --bgp-routing-mode=regional \
    --mtu=1460

次に、Cloud Build と通信するための内部 IP 範囲を割り当てます。
こちらのやりかたは公式ドキュメントを参照してください。

  gcloud compute addresses create reserve4build \
      --global \
      --purpose=VPC_PEERING \
      --addresses=192.168.0.0 \
      --prefix-length=16 \
      --description=test \
      --network=test-for-build

つぎに、PSA 接続を作成します。
補足ですが、PSA は内部的に Google 管理 VPC と利用者管理 VPC とを VPC Peering で接続していることがコマンドからわかります。

gcloud services vpc-peerings connect \
    --service=servicenetworking.googleapis.com \
    --ranges=reserve4build \
    --network=test-for-build \
    --project=${PROJECT_ID}
その 2 Cloud Build プライベートプール作成

今回は簡単のため、コマンドラインで直接ステータスを指定してプライベートプールを作っています。
--regionasia-northeast1 にしている理由は特にないので、お好みのリージョンを指定して構いません。

公式ドキュメントの該当ページも併せて確認してください。

    gcloud builds worker-pools create test_private_pool \
        --project=${PROJECT_ID} \
        --region=asia-northeast1 \
        --peered-network=projects/${PROJECT_ID}/global/networks/test-for-build \
        --worker-machine-type=e2-medium \
        --worker-disk-size=100 \
        --no-public-egress
その 3 Cloud SQL インスタンス作成

次に、あとで PSC エンドポイントと紐づけることになる Cloud SQL インスタンスを作成します。
こちらも公式ドキュメントを参照しながら進めます。

今回は下記のコマンドを利用して作成しました。

gcloud sql instances create test-for-psc \
--project=${PROJECT_ID} \
--region=asia-northeast1 \
--enable-private-service-connect \
--allowed-psc-projects=${PROJECT_ID} \
--availability-type=ZONAL \
--no-assign-ip \
--tier=db-f1-micro \
--database-version=POSTGRES_15

--tier フラグや --database-version フラグについては、インスタンスを作成するための公式ドキュメントを参照してください。

その 4 PSC エンドポイント作成

PSC エンドポイントのためには、VPC 内のサブネットを利用します。
サブネットから、PSC エンドポイント用の IP アドレスを払い出す形です。

今回は検証なので /28 の小さな範囲でサブネットを作成していますが、実際のところこの用途でも /24 くらいを使うのが良い気がします。

VPC にサブネットを作成します。

gcloud compute networks subnets create test-psc-subnet \
  --network=test-for-build \
  --region=asia-northeast1 \
  --range=10.20.0.0/28

サブネットの中で IP アドレスを予約します。

gcloud compute addresses create reserve4psc \
--project=${PROJECT_ID} \
--region=asia-northeast1 \
--subnet=test-psc-subnet \
--addresses=10.20.0.10

作成したエンドポイントが、Cloud SQL サービス アタッチメントを指すようにします。

gcloud compute forwarding-rules create psc-endpoint \
--address=reserve4psc \
--project=${PROJECT_ID} \
--region=asia-northeast1 \
--network=test-for-build \
--target-service-attachment=${SERVICE_ATTACHMENT_URI} \
--allow-psc-global-access

${SERVICE_ATTACHMENT_URI} を確認するには、Cloud SQL インスタンス作成後に下記のコマンドを実行するか、Cloud SQL の Web コンソール画面に記載された「Service attachment」を確認してください。

gcloud sql instances describe test-for-psc \
--project=${PROJECT_ID}

念のため下記のコマンドで、転送ルールが作成されたことを確認しましょう。

gcloud compute forwarding-rules describe psc-endpoint \
--project=${PROJECT_ID} \
--region=asia-northeast1

ここまでの Cloud SQL インスタンスのセットアップがうまくいっていれば、結果が返ってくるはずです。
その結果の中で pscConnectionStatusACCEPTED になっていれば、成功です。

Cloud SQL インスタンスに Cloud Shell からでもアクセスし、デフォルトで作成される postgres ユーザ用のパスワードを設定しておきます。

gcloud sql users set-password postgres \
  --instance=test-for-psc \
  --password=${PASSWORD}

ここまでで、事前準備はひととおり完了です。

通信失敗の確認

それでは、通信できるかどうか試してみましょう[1]

Cloud Build で実行するビルドスクリプトの中で、PSC エンドポイントの内部 IP アドレスを直に指定します。
公式ドキュメントによると、これでも接続できるはずです。

yaml: Cloud Build で実行するビルド内容
steps:
  - name: 'postgres:15'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        echo "Check connectivity to DB via PSC endpoint"
        # PostgreSQL 例: PSC で割り当てられた private IP へ接続 (5432)
         psql -h 10.20.0.10 -p 5432 -U postgres -d postgres -c "SELECT NOW();"
options:
  pool:
    name: 'projects/${PROJECT_ID}/locations/asia-northeast1/workerPools/test_private_pool'

このスクリプトを実行すると、推移的接続の制限によって到達できずタイムアウトエラーになってしまっている様子が確認できました。

ビルド失敗の図

踏み台 VM の用意

直接の接続が難しい場合、次の選択肢として、Cloud Build からの向き先を別のものに変えることを検討します。
ここで候補になってくるのが、踏み台 VM です。

Cloud Build の接続先を踏み台 VM に変え、それ経由で Cloud SQL インスタンスに接続すれば、推移的接続の制限に引っかかることなく通信できそうです。

では、踏み台 VM を用意して、通信が成功する様子を観察しましょう。
構成図でいうとこのようになります。

構成図2

踏み台 VM の構築方法は公式ドキュメントを見ながら進めます。

また、ファイアウォールルールの構成も忘れずに行ってください。

2 つめが Cloud SQL Auth Proxy です。
Cloud SQL Auth Proxy を使うことで、クライアントと Cloud SQL インスタンスの間に安全な接続を確立することが簡単になります。

Cloud SQL Auth Proxy の導入方法

公式ドキュメントでもおすすめされているように、Cloud SQL インスタンスの DNS レコードを作成します。
その後、Cloud SQL Auth Proxy を VM にインストールし、接続ができるかどうかを確認していきます。

DNS レコードの作成方法も公式ドキュメントに記載があるので、それに従っていきます。

まずは DNS 名を gcloud sql instances describe コマンド(すでに上で利用したものと同じです)を使って把握します。
コマンドのレスポンスにある dnsName がインスタンスの持つ DNS 名になっています。

その後、下記のコマンドで、すでに作成した VPC 配下に限定公開 DNS ゾーンを作成します。

gcloud dns managed-zones create psc-endpoint-asia-northeast1 \
--project=${PROJECT_ID} \
--description="for Cloud SQL PSC Endpoint" \
--dns-name=asia-northeast1.sql.goog. \
--networks=test-for-build \
--visibility=private

限定公開 DNS ゾーンが作成できたら、そのゾーン内に DNS レコードを作成します。
${DNS_NAME} には、Cloud SQL インスタンスの dnsName を代入してください。

gcloud dns record-sets create ${DNS_NAME} \
--project=${PROJECT_ID} \
--type=A \
--rrdatas=10.20.0.10 \
--zone=psc-endpoint-asia-northeast1

次は Cloud SQL Auth Proxy を使って、踏み台 VM から Cloud SQL インスタンスにアクセスできることを確認していきます。
こちらも公式ドキュメントにチュートリアルがあるので、その手順に沿って進めていきます。必要なものは(今回の場合) psql クライアントと、Cloud SQL Auth Proxy になります。

なお PSC を Cloud SQL Auth Proxy で扱うためには、Cloud SQL Auth Proxy の v2.5.0 以降が必要になります。

インストールおよび Cloud SQL Auth Proxy の実行権限付与が済んだ後、下記のコマンドで接続を確立します。
${INSTANCE_CONNECTION_NAME} は、Cloud SQL インスタンスのインスタンス接続名に置き換えてください。

./cloud-sql-proxy ${INSTANCE_CONNECTION_NAME} --psc 

踏み台 VM を通した接続確認

ここまでできたら、先ほど利用したビルドスクリプトを踏み台 VM 経由になるように書き換え、接続できるかどうかを試してみましょう。
${INSTANCE_NAME} は Compute Engine の VM インスタンス名を、${LOCATION} は VM インスタンスが存在するゾーンを、${HOST_NAME} は Cloud SQL インスタンスの接続名を、${PASSWORD} には Cloud SQL インスタンスの postgres ユーザーに設定したパスワードを、それぞれ代入してください。

steps:
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        gcloud compute ssh ${INSTANCE_NAME} --internal-ip --zone "${LOCATION}" --command="PGPASSWORD=${PASSWORD} psql -d postgres -h 127.0.0.1 -U postgres -c 'SELECT NOW();'"
options:
  pool:
    name: 'projects/${PROJECT_ID}/locations/asia-northeast1/workerPools/test_private_pool'

これをビルドしてみると……成功しました!

まとめ + ちゃぶ台返し

ここまで、踏み台 VM を用意して、Cloud Build プライベートプールから PSC エンドポイントを有効化した Cloud SQL インスタンスに接続するための方法を見てきました。

しかし、踏み台 VM を用意する方法は、本来余計なものを用意するということでもあります。
踏み台 VM を維持するためにかかる金銭的コストや、踏み台 VM の運用コストといった、追加のコストがかかってくることも事実です。

実は Google Cloud では Network Connectivity Center というプロダクトもあり、そこでは今回のようなユースケースで踏み台がいらなくなるかもしれない機能も登場しています。
2 週間以内に登場する次の記事では、Network Connectivity Center を使うと今回のようなユースケースではどう刺さるのか、を検証してみるつもりです。そちらもご覧いただけたらと思います。

脚注
  1. Cloud Build のプライベートプールを使ってビルドを実行する方法についての詳細は、公式ドキュメントを確認してください。 ↩︎

Discussion