🛠️

Cloud SQL Proxy Operator を使ったプライベート IP の Cloud SQL インスタンスへの接続

2024/07/16に公開

要約

クラウドエースの北野です。
Cloud SQL Proxy Operator を使って、GKE からプライベート IP のみを有する Cloud SQL インスタンスに接続する方法を紹介します。

以下のような GKE 上の Pod から Cloud SQL への接続を実現させます。

ワーカープール作成のコンソール画面

構築の手順は以下の通りです。

  • Google Cloud 上で GKE クラスター、 Cloud SQL インスタンス、Pod 用の Service Account の作成
  • Kubernetes に Cloud SQL Proxy Operator のインストール
  • Pod、ServiceAccount、AuthProxyWorkload リソースの作成

また簡便に構築するため、GKE の構成は以下とします。

  • 運用モード: Autopilot クラスタ
  • ネットワーク: Private Service Access によるプライベート IP での接続

検証では、Cloud SQL for PostgreSQL を作成し、postgres のコンテナから psql コマンドを使い接続を確認します。

Cloud SQL Proxy Operator とは

Cloud SQL Proxy Operator は、2023年5月16日にリリースされた機能で、オープンソースの Kubernetes オペレータです。
Cloud SQL Proxy Operator は Pod に AuthProxy コンテナを挿入し、Cloud SQL のデータベースへの接続を作成します。 このリソースを使用するには、カスタムリソース AuthProxyWorkload を定義し、挿入する Pod を指定します。
今まで AuthProxy を使い接続する場合、AuthProxy コンテナをサイドカーとして挿入する必要がありましたが、 Cloud SQL Proxy Operator を使うと、AuthProxy のコンテナが Pod に自動で挿入されます。そのため、Cloud SQL Proxy Operator を使うと、アプリケーションのマニフェストから AuthProxy を分離させることが可能になります。

Cloud SQL Proxy Operator が、AuthProxy コンテナを挿入できるリソースは以下の通りです。

  • Deployment
  • StatefulSet
  • Pod
  • ReplicaSet
  • DaemonSet
  • Job
  • CronJob

カスタムリソース AuthProxyWorkload

AuthProxy の接続を定義するカスタムリソース AuthProxyWorkload の API 仕様について簡単に紹介します。

AuthProxyWorkload リソースの spec では、以下の内容を指定します。

  • workloadSelector: AuthProxy コンテナを挿入するリソースの指定
  • instances: AuthProxy で接続する Cloud SQL の指定
  • authProxyContainer: AuthProxy コンテナのスペックの指定

workloadSelector は以下の内容を設定できます。

変数名 変数の内容
selector 対象のリソースのラベル情報
kind 対象のリソースの種類
name リソース名

instances は以下の内容を設定できます。

変数名 変数の内容
connectionString Cloud SQL の インスタンス接続名 ( プロジェクト ID :リージョン:インスタンス名 )
port Cloud SQL の接続先ポート番号
autoIAMAuthN IAM 認証のインスタンスか否か
privateIP Cloud SQL にプライベート IP で接続するか否か
pcs Private Service Connect での接続か否か (privateIP の設定と一緒には使えない)
portEnvName Cloud SQL インスタンス接続先ポート番号を格納した環境変数名
hostEnvName Cloud SQL インスタンス接続先のホスト情報を格納した環境変数名
unixSocketPath プロキシがリッスンしている Unix ソケットのパス
unixSocketPathEnvName unixSocketPath の値を格納した環境変数名

authProxyContainer は以下の内容を設定できます。

変数名 変数の内容
container Container を使い AuthProxy コンテナ以外のコンテナの挿入
resources Resource を使い AuthProxy のリソースの limits, requests の指定
telemetry コンテナが出力するテレメトリーの指定
adminServer Pod 内のコンテナが利用できるプロキシの管理サービスの指定
authentication Cloud SQL への認証方法の指定
maxConnections Cloud SQL への接続数の最大値
maxSigtermDelay TERM 受信後の接続の閉塞を待つ最大時間
sqlAdminAPIEndpoint デバッグ時の Google Cloud API のエンドポイントの変更先
image AuthProxy のコンテナイメージ名
rolloutStrategy AuthProxy のコンテナのロールアウトストラテジを挿入先のリソースのストラテジに沿わせるか否か
quiet AuthProxy のログ量を抑える --quiet を設定するか否か

