0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AlloyDBのコスト最適化!Cloud RunとCloud Schedulerで自動起動・停止を実装する

Posted at

はじめに

背景

AlloyDBには、現時点で「マネージドな自動起動/停止」機能が提供されていません。
開発・検証用途では、夜間や週末に停止することでコスト最適化したいケースが多いため、Google Cloudのマネージドサービスを組み合わせて自動化を実装しました。

目的

定期的なスケジュールに合わせて、AlloyDBのインスタンスを自動で停止・起動する。

AlloyDBの概要

仕組み

全体構成

①Cloud Scheduler → ②Cloud Run(HTTP)→ ③AlloyDB Admin API(start/stop)

structure.png

①:Cloud Schedulerが指定時刻にHTTPリクエストをCloud Runへ送信する。
②~③:Cloud Runは受け取ったパラメータに基づいて、AlloyDB の「起動」・「停止」APIを呼び出します。

Cloud Runは、RuntimeのService Accountで認可され、AlloyDB のプロジェクト/ロケーション/クラスタ/インスタンスを指定して「起動」・「停止」を実行します。
※Cloud Runでは、環境変数で、プロジェクトIDとインスタンスの情報を取得を実施している。

実行結果(成功/失敗、インスタンスの状態)をCloud Loggingへ出力する。

サービスアカウント

上記の実行には、サービスアカウントを利用して、処理します。
サービスアカウントの権限は、以下のとおりです。
・AlloyDB 管理者
・Cloud Run サービス起動元
・ログ書き込み

デプロイ時の設定

Cloud Scheduler

起動設定

平日8:30 に起動処理を行いたい場合、以下のように設定を行います。

alloydb_scheduler.png

cronの設定方法の詳細は、cron ジョブの形式とタイムゾーンをご参照ください。

Cloud Run

今回実装した、Cloud Runソースコードは、以下のとおりです。

<起動処理>

import functions_framework
import requests
import os

# 環境変数からプロジェクトIDとインスタンス情報を取得
PROJECT_ID = os.environ.get('PROJECT_ID')
LOCATION = os.environ.get('LOCATION')
CLUSTER_ID = os.environ.get('CLUSTER_ID')
INSTANCE_ID = os.environ.get('INSTANCE_ID')

@functions_framework.http
def start_alloydb_instance(request):
    """
    HTTPリクエストを受け取り、AlloyDB Admin APIを呼び出してインスタンスを起動します。
    """
    if not all([PROJECT_ID, LOCATION, CLUSTER_ID, INSTANCE_ID]):
        print("Error: Required environment variables are not set.")
        return 'Error: Required environment variables are missing', 500

    # AlloyDBインスタンスのリソースパス
    instance_name = f'projects/{PROJECT_ID}/locations/{LOCATION}/clusters/{CLUSTER_ID}/instances/{INSTANCE_ID}'
    api_url = f'https://alloydb.googleapis.com/v1beta/{instance_name}'

    # APIリクエストのペイロード
    payload = {
        "activationPolicy": "ALWAYS"
    }

    # APIリクエストのクエリパラメータ
    params = {
        "updateMask": "activationPolicy"
    }

    try:
        # **認証ヘッダーの取得**
        # Cloud Functions/Run 環境では、実行環境に割り当てられたサービスアカウント
        # IDトークン(ID Token)を自動的に取得し、Authorizationヘッダーに設定することで認証を行う。
        # Google Cloud のクライアントライブラリ(google-auth)を使用するとこの処理が簡略化。
        from google.auth import default
        from google.auth.transport.requests import AuthorizedSession

        # 認証情報とセッションを取得
        credentials, project = default()
        authed_session = AuthorizedSession(credentials)

        # PATCHリクエストの実行
        print(f"AlloyDBインスタンス: {instance_name} の起動リクエストを送信中...")
        response = authed_session.patch(
            api_url,
            json=payload,
            params=params
        )

        # 応答の確認
        response.raise_for_status() # HTTPエラーレスポンスをチェック

        # レスポンスは長時間実行オペレーション(LRO)を示す
        operation_name = response.json().get('name')

        log_message = f'AlloyDBインスタンス起動リクエストが正常に送信されました。Operation: {operation_name}'
        print(log_message)
        return log_message, 200

    except requests.exceptions.HTTPError as e:
        error_message = f'AlloyDB API呼び出しエラー: {e.response.text}'
        print(error_message)
        return error_message, e.response.status_code
    except Exception as e:
        error_message = f'予期せぬエラーが発生しました: {str(e)}'
        print(error_message)
        return error_message, 500

停止処理については割愛しますが、APIリクエストのペイロードを停止:NEVERとすることで、実装可能です。

実際に動かしてみる

Cloud Schedulerを有効にしていると、自動実行はできるが、今回は「強制実行」して、処理が正常動作するか確認する。

alloydb_scheduler2.png

Cloud Runから受け取ったパラメータに基づいて、AlloyDB の「起動」のAPIが呼び出され、AlloyDBのプライマリインスタンスのステータスが「開始中」となり、起動処理が開始されました。
alloydb_scheduler5.png

数分~数十分ほどで、AlloyDBのプライマリインスタンスのステータスが「準備完了」となり、無事にCloud Scheduler+Cloud Run経由での起動が完了しました。
alloydb_scheduler6.png

苦労した点

APIリクエストは、「start」や「stop」のような専用のAPIを呼び出すと当初思い込んでいましたが、調べてみると、実際はインスタンスのアクティベーションポリシーフィールドを更新するAPIリクエストを使用し、「起動」=ALWAYS、「停止」=NEVERと設定することが正しく、躓いてしまいました。

アクティベーション ポリシー

参考

AlloyDB インスタンスを起動、停止、再起動する

まとめ

今回の検証では、Cloud Scheduler+Cloud Run+AlloyDB Admin APIを組み合わせることで、AlloyDBの自動起動・停止をシンプルに実装できることを確認しました。

手動での起動停止だと、起動・停止忘れが発生していまいます。そのため、常時起動ではない場合は、このような仕組みを入れることで、コスト最適化や開発環境の運用効率化を図ることが可能です。

留意点として、プライマリインスタンスのみの起動・停止であれば本記事の方法で対応できますが、読み取りプールインスタンスも含めて自動起動・停止を行いたい場合は、追加の考慮が必要です。その内容は、次回の記事として別途詳細を解説したいと考えております。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?