Cloud RunからAlloy DBに接続する初歩

2022/10/07に公開されました。
2022/10/12に更新されました。

Cloud RunからAlloy DBに接続する手順についてまとめました。


author: Yoshio

はじめに

こんにちは、GIクラウドのスペランカーYoshioです。
世の中、「出来る気がする」よりも「出来るらしい」と分かるだけで気が楽になることって多いですよね。そういう僕みたいに気は小さいけどなんとかしたいっていう人の励みになればと思って、このCloud RunからAlloy DBに接続する初歩についてを記事にしました。


サマリ

Alloy DBとCloud Runの接続の構成は以下の図のようになります。今回は、このうちの赤枠についての記載となります。

Alloy DBとCloud Runの構成

  • ※1実際はCloud Runが参入しているサーバレスVPCアクセスコネクタの構築もしています
  • ※2便宜上、サーバーレス環境からAlloy DBへのVPC越しのアクセスを、サーバーレスVPCアクセスコネクタの経由ではなく、サーバレスVPCからVPCへの接続と表現しています
  • ※3同一プロジェクト内での接続となります

上記構成を以下の手順を追って構築していきます。お察しの方もいらっしゃるでしょうが、Cloud SQLとの接続とほぼ同じです。知見がある方は公式ドキュメントに直接当たった方が回り道をしなくて済みますので、僕が参考にした公式ドキュメントも併記しておきました。

  1. Alloy DBの構築
    • 完了していると想定
  2. Cloud Runの構築
  3. サーバレスVPCアクセスコネクタを構成

Alloy DBを構築

弊社ブログAlloy DB試してみたをご参照ください。


Cloud Runの構築

手順としては以下の通りです。

  1. ローカル開発環境でソースコードを準備
    • .dockerignore
    • Dockerfile
    • main.py
    • requirements.txt
  2. gcloud コマンドでデプロイ

弊社的にはGo推しらしいのですが、Pythonの方が慣れているのでPythonで記述します。

1. ローカル開発環境でソースコードを準備

今回は halloyworld という名前のディレクトリを切って作成しています。

halloyworld
 .dockerignore
 Dockerfile
 main.py
 requirements.txt

Pythonプログラムは至って簡単で、DBに対して SELECT NOW(); を投げて現在時刻を取得するだけのプログラムとなっています。
DBサーバから業務時間を取る?う、なにか思い出しそうだ。

.dockerignore

Dockerfile
README.md
*.pyc
*.pyo
*.pyd
__pycache__
.pytest_cache

Dockerfile


FROM python:3.10-slim
ENV PYTHONUNBUFFERED True
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
RUN pip install --no-cache-dir -r requirements.txt
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

main.py

import os
import ssl
import sqlalchemy
from flask import Flask

app = Flask(__name__)
db = None

@app.route("/")
def hello_world():
    now = get_now()
    return now

def get_now() -> str:
    with db.connect() as conn:
        record = conn.execute("select now()").one()
        return str(record[0])
    return "Wow, ah Red, you look great. Everything looks great. 01:24, I still got time. Oh my god."

def connect_tcp_socket() -> sqlalchemy.engine.base.Engine:
    db_host = "xxx.xxx.xxx.xxx" # ダメ絶対
    db_user = "postgres"        # STOP
    db_pass = "**********"      # リテラル書き
    db_name = "postgres"        # Secret Managerとか
    db_port = 5432              # 使いましょう

    pool = sqlalchemy.create_engine(
        sqlalchemy.engine.url.URL.create(
            drivername="postgresql+pg8000",
            username=db_user,
            password=db_pass,
            host=db_host,
            port=db_port,
            database=db_name,
        ),
        pool_size=1,    # サンプルだしプールサイズは最小でええやろ
        max_overflow=1, # サンプルだしオーバーフローは(以下略
        pool_timeout=5, # サンプルだし5秒もあれば(以下略
        pool_recycle=60,# サンプルだし適t(以下略
    )
    return pool

@app.before_first_request
def init_db() -> sqlalchemy.engine.base.Engine:
    global db
    db = connect_tcp_socket()

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

requirements.txt

Flask==2.1.0
gunicorn==20.1.0
sqlalchemy==1.4.41
cloud-sql-python-connector[pg8000]

2. gcloud コマンドでデプロイ

gcloud run deploy

gcloudコマンドでRunをデプロイすると以下のようなメッセージが表示されるので、適宜回答を入力していってください。以下は僕の入力例です。

  1. ソースコードの場所を求められたら、Enterキーを押して現在のフォルダにデプロイ
  2. サービス名の入力を求められたら、Enterキーを押して、デフォルト名(フォルダ名)を設定
  3. Artifact Registry APIを有効にするよう求められたら、「y」と入力
  4. リージョンの入力を求められたら、適当なリージョンを選択
  5. 未認証の呼び出しを許可するように求めらたら「y」と入力

ガイドに従ってひとしきり入力してしばらく待つと、デプロイが完了します。

Building using Dockerfile and deploying container to Cloud Run service [halloyworld] in project [xxxxx] region [asia-northeast1]
 Building and deploying... Done.
 Uploading sources...
 Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds/xxx?project=nnnn].
 Creating Revision...
 Routing traffic...
Done.
Service [halloyworld] revision [halloyworld-00002-soj] has been deployed and is serving 100 percent of traffic.
Service URL: https://halloyworld-xxxxx-xx.x.run.app