プライベート IP のみ Cloud SQL インスタンスへの接続

以下のような構成で Cloud SQL Proxy Operator の挙動を確認します。

ワーカープール作成のコンソール画面

Cloud SQL と GKE の VPC ネットワークを Private Service Access によりプライベート通信の経路を確保します。また、Cloud SQL インスタンスは、作成時にパブリック IP を無効にし、外部ネットワークからアクセスできないようにします。
今回、Cloud SQL for PostgreSQL のインスタンスを作成します。GKE からの接続には、Docker Hub の postgres イメージを使い作成した Pod から psql コマンドを発行し接続を確認します。

Google Cloud 上に作成するリソースは以下の通りです。

リソースの種類 役割
Cloud SQL GKE が接続する Cloud SQL for PostgreSQL インスタンス
GKE Cloud SQL に接続する Pod を稼動させる Kubernetes 基盤
VPC Network GKE が稼動するネットワーク
Service Account Pod への権限付与

Kubernetes 上に作成するリソースは以下の通りです。

リソースの種類 役割
AuthProxyWorkload Cloud SQL への接続
Pod psql コマンドにより Cloud SQL に接続するコンテナが動く環境
ServiceAccount Pod のサービスアカウント

Google Cloud のリソース作成

まず、Cloud SQL インスタンスおよび GKE Autopilot を作成します。
始めに Cloud SQL インスタンスと GKE Autopilot クラスタを作成する VPC ネットワークとサブネットワークを作成します。

gcloud compute networks create $VPC_NETWORK_NAME \
	   --project $PROJECT_ID \
	   --subnet-mode custom

gcloud compute networks subnets create $SUBNETWORK_NAME \
	   --project $PROJECT_ID \
	   --network $VPC_NETWORK_NAME \
	   --region $REGION \
	   --range $ADDRESS_RANGE

次にプライベート IP の Cloud SQL インスタンス用のプライベート IP と Private Service Access を作成します。

gcloud compute addresses create $ADDRESS_NAME \
	   --project $PROJECT_ID \
	   --global \
	   --purpose VPC_PEERING \
	   --prefix-length $PREFIX_LENGTH \
	   --network $VPC_NETWORK_NAME \

gcloud services vpc-peerings connect \
	--project $PROJECT_ID \
	--service servicenetworking.googleapis.com \
	--ranges $ADDRESS_NAME \
	--network $VPC_NETWORK_NAME

プライベート IP の Cloud SQL インスタンスを先のプライベート IP と Private Service Access を使い作成します。

gcloud beta sql instances create $CLOUDSQL_INSTANCE_NAME \
	   --project $PROJECT_ID \
	   --network $VPC_NETWORK_NAME \
	   --tier $TIER \
	   --database-version $DATABASE_VERSION \
	   --no-assign-ip \
	   --allocated-ip-range-name $ADDRESS_NAME \
	   --region $REGION \
	   --enable-google-private-path

続いて、GKE Autopilot を次のコマンドで作成します。

gcloud container clusters create-auto $GKE_CLUSTER_NAME \
	   --project $PROJECT_ID \
	   --location $REGION \
	   --network $VPC_NETWORK_NAME \
	   --subnetwork $SUBNETWORK_NAME \

最後に Pod 用のサービスアカウントを作成し、Cloud SQL の接続に必要な権限を付与します。

gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
	   --project $PROJECT_ID

gcloud projects add-iam-policy-binding $PROJECT_ID \
	   --member="serviceAccount:$SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
	   --role="roles/cloudsql.client"

gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com \
	   --role roles/iam.workloadIdentityUser \
	   --member "serviceAccount:$PROJECT_ID.svc.id.goog[$NAMESPACE/$KSA_NAME]"

