G-gen の佐々木です。当記事では、Cloud Run services の マルチコンテナ (サイドカー) 機能 のユースケースの 1 つである、AlloyDB Auth Proxy をサイドカーコンテナとして使用した Alloy DB への接続を試してみます。
前提知識
Cloud Run services
Cloud Run services(以下、Cloud Run)は Google Cloud のサーバーレス コンテナ サービスである Cloud Run の 1 機能であり、フルマネージドの実行環境で HTTP リクエストをトリガーとしたコンテナアプリケーションを実行することができます。
サービスの詳細は以下の記事で解説しています。
Cloud Run services におけるマルチコンテナ (サイドカー) 構成
Cloud Run のマルチコンテナ (サイドカー) 機能を使用すると、外部からの HTTP リクエストを受信・処理する Ingress コンテナ と、1 つ以上の サイドカーコンテナ でサービスを構成することができます。
サイドカーコンテナは外部からの HTTP リクエストを受信することはできませんが、ローカルホスト ポートを使用して Ingress コンテナや他のサイドカーコンテナと通信することができます。また、それぞれのコンテナから 共有メモリ内ボリューム にアクセスすることも可能です。
公式ドキュメントで紹介されているマルチコンテナ機能のユースケースは以下の通りです。
- アプリケーションのモニタリング、ロギング、トレース。
- Nginx、Envoy、または Apache2 をリバースプロキシとして使用する。
- 認証および認可フィルターを追加する (Open Policy Agent など)。
- Alloy DB Auth プロキシなど、アウトバウンド接続用のプロキシを実行する。
マルチコンテナ機能は Cloud Run の第 1 世代、第 2 世代いずれの実行環境でも利用することができます。
AlloyDB for PostgreSQL
AlloyDB for PostgreSQL(以下、AlloyDB)は Google Cloud が提供する PostgreSQL 互換のフルマネージド データベース サービスです。
同じくマネージドな PostgreSQL データベースを提供する Cloud SQL と比較すると、パフォーマンスや可用性、スケーラビリティに優れ、大規模ワークロードに対応したサービスとなっています。
AlloyDB の詳細については以下の記事で解説しています。
AlloyDB Auth Proxy
AlloyDB Auth Proxy(以下、Auth Proxy)は AlloyDB の接続に使用することができるプロキシソフトウェアであり、Google Cloud の IAM でデータベースの認証・認可 (ログイン) をすることができます。
また、Auth Proxy を使用することで、アプリケーションからデータベースへの通信が TLS で暗号化され、より安全なデータベース接続を構成することができます。
構成
当記事では、Cloud Run のマルチコンテナ機能を利用し、AlloyDB Auth Proxy をサイドカーとして使用するコンテナアプリケーションを作成します。
Cloud SQL 同様、AlloyDB のインスタンスは Google Cloud が管理する VPC (サービスプロデューサー VPC) に作成されます。AlloyDB のインスタンスはプライベート IP しかエンドポイントを持たないため、サービスプロデューサー VPC に接続できる VPC を作成し、プライベートサービスアクセスを構成する必要があります。
Cloud Run から AlloyDB へのアクセスは、サーバーレス VPC アクセスコネクタを VPC に作成し、コネクタ経由でサービスプロデューサー VPC に到達できるようにします。
VPC リソースの作成
VPC、サブネットの作成
asia-northeast1
にサブネットをもつ VPC を作成します。
この VPC を、AlloyDB が作成されるサービスプロデューサー VPC にピアリング接続します。
# VPC の作成 $ gcloud compute networks create my-vpc --subnet-mode=custom
サーバーレス VPC アクセスコネクタを作成するサブネットは /28
の CIDR 範囲である必要があります。
Auth Proxy がプライベート接続で AlloyDB のメタデータを取得する際に Google Cloud APIs にアクセスできる必要があるため、--enable-private-ip-google-access
で 限定公開の Google アクセス を有効化します。
# サブネットの作成 $ gcloud compute networks subnets create my-subnet \ --network=my-vpc \ --range=192.168.100.0/28 \ --region=asia-northeast1 \ --enable-private-ip-google-access
サービスプロデューサー VPC の IP アドレス範囲を作成
サービスプロデューサー VPC で使用する IP アドレス範囲を確保します。
$ gcloud compute addresses create my-iprange \ --global \ --purpose=VPC_PEERING \ --addresses=192.168.200.0 \ --prefix-length=24 \ --network=my-vpc
プライベートサービスアクセスの構成
作成した IP アドレス範囲をサービスプロデューサー VPC で使用し、VPC とのピアリングを構成します。
# プライベートサービスアクセスの構成 $ gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=my-iprange \ --network=my-vpc
サーバーレス VPC アクセスの構成
Cloud Run が VPC を経由してサービスプロデューサー VPC にある AlloyDB にアクセスできるように、サーバーレス VPC アクセスコネクタを作成します。
# サーバーレス VPC アクセスコネクタの作成 $ gcloud compute networks vpc-access connectors create my-connector \ --region=asia-northeast1 \ --subnet=my-subnet \ --min-instances=2 \ --max-instances=3 \ --machine-type=f1-micro
AlloyDB クラスタ、インスタンスの作成
AlloyDB は基本的な管理単位である クラスタ と、クラスタ内に作成され実際にデータベースを持つ プライマリインスタンス 、読み取り専用の リードプールインスタンス で構成されます。
当記事ではリードプールインスタンスは使用しないため、クラスタとプライマリインスタンスのみ作成していきます。
# クラスタの作成 $ gcloud alloydb clusters create my-alloycls \ --password=mypassword \ --region=asia-northeast1 \ --network=my-vpc # プライマリインスタンスの作成 $ gcloud alloydb instances create my-alloyins \ --cluster=my-alloycls \ --cpu-count=2 \ --instance-type=PRIMARY \ --region=asia-northeast1
サービスアカウントの作成
AlloyDB インスタンスに接続するための権限を付与したサービスアカウントを作成します。
# サービスアカウントを作成する $ gcloud iam service-accounts create my-serviceaccount --project={プロジェクト名}
AlloyDB に接続するために、roles/alloydb.client
ロールをサービスアカウントに付与します。
# AlloyDB クライアントのロールを付与 $ gcloud projects add-iam-policy-binding {プロジェクト名} \ --role="roles/alloydb.client" \ --member=serviceAccount:my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com
データベースの作成
踏み台 VM の作成
psql クライアントを使用して AlloyDB にデータベースを作成します。
AlloyDB クラスタにはプライベート IP を使用して接続するため、プライベートサービスアクセスを設定した VPC に踏み台 VM を作成し、そこから AlloyDB に接続します。
踏み台 VM には AlloyDB クライアントのロールを付与したサービスアカウントを紐付けます。
# 踏み台 VM の作成 $ gcloud compute instances create my-bastion \ --machine-type=e2-micro \ --subnet=my-subnet \ --zone=asia-northeast1-b \ --image-family=debian-11 \ --image-project=debian-cloud \ --metadata=enable-oslogin=true \ --service-account=my-serviceaccount@{プロジェクト名}.iam.gserviceaccount.com
ファイアウォールルールを設定し、踏み台への 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 で作業する際に AlloyDB インスタンスの IP アドレスが必要になるため、以下のコマンドで確認しておきます。
# AlloyDB インスタンスの IP アドレスを確認 $ gcloud alloydb instances describe my-alloyins \ --cluster=my-alloycls \ --region=asia-northeast1 \ | grep ipAddress # 出力例 ipAddress: 192.168.200.2
psql クライアントのインストール
踏み台 VM に psql クライアントをインストールします。
以下のコマンドは踏み台 VM に SSH 接続してから実行します。
# 踏み台 VM で実行 # psql クライアントのインストール $ sudo apt-get update $ sudo apt-get install -y postgresql-client
データベース、テーブルの作成
踏み台 VM から AlloyDB にデータベースとテーブルを作成します。
作成したテーブルには、Cloud Run にデプロイするアプリケーションから接続確認するために、適当なレコードを挿入しておきます。
データベースの作成
# 踏み台 VM で実行 # AlloyDB に接続(パスワードは AlloyDB クラスタ作成時に指定したもの) $ psql -h {AlloyDBのプライベートIPアドレス} -U postgres # データベースを作成 > CREATE DATABASE mydb;
テーブルの作成
# 踏み台 VM で実行 # データベースの切り替え > \c mydb # users テーブルを作成 > CREATE TABLE users (id varchar(128), name varchar(128)); # 適当なデータを挿入 > INSERT INTO users VALUES ('3', 'sasashun');
以降、踏み台 VM は使用しないため、消し忘れないようにここで削除してしまっても良いです。
Cloud Run サービスの作成
コンテナイメージの作成
Cloud Run にデプロイするアプリケーションのコンテナイメージを作成します。
Auth Proxy のコンテナイメージについては、Google Cloud から提供されているものをそのまま利用します。
使用するコード
PostgreSQL ドライバを使用して AlloyDB の mydb
データベースに接続し、users
テーブルのデータを取得する処理を実装します。
当記事では 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 ファイル
当記事ではYAML ファイルを使用して Cloud Run サービスをデプロイします。Google Cloud コンソール、Google Cloud CLI からもマルチコンテナ機能を使用したサービスをデプロイすることが可能です。
サイドカーコンテナに AlloyDB Auth Proxy のコンテナイメージを指定したファイル service.yaml
を作成します。
なお、当記事では AlloyDB の作成時に自動で作成される postgres
ユーザを使用していますが、実運用では専用のユーザを使用することが推奨されます。
また実運用では、ユーザやパスワードなどの認証情報は Secret Manager に格納し、それを環境変数から読み込む方式にしたほうが良いでしょう。
apiVersion: serving.knative.dev/v1 kind: Service metadata: # サービスの名前 name: service-alloyrun spec: template: metadata: annotations: run.googleapis.com/execution-environment: gen1 # Cloud Run からの外向き通信をサーバーレス VPC アクセスコネクタ経由にする run.googleapis.com/vpc-access-egress: all-traffic # サーバーレス VPC アクセスコネクタを指定する run.googleapis.com/vpc-access-connector: projects/{プロジェクト名}/locations/asia-northeast1/connectors/my-connector # AlloyDB Auth Proxy コンテナの起動後にアプリケーションコンテナを起動するようにする 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-alloycls/instances/my-alloyins" - --address=0.0.0.0 - --port=5432 # Startup Probe の設定 startupProbe: tcpSocket: port: 5432 initialDelaySeconds: 5 timeoutSeconds: 1 failureThreshold: 10 periodSeconds: 3
コンテナの起動順序について
Auth Proxy コンテナが起動していない状態ではアプリケーションコンテナが正常に動作しないため、spec.template.metadata.annotations
の run.googleapis.com/container-dependencies
でコンテナの依存関係を指定しています。
それに加えて Auth Proxy コンテナに Startup Probe を設定することで、Auth Proxy コンテナの TCP 5432
ポートと疎通が取れるようになるのを待ってからアプリケーションが実行されるようにしています。
サービスのデプロイ
YAML ファイルからのデプロイは、新規であっても gcloud run services replace
コマンドを使用します。
# 新しいサービスのデプロイ $ gcloud run services replace service.yaml --region=asia-northeast1
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 サービスからの接続
gcloud run services replace
コマンドで Cloud Run サービスをデプロイした後、エンドポイントとなる URL が出力されているので、ブラウザからアクセスします。
# 出力例 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
アプリケーションから AlloyDB のデータベースに接続され、SELECT * クエリの結果が画面に表示されます。
佐々木 駿太 (記事一覧)
G-gen最北端、北海道在住のクラウドソリューション部エンジニア
2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。
趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。
Follow @sasashun0805