URLを確認してみる(500 Internal Server Error)

サーバレスVPCの設定が済んでいないためデプロイされたサイトを確認しても、この時点ではDBアクセス失敗によるInternalServerErrorが発生します。Loggingにて以下のログが出力されているのが確認できます。

sqlalchemy.exc.InterfaceError: (pg8000.exceptions.InterfaceError) Can't create a connection to host xxx.xxx.xxx.xxx and port 5432 (timeout is None and source_address is None).

サーバレスVPCアクセスコネクタを構成

手順としては以下のようになります。

  1. サーバーレスVPCアクセス コネクタの作成
  2. サービス プロジェクトでCloud Runを有効にする
  3. コネクタへのアクセス権を設定
  4. コネクタを使用するサービスを構成する
  • ※1今回はデプロイするアカウントとホストプロジェクトを操作するアカウントが同じため、デプロイアカウントにロールを付与する手順を割愛しています。必要に応じて手順3と4の間にて、コネクタを検出可能にするを実施してください。

事前準備

ホストするプロジェクトで操作するアカウントに以下のロールが付与されていることを確認してください。

  • Computeネットワーク閲覧者(compute.networkViewer)
  • プロジェクトIAM管理者(resourcemanager.projectIamAdmin)
  • Service Usage管理者(serviceuseage.serviceUsageAdmin)
  • サーバーレスVPCアクセス管理者(vpcaccess.admin)

ロールの付与が確認出来たら、こちらからプロジェクトでサーバーレスVPCアクセスのAPIを有効にしてください。有効となっている場合、以下のように表示されます。
activate serverless vpc access connector

サーバーレス VPC アクセス コネクタの作成

ナビゲーションメニューから VPCネットワーク を選択し、 サーバレスVPCアクセス に移動し、そこで コネクタを作成 を選択してください。

今回はAlloy DBを作成した際に使用したdefaultネットワークをそのまま使うため以下のような設定になっています。
コネクタの作成画面に注意書きされているように、サブネットが利用するネットワークのいずれのサブネットのCIDR範囲と重複しないように注意して設定してください。(重複した場合はメッセージとともにコネクタの作成に失敗する親切設計となっています)
create serverless vpc access connector

サービス プロジェクトで Cloud Run を有効にする

こちらからCloud Run APIを有効にしてください。有効になっている場合、以下のように表示されます。
activate cloud run

コネクタへのアクセス権を設定

ナビゲーションメニューから IAM を選択し、そこで アクセス権を付与 を選択してください。
「新しいプリンシパル」に service-{SERVICE_PROJECT_NUMBER}@serverless-robot-prod.iam.gserviceaccount.com のようなCloud Runサービス エージェントのメールアドレスを入力します。
ここで {SERVICE_PROJECT_NUMBER}プロジェクトの設定に記載されている プロジェクト番号 となります。
give permission to connector

コネクタを使用するサービスを構成する

ナビゲーションメニューから Cloud Run を選択すると、先ほどデプロイしたCloud Runサービスが表示されます。そのリンクを辿りって サービスの詳細 画面を表示し、 新しいリビジョンの編集とデプロイ を選択してください。
コンテナ、接続、セキュリティの3つのタブのうち 接続 タブを選択し、 VPC フィールドで先ほど作成したコネクタを指定して デプロイ します。
add connector to cloud run

サービスの詳細 画面に表示されているURLを選択するとAlloy DBから取得した時刻が表示されるはずです。(ここちょっと消えてますね)
sample

お金もかかりますし、動作確認が済んだらサーバレスVPCアクセスコネクタとCloud Runを削除しておきましょう。


おまけ(GCEからAlloy DB Auth Proxyを使って接続する)

Alloy DB Auth Proxy越しにPostGIS拡張を突っ込んだりしようかなって思ったのですが、長くなりそうなので別の記事にします。

おわりに

今はまだAWSのAuroraやAzureのHyperscaleに後れをとってはいますが、クラウドネイティブDBのPostgreSQLの中で最もパフォーマンスが高いAlloy DB for PostgreSQLはこれからが楽しみなプロダクトです。
個人的にはPostGIS拡張を使うプロダクトをクラウド化する選択肢の本命な気がしているので、これからも積極的に使ってみようと思ってます。


GI Cloud は事業の拡大に向けて一緒に夢を追う仲間を募集しています

当社は「クラウドで日本のIT業界を変革し、世の中をもっとハッピーに」をミッションに掲げ、Google Cloudに特化した技術者集団として、お客様にコンサルティングからシステム開発、運用・保守まで一気通貫でサービスを提供しています。

まだ小規模な事業体ですが、スタートアップならではの活気と成長性に加えて、大手総合商社である伊藤忠グループの一員としてやりがいのある案件にもどんどんチャレンジできる環境が整っています。成長意欲の高い仲間と共にスキルを磨きながら、クラウドの力で世の中をもっとハッピーにしたい。そんな我々の想いに共感できる方のエントリーをお待ちしています。

採用ページ

※本記事は、ジーアイクラウド株式会社の見解を述べたものであり、必要な調査・検討は行っているものの必ずしもその正確性や真実性を保証するものではありません。

※リンクを利用する際には、必ず出典がGIC dryaki-blogであることを明記してください。
リンクの利用によりトラブルが発生した場合、リンクを設置した方ご自身の責任で対応してください。
ジーアイクラウド株式会社はユーザーによるリンクの利用につき、如何なる責任を負うものではありません。