開発費用の削減: Cloud SQL インスタンスの起動と停止をスケジュールする
はじめに
こんにちは、クラウドエースの許と申します。
こちらの記事は、2021 年 6 月 21 日に Google Cloud の公式ブログで投稿された「開発費用の削減: Cloud SQL インスタンスの起動と停止をスケジュールする」(以降、2021 年記事)の 2024 年 9 月版(以降、2024 年版)となります。
2021 年記事では、Cloud Run Functions(旧: Cloud Functions)を利用して起動と停止の制御を行なっていたのですが、当時より以下の2点が変わっているため、2021 年記事のリマスター版的な位置付けで当記事を執筆しております。
- Cloud Run Functions の仕様やUIが大幅に変わっている
- 2021 年記事で利用していた、
SQLAdmin
の関数の一部が非推奨になっている
前提
作業者がオーナー権限を持った Google Cloud プロジェクトで操作を行なっていきます。
もし操作の途中で不足している権限がありましたら、適宜必要な権限を付与してください。
SQLインスタンスの作成
[インスタンスを作成]をクリックして、SQL インスタンスを作成します。
-
使用したいデータベースエンジンを選択します。(筆者は MySQL が好みなので、MySQL を選択します。)
-
エディションのプリセット、インスタンスID、パスワード、リージョンを入力していきます。今回は動作するかどうかの確認が目的なので、最低限の設定で進めます。
-
[インスタンスを作成]をクリックします。
Cloud Pub/Sub トピックの作成
サブスクリプションはトリガーに設定すると自動で作成されるため、トピックのみ作成します。
手順は少ないですが、以下の操作で作成できます。
- Cloud Pub/Sub の画面を開いて、[トピックを作成]を押下します。
- トピック ID を記入して、トピックを作成します。(トピック ID はなんでもいいですが、今回は
InstanceMgmt
で進めていきます。)
Cloud SQL インスタンスの起動と停止を制御する Cloud Run Functions の作成
このセクションが 2021 年記事と大きく異なる部分です。
2021 年記事では、第一世代を利用していましたが、2024 年時点では第二世代を利用します。
第一世代と異なる点は、イベントの受け取り方が event.Event
を利用して受け取るようになったことです。
ただし、画面上での操作は大きく変わらないため、手順に従って進めていただければ問題ありません。
なお、2021 年記事と同様に画面上で関数を作成する予定でしたが、原因不明のエラーが発生したため、今回は gcloud コマンドを利用して関数を作成します。
Cloud Run Functionsの作成の有効化
- Cloud Run Functions の画面を開きます。
- [ファンクションを作成]をクリックします。
- 以下の画面が表示されたら、[有効にする]をクリックします。(すでに有効になっている場合はこの画面は表示されません。)
コードの実装
-
functions.go
とgo.mod
の2つのファイルを作成します。
- 以下の内容で
functions.go
を作成します。
// Package p contains a Pub/Sub Cloud Function.
package p
import (
"context"
"encoding/json"
"fmt"
"github.com/cloudevents/sdk-go/v2/event"
"google.golang.org/api/option"
"log"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)
func init() {
functions.CloudEvent("ProcessPubSub", ProcessPubSub)
}
// PubSubMessage is the payload of a Pub/Sub event.
// See the documentation for more details:
// https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage
type PubSubMessage struct {
Data []byte `json:"data"`
}
type MessagePublishedData struct {
Message PubSubMessage
}
type MessagePayload struct {
Instance string
Project string
Action string
}
// ProcessPubSub consumes and processes a Pub/Sub message.
func ProcessPubSub(ctx context.Context, e event.Event) error {
log.Println("ProcessPubSub function invoked")
// Unmarshal the Pub/Sub message.
var pubsubData MessagePublishedData
if err := e.DataAs(&pubsubData); err != nil {
fmt.Errorf("error unmarshalling Pub/Sub message: %v", err)
}
var psData MessagePayload
err := json.Unmarshal(pubsubData.Message.Data, &psData)
if err != nil {
log.Println(err)
}
log.Printf("Request received for Cloud SQL instance %s action: %s, %s", psData.Action, psData.Instance, psData.Project)
// Create the Google Cloud SQL service.
sqladminService, err := sqladmin.NewService(ctx, option.WithScopes(sqladmin.CloudPlatformScope))
// Get the requested start or stop Action.
action := "UNDEFINED"
switch psData.Action {
case "start":
action = "ALWAYS"
case "stop":
action = "NEVER"
default:
log.Printf("No valid action provided")
}
// See more examples at:
// https://cloud.google.com/sql/docs/sqlserver/admin-api/rest/v1beta4/instances/patch
rb := &sqladmin.DatabaseInstance{
Settings: &sqladmin.Settings{
ActivationPolicy: action,
},
}
resp, err := sqladminService.Instances.Patch(psData.Project, psData.Instance, rb).Context(ctx).Do()
if err != nil {
log.Fatal(err)
}
log.Printf("%#v\n", resp)
return nil
}
- 以下の内容で
go.mod
を作成します。
module example.com/gcf
go 1.22.7
require (
github.com/GoogleCloudPlatform/functions-framework-go v1.7.0
github.com/cloudevents/sdk-go/v2 v2.15.2
google.golang.org/api v0.196.0
)
require (
cloud.google.com/go/auth v0.9.3 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.3 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.uber.org/atomic v1.4.0 // indirect
go.uber.org/multierr v1.1.0 // indirect
go.uber.org/zap v1.10.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/text v0.17.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.66.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
)
- 以下の内容で関数を作成します。下記のコマンドを実行してください。(コマンドはカレントディレクトリが
functions.go
とgo.mod
が入ったディレクトリを前提としています。カレントディレクトリが別の場所にある場合は、移動して実行をお願いします。)- 環境名: Cloud Run function
- 関数名:
start-or-stop-cloud-sql-instance
- リージョン: asia-northeast1
- トリガー: Cloud Pub/Sub
- トピック: InstanceMgmt
- ランタイム: Go 1.22
gcloud functions deploy start-or-stop-cloud-sql-instance \
--gen2 \
--runtime=go122 \
--region=asia-northeast1 \
--source=. \
--entry-point=ProcessPubSub \
--trigger-topic=InstanceMgmt \
--project=<プロジェクト ID>
- Cloud Build が動いて、デプロイされるので、しばらく待ちます。
- 画像のように関数が作成されていたら成功です。
Cloud Run Functions のサービスアカウントに IAM ロールを付与
現状のままだと、SQL を起動、停止する権限がないため、サービスアカウントに IAM ロールを付与します。
- IAM と管理の画面を開きます。
- Cloud Run Functions で利用しているサービスアカウントのペンマークをクリックします。
-
Cloud SQL 管理者
のロールを付与します。
- [保存]をクリックします。
Cloud SQL Admin API の有効化
- API とサービスの画面を開きます。
-
Cloud SQL Admin API
を検索して、有効化します。
これで、Cloud Run Functions を動作させるための準備が整いました。
Cloud Schedulerの設定
ここは 2021 年記事と変わらないため、手順に従って進めていただければ問題ありません。
-
Cloud Scheduler の画面を開き、[ジョブの作成]をクリックします。
-
名前、リージョン、頻度、タイムゾーンを設定し[続行]をクリックします。
-
[ターゲットタイプ]から Pub/Sub を選択します。
-
前章で作成したトピックを選択します。
-
以下記載の Pub/Sub メッセージを[メッセージ本文]に記入します。
- 起動メッセージ
{ "Instance": "<SQLインスタンス名>", "Project": "<プロジェクト名>", "Action": "start" }
- 停止メッセージ
{ "Instance": "<SQLインスタンス名>", "Project": "<プロジェクト名>", "Action": "stop" }
-
[作成]をクリックします。
この手順が終了すると、Cloud SQL インスタンスの起動と停止をスケジュールすることができるようになります。
おわりに
今回は、Cloud SQL インスタンスの起動と停止をスケジュールする方法をご紹介しました。
こちらの記事が開発費用の削減の一助になれば幸いです。
Discussion