G-gen の佐々木です。当記事では AlloyDB for PostgreSQL でパブリック IP アドレスを有効化して、Cloud Run からの接続を試してみます。
前提知識
AlloyDB と Cloud Run
AlloyDB for PostgreSQL(以下、AlloyDB)と Cloud Run については、それぞれ以下の記事をご参照ください。
パブリック IP アドレスを使用した AlloyDB への接続
AlloyDB では、プライベート IP アドレスもしくはパブリック IP アドレスを使用した接続がサポートされています。
Cloud SQL 同様、DB インスタンスでパブリック IP アドレスを有効化する場合、承認されたネットワーク として DB インスタンスにアクセスできるアクセス元 IP アドレス範囲を制限することができます。
AlloyDB ではプロキシソフトウェアである AlloyDB Auth Proxy を使用することで、TLS によって暗号化されたデータベース接続を構成することができるため、パブリック IP アドレスを使用する場合は Auth Proxy 経由で接続することを推奨します。また、Auth Proxy を使用する場合、承認されたネットワークの設定は必要ありません。
Cloud Run から AlloyDB への接続
Cloud Run などのサーバーレスサービスから Cloud SQL や AlloyDB などの VPC リソースに接続する場合、プライベート IP アドレスを使用した接続ではサーバーレス VPC アクセスを構成し、コネクタインスタンスを経由して接続を行う必要がありました。
サーバーレス VPC アクセスのコネクタインスタンスは常時起動のリソースであり「起動時間ぶんのコストがかかってしまう」「一度スケールアウトするとスケールインできない」といった仕様があります。そのため Cloud SQL の場合は、Cloud SQL インスタンスでパブリック IP アドレスを有効化し、Cloud SQL Auth Proxy を使用して Cloud Run から接続するケースも少なくありません。
AlloyDB クラスタでパブリック IP アドレスを有効化することで、Cloud SQL 同様、Cloud Run から Auth Proxy を経由したパブリック IP アドレスによる接続を実現することができます。Cloud Run で AlloyDB Auth Proxy を使用する場合、Cloud Run のマルチコンテナ(サイドカー)機能を使用します。
Cloud Run のマルチコンテナ機能、およびプライベート IP アドレスを使用した AlloyDB への接続に関しては以下の記事で解説しています。
なお、2024年4月に Direct VPC Egress が GA となったことで、サーバーレス VPC アクセスを使用することなく、VPC リソースにプライベート IP で接続することができるようになりました。
Direct VPC Egress 機能の詳細については以下の記事で解説しています。
Cloud Run jobs からの接続
Cloud Run jobs ではマルチコンテナ機能がサポートされていない(= AlloyDB Auth Proxy が使用できない)ため、AlloyDB への接続は引き続きサーバーレス VPC アクセスを使用してプライベート IP アドレスで接続します。
なお、Cloud SQL の場合は Cloud Run のネイティブ機能として Cloud SQL Auth Proxy が利用できるため、Cloud Run jobs であっても Auth Proxy が使用できます。
VPC の作成
AlloyDB に紐付ける VPC を作成します。プライベートサービスアクセス を使用して、この VPC を AlloyDB が実際に作成されるサービスプロデューサー VPC にピアリング接続します。
# VPC の作成 $ gcloud compute networks create my-vpc --subnet-mode=custom # サービスプロデューサー VPC が使用する IP アドレス範囲を作成 gcloud compute addresses create my-iprange \ --global \ --purpose=VPC_PEERING \ --addresses=192.168.200.0 \ --prefix-length=24 \ --network=my-vpc # プライベートサービスアクセスの構成 $ gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=my-iprange \ --network=my-vpc
AlloyDB の作成
AlloyDB クラスターの作成
AlloyDB を作成するには、まず大枠となるクラスターを作成します。
以下のコマンドを使用して AlloyDB クラスターを作成します。
# AlloyDB クラスターの作成 $ gcloud alloydb clusters create my-alloycluster \ --password=mypassword \ --region=asia-northeast1 \ --network=my-vpc
AlloyDB インスタンスの作成
クラスターを作成したら、その中に パブリック IP アドレスを有効化した DB インスタンスを作成していきます。
--assign-inbound-public-ip
フラグで ASSIGN_IPV4
を指定することで、パブリック IP アドレスを有効化できます。
# AlloyDB インスタンスの作成 $ gcloud alloydb instances create my-alloyinstance \ --cluster=my-alloycluster \ --cpu-count=2 \ --instance-type=PRIMARY \ --region=asia-northeast1 \ --availability-type=ZONAL \ --require-connectors \ --assign-inbound-public-ip=ASSIGN_IPV4 \ --database-flags=password.enforce_complexity=on
パブリック IP アドレスを有効化したインスタンスを作成する際、データベースフラグである 「password.enforce_complexity」を ON にしないとエラーが発生してしまいます。
# エラー抜粋 ERROR: (gcloud.alloydb.instances.create) INVALID_ARGUMENT: The request was invalid: password complexity flag password.enforce_complexity is required when public IP is enabled
また、--require-connectors
フラグを指定することで、AlloyDB インスタンスの接続元に Auth Proxy の使用を強制することができます。パブリック IP アドレスを有効化する場合は指定したほうがよいでしょう。
# 使用できるオプションの確認 $ gcloud alloydb instances create --help --- 出力抜粋 --- --[no-]require-connectors Enable or disable enforcing connectors only (ex: AuthProxy)connections to the database. Use --require-connectors to enable and --no-require-connectors to disable.
作成された AlloyDB インスタンスを確認すると、publicIpAddress
の項目にパブリック IP アドレスの値が入っていることがわかります。
# AlloyDB インスタンスのパブリック IP アドレスを確認 $ gcloud alloydb instances describe my-alloyinstance \ --cluster=my-alloycluster \ --region=asia-northeast1 \ --format='value(publicIpAddress)'
サービスアカウントの作成
AlloyDB インスタンスに接続するための権限を付与したサービスアカウントを作成します。このサービスアカウントは後ほど作成する踏み台 VM と Cloud Run で使用します。
# サービスアカウントを作成する $ gcloud iam service-accounts create my-serviceaccount --project={プロジェクト名}
AlloyDB に接続するために、roles/alloydb.client
および roles/serviceusage.serviceUsageConsumer
ロールをサービスアカウントに付与します。
# alloydb.client ロールを付与 $ gcloud projects add-iam-policy-binding {プロジェクト名} \ --role="roles/alloydb.client" \ --member=serviceAccount:my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com # serviceusage.serviceUsageConsumer ロールを付与 $ gcloud projects add-iam-policy-binding {プロジェクト名} \ --role="roles/serviceusage.serviceUsageConsumer" \ --member=serviceAccount:my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com
データベースの作成
踏み台 Compute Engine VM の作成
踏み台 VM から psql クライアントを使用して AlloyDB にデータベースを作成していきます。
AlloyDB にはパブリック IP アドレスを使用して接続するため、VM を作成する VPC は任意のもので構いませんが、ここでは AlloyDB に紐づけた VPC を使用していきます。
踏み台 VM には AlloyDB クライアントのロールを付与したサービスアカウントを紐付けます。
# VM 用のサブネットの作成 $ gcloud compute networks subnets create my-subnet \ --network=my-vpc \ --range=192.168.100.0/28 \ --region=asia-northeast1 # 踏み台 VM の作成 $ gcloud compute instances create my-bastion \ --machine-type=e2-micro \ --subnet=my-subnet \ --zone=asia-northeast1-b \ --image-family=debian-12 \ --image-project=debian-cloud \ --service-account=my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com \ --scopes=cloud-platform
ファイアウォールルールを設定し、踏み台 VM への SSH 接続を許可します。
# SSH 接続を許可するファイアウォールルールを作成 $ gcloud compute firewall-rules create my-firewall-rule \ --network=my-vpc \ --allow=tcp:22 \ --direction=INGRESS \ --target-service-accounts=my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com
踏み台 VM からデータベース、テーブルを作成する
踏み台 VM に SSH 接続して作業を進めていきます。
事前準備
AlloyDB に接続するためのクライアントをインストールし、また AlloyDB Auth Proxy をダウンロードします。
# psql クライアントのインストール $ sudo apt-get update && sudo apt-get install -y postgresql-client
AlloyDB への接続に Auth Proxy の使用を強制する設定にしたため、AlloyDB Auth Proxy クライアントをダウンロードします(最新バージョンのダウンロードはドキュメントを参考)。
# Auth Proxy クライアントのダウンロード $ wget https://storage.googleapis.com/alloydb-auth-proxy/v1.10.2/alloydb-auth-proxy.linux.amd64 -O alloydb-auth-proxy # クライアントを実行可能にする $ chmod +x alloydb-auth-proxy
AlloyDB に接続する
AlloyDB Auth Proxy を起動して psql クライアントが AlloyDB に接続できるようにします。
Auth Proxy クライアントをそのまま実行した場合、Auth Proxy はプライベート IP アドレスを使用して AlloyDB に接続しようとします。
今回作成した踏み台 VM がある VPC からはプライベートサービスアクセス経由で AlloyDB に接続できるため、プライベート IP アドレスを使用してもよいのですが、ここではあえてパブリック IP アドレスを使用して接続してみます。
以下のコマンドを使用して、バックグラウンドで Auth Proxy を実行します。
# バックグラウンドで AlloyDB Auth Proxy を実行する(実行後 ctrl + C) $ ./alloydb-auth-proxy projects/{プロジェクト名}/locations/asia-northeast1/clusters/my-alloycluster/instances/my-alloyinstance \ --public-ip &
psql クライアントで Auth Proxy を経由して AlloyDB に接続します。
# psql クライアントを起動する $ psql -h 127.0.0.1 -U postgres -W Password: # パスワードを入力(この記事では mypassword)
AlloyDB に接続したら、データベースとテーブルを作成します。
# データベースを作成 > CREATE DATABASE mydb; # データベースの切り替え > \c mydb # users テーブルを作成 > CREATE TABLE users (id varchar(128), name varchar(128)); # 適当なデータを挿入 > INSERT INTO users VALUES ('3', 'sasashun'); # ログアウト > \q
ここまで完了したら、踏み台 VM からログアウトします。
以降は VM を使用しないため、消し忘れ防止のためここで削除してしまっても構いません。
Cloud Run の作成
使用するコード(Go)
PostgreSQL ドライバを使用して AlloyDB の mydb
データベースに接続し、users
テーブルのデータを取得する Web アプリケーションを実装します。
取得したデータはブラウザ上にそのまま表示します。
// main.go package main import ( "database/sql" "fmt" "log" "net/http" "os" _ "github.com/jackc/pgx/v4/stdlib" // PostgreSQLドライバ ) type User struct { ID string NAME string } // AlloyDB Auth Proxy に接続する関数 func connectTCPSocket() (*sql.DB, error) { mustGetenv := func(k string) string { v := os.Getenv(k) if v == "" { log.Fatalf("Warning: %s environment variable not set.", k) } return v } // Cloud Run の環境変数に設定するデータベース接続情報 var ( dbUser = mustGetenv("DB_USER") // データベースユーザ dbPwd = mustGetenv("DB_PASS") // データベースユーザのパスワード dbTCPHost = mustGetenv("INSTANCE_HOST") // 127.0.0.1 (Auth Proxy コンテナ) dbPort = mustGetenv("DB_PORT") // Port 5432 dbName = mustGetenv("DB_NAME") // データベース名 ) // データベース接続情報 dbURI := fmt.Sprintf("host=%s user=%s password=%s port=%s database=%s", dbTCPHost, dbUser, dbPwd, dbPort, dbName) // Auth Proxy 経由で AlloyDB に接続 dbPool, err := sql.Open("pgx", dbURI) if err != nil { return nil, fmt.Errorf("sql.Open: %v", err) } return dbPool, nil } // SELECT * を実行する関数 func selectAll() ([]User, error) { db, err := connectTCPSocket() if err != nil { return nil, fmt.Errorf("connectTCPSocket: %v", err) } defer db.Close() rows, err := db.Query("SELECT * FROM users") if err != nil { return nil, fmt.Errorf("db.Query: %v", err) } var users []User for rows.Next() { var u User rows.Scan(&u.ID, &u.NAME) users = append(users, u) } return users, nil } // SELECT オペレーションを実行するハンドラ func selectHandler(w http.ResponseWriter, r *http.Request) { users, err := selectAll() if err != nil { log.Fatal(err) } fmt.Fprintf(w, "Select Users: %v\n", users) } // Cloud Runで Webサーバを実行する func main() { log.Print("starting server...") http.HandleFunc("/", selectHandler) port := os.Getenv("PORT") if port == "" { port = "8080" log.Printf("defaulting to port %s", port) } log.Printf("listening on port %s", port) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatal(err) } }
コンテナイメージのビルド
当記事では Dockerfile を使用せず、Buildpack を使用してコンテナイメージをビルドします。Buildpack を使用することで、ソースコードを自動でパッケージ化し、デプロイ可能なコンテナイメージを生成することができます。
コンテナイメージは Artifact Registry のリポジトリにプッシュします(リポジトリがない場合は作成してください)。
# Buildpack を使用してコンテナイメージをビルド $ gcloud builds submit --pack image=asia-northeast1-docker.pkg.dev/{プロジェクト名}/{リポジトリ名}/run-alloydb
YAML ファイルの作成
当記事では YAML ファイルを使用して Cloud Run サービスをデプロイしていきます。
サイドカーコンテナのコンテナイメージに AlloyDB Auth Proxy のコンテナイメージを指定したファイル service.yaml
を作成します。
踏み台 VM で Auth Proxy を使用したときと同様、サイドカーコンテナのエントリポイントの引数(args
)で --public-ip=true
を指定することで、パブリック IP アドレスを使用した AlloyDB への接続が可能です。
また、プライベート IP アドレスで AlloyDB に接続する場合(参考)と比べると、サーバーレス VPC アクセスに関する設定が無くなっています。
# service.yaml apiVersion: serving.knative.dev/v1 kind: Service metadata: name: service-alloyrun spec: template: metadata: annotations: run.googleapis.com/execution-environment: gen1 run.googleapis.com/container-dependencies: '{"alloydb-app":["alloydb-proxy"]}' autoscaling.knative.dev/maxScale: '10' spec: # AlloyDB に接続できるサービスアカウント serviceAccountName: my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com containers: # Ingress Container - name: alloydb-app # アプリケーションのコンテナイメージを指定する image: asia-northeast1-docker.pkg.dev/{プロジェクト名}/{リポジトリ名}/run-alloydb:latest ports: - containerPort: 8080 # 環境変数にデータベース接続情報を設定する env: - name: DB_USER value: postgres # AlloyDB のデフォルトのユーザ - name: DB_PASS value: mypassword # AlloyDB 作成時に設定したパスワード # サイドカーコンテナの Auth Proxy に接続するため 127.0.0.1(localhost)を指定する - name: INSTANCE_HOST value: 127.0.0.1 - name: DB_PORT value: '5432' - name: DB_NAME value: mydb # Sidecar Container - name: alloydb-proxy # AlloyDB Auth Proxy のコンテナイメージを指定する image: gcr.io/alloydb-connectors/alloydb-auth-proxy:latest args: # AlloyDB インスタンスの接続文字列を設定する - "projects/{プロジェクト名}/locations/asia-northeast1/clusters/my-alloycluster/instances/my-alloyinstance" - --address=0.0.0.0 - --port=5432 - --public-ip=true # パブリックIPを使用して接続する # Startup Probe の設定 startupProbe: tcpSocket: port: 5432 initialDelaySeconds: 5 timeoutSeconds: 1 failureThreshold: 10 periodSeconds: 3
Cloud Run サービスの作成
YAML ファイルからサービスを作成する場合、新規作成であっても gcloud run services replace
コマンドを使用します。
出力の URL
欄に Cloud Run のエンドポイントが表示されるので、これをメモしておきます(コンソールからも確認可能)。
# 新しいサービスのデプロイ $ gcloud run services replace service.yaml --region=asia-northeast1 --- 出力例 --- Applying new configuration to Cloud Run service [service-alloyrun] in project [myproject] region [asia-northeast1] ✓ Deploying new service... Done. ✓ Creating Revision... Creating Service. ✓ Routing traffic... Done. New configuration has been applied to service [service-alloyrun]. URL: https://service-alloyrun-xxxxxxxxxx-an.a.run.app
YAML ファイルからのデプロイでは metadata.annotations.run.googleapis.com/ingress
に all
を設定しても「未認証の呼び出しを許可」の設定ができないようなので、別途 allUsers
に対して Cloud Run 起動元
のロールを付与します。
# 未認証で Cloud Run サービスを呼び出せるようにする $ gcloud run services add-iam-policy-binding service-alloyrun \ --role="roles/run.invoker" \ --member="allUsers" \ --region=asia-northeast1
動作確認
ブラウザから Cloud Run のエンドポイントにアクセスします。
サーバーレス VPC アクセスが設定されていなくても、Cloud Run 上のアプリケーションからパブリック IP アドレスで AlloyDB に接続され、SELECT *
クエリの結果が画面に表示されます。
佐々木 駿太 (記事一覧)
G-gen最北端、北海道在住のクラウドソリューション部エンジニア
2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。
趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。
Follow @sasashun0805