Kubernetes 上の設定

作成した GKE クラスタに接続します。

gcloud container clusters get-credentials $GKE_CLUSTER_NAME \
	   --region $REGION \
	   --project $PROJECT_ID

GKE に Cloud SQL Proxy Operator をインストールします。

gcloud container clusters get-credentials $GKE_CLUSTER_NAME \
	   --region $REGION \
	   --project $PROJECT_ID

helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--version "v1.9.1" \
--create-namespace \
--set global.leaderElection.namespace=cert-manager \
--set installCRDs=true

kubectl apply -f https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy-operator/v1.4.5/cloud-sql-proxy-operator.yaml

作成が完了すると、cert-manager および cloud-sql-proxy-operator-system の namespace に以下のリソースが作成されます。

kubectl get deployment  -n cert-manager
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
cert-manager              1/1     1            1           11m
cert-manager-cainjector   1/1     1            1           11m
cert-manager-webhook      1/1     1            1           11m

kubectl get deployment -n cloud-sql-proxy-operator-system
NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE
cloud-sql-proxy-operator-controller-manager   1/1     1            1           9m11s

以下のマニフェストを使い postgres の Pod と Pod が使う ServiceAccount を作成します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: $KSA_NAME
  annotations:
    iam.gke.io/gcp-service-account: $SERVICE_ACCOUNT_NAME@$PROJECT_ID.iam.gserviceaccount.com
---
apiVersion: v1
kind: Pod
metadata:
  name: $POD_NAME
  labels:
    app: cloudsql
spec:
  serviceAccountName: $KSA_NAME
  containers:
    - name: postgresql-clien
      image: postgres
      env:
        - name: "DB_PORT"
        - name: "INSTANCE_HOST"
      command: ['sh', '-c', 'sleep infinity']

最後に AuthProxyWorkload リソースを以下のマニフェストを使い作成します。

apiVersion: cloudsql.cloud.google.com/v1
kind: AuthProxyWorkload
metadata:
  name: $AUTHPROXYWORKLOAD_NAME
spec:
  workloadSelector:
    selector:
      matchLabels:
        app: cloudsql
    kind: Pod
  instances:
    - connectionString: "$PROJECT_ID:$REGION:$CLOUDSQL_INSTANCE_NAME"
      privateIP: true
      portEnvName: "DB_PORT"
      hostEnvName: "INSTANCE_HOST"
  authProxyContainer:
    image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.11

AuthProxyWorkload のリソースを作成すると、以下の様に対象の Pod 内に AuthProxy のコンテナが挿入されます。

 kubectl get pod cloudsql -o json | jq '.spec.containers[] | {name: .name, image: .image}'
{
	"name": "postgresql-clien",
	"image": "postgres"
}
{
	"name": "csql-default-sample",
	"image": "gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.11.0"
}

最後に Pod にアクセスし、psql コマンドを使って接続できているかを確認します。
まず、AuthProxyWorkload リソースで作成した portEnvName と hostEnvName の環境変数に入力されている値について確認してみます。

kubectl exec -it $POD_NAME /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
Defaulted container "postgresql-clien" out of: postgresql-clien, csql-default-sample
root@cloudsql:/# echo $INSTANCE_HOST
127.0.0.1
root@cloudsql:/# echo $DB_PORT
5000

psql コマンドを使って、 Cloud SQL に接続してみます。

root@cloudsql:/# psql -h $INSTANCE_HOST -p $DB_PORT -U postgres
Password for user postgres:
psql (16.3 (Debian 16.3-1.pgdg120+1), server 15.7)
Type "help" for help.

postgres=>

さいごに

Cloud SQL Proxy Operator について紹介しました。AuthProxyWorkload リソースを使い Cloud SQL への接続を分離できます。そのため、他の環境で利用していたマニフェストを簡単に移行することが可能かと思います。GKE で Cloud SQL を使う際には活用を検討してみてください。

Discussion