何らかの処理を定期的に実行したくなる場面は多い。 トラディショナルなやり方であれば、仮想マシンを用意して cron などで処理を呼び出すと思う。 もちろん、それでも良いんだけど、よりシンプルに実装したい気持ちが出てくる。 具体的にはマシンの管理をなくした、いわゆるサーバレス・コンピューティングで楽がしたくなる。
Google Cloud であれば、このようなニーズに対して以下のサービスを組み合わせるのが良いようだ。
Cloud Functions
- サーバレスで特定の処理 (関数) を呼び出すためのサービス
Cloud Scheduler
- フルマネージドな cron ジョブを提供するサービス
Cloud Pub/Sub
- 非同期のスケーラブルなメッセージングを提供するサービス
利用の流れは次のとおり。 まず、Cloud Functions で定期的に実行したい何らかの処理を定義する。 その際、Cloud Pub/Sub にメッセージが到達したタイミングで処理が実行されるように設定する。 そして、Cloud Scheduler から特定のタイミングで Cloud Pub/Sub にメッセージを送ることになる。
今回は、サービスを組み合わせて 1 分ごとに Cloud Functions を実行させてみよう。 操作は、基本的に Google Cloud SDK の gcloud コマンドから実施する。 なお、操作の対象となる Google Cloud API が有効化されていない場合には、別途有効化するかを確認する表示が出ることもある。
使った環境は次のとおり。
$ sw_vers ProductName: macOS ProductVersion: 13.5 BuildVersion: 22G74 $ gcloud version Google Cloud SDK 441.0.0 bq 2.0.95 core 2023.07.28 gcloud-crc32c 1.0.0 gsutil 5.25
もくじ
- もくじ
- 下準備
- Cloud Pub/Sub のトピックを作成する
- Cloud Functions を Python で作成する
- Cloud Functions をデプロイする
- Cloud Scheduler のジョブを作成する
- 後片付け
- まとめ
下準備
まずは下準備として Google Cloud SDK をインストールしておく。
$ brew install google-cloud-sdk
gcloud コマンドが使えるようになるのでログインする。
$ gcloud auth login
操作するプロジェクトを指定する。 なお、プロジェクトはあらかじめ作成しておく。
$ gcloud config set project <project-name>
Cloud Pub/Sub のトピックを作成する
まずは Cloud Scheduler と Cloud Functions の間をつなぐ Cloud Pub/Sub のトピックを作成する。
名前は分かりやすければ何でも構わない。
今回は example-pubsub-topic
という名前にした。
$ gcloud pubsub topics create example-pubsub-topic
Cloud Functions を Python で作成する
続いて Cloud Functions を作成する。 プログラミング言語として今回は Python を利用する。
まずは必要なファイル一式を収めるディレクトリを作成する。
ここでは helloworld
という名前にした。
$ mkdir helloworld
続いて肝心の実行される処理を定義する。
以下では main.py
というモジュール名で作成している。
処理の本体は main()
関数で、この関数がイベントハンドラとして呼び出される。
ただし、中身の処理はログを 1 行出力しているだけ。
なお、ログの出力先を Cloud Logging にするために google-cloud-logging パッケージを利用している。
$ cat << 'EOF' > helloworld/main.py import logging from google.cloud import logging as gcloud_logging # Cloud Logging にログを出力できるようセットアップする gcloud_logging.Client().setup_logging() LOG = logging.getLogger(__name__) def main(event, context): # Cloud Functions のイベントハンドラでログを出力する LOG.info("Hello, World!") EOF
処理が定義できたら必要なパッケージを requirements.txt
で定義する。
ここでは、先ほどの処理の中で利用していた google-cloud-logging をインストールしている。
$ cat << 'EOF' > helloworld/requirements.txt google-cloud-logging EOF
ここまでで、ディレクトリの構成は次のようになっている。
$ tree helloworld helloworld ├── main.py └── requirements.txt 1 directory, 2 files
これで Cloud Functions に必要な準備が整った。
Cloud Functions をデプロイする
続いて Cloud Functions をデプロイする。
デプロイには gcloud functions deploy
コマンドを使う。
以下では helloworld
という名前で Cloud Functions をデプロイしている。
$ gcloud functions deploy helloworld \ --gen2 \ --no-allow-unauthenticated \ --runtime python310 \ --memory 128Mi \ --region asia-east1 \ --trigger-topic example-pubsub-topic \ --source helloworld \ --entry-point main
オプションについては次のような意味になる。
--gen2
- 現在 (2023-08) の Cloud Functions には第 1 世代と第 2 世代があり、後者を利用するために指定している
--no-allow-unauthenticated
- 任意のユーザが呼び出しできないように指定している
--runtime python310
- Python 3.10 / Ubuntu 22.04 LTS の環境で実行されるように指定している
--memory 128Mi
- ランタイムが利用できるメモリのサイズを指定している
--region asia-east1
- デプロイ先のリージョンを指定している
--trigger-topic example-pubsub-topic
- メッセージが到着した際に実行されるトピックを指定している
--source helloworld
- デプロイするディレクトリを指定している
--entry-point main
- イベントハンドラの関数名を指定している
デプロイが成功すると gcloud functions list
コマンドで確認できる。
もしエラーになったときはログなどから原因を調査する。
$ gcloud functions list
NAME STATE TRIGGER REGION ENVIRONMENT
helloworld ACTIVE topic: example-pubsub-topic asia-east1 2nd gen
デプロイされた時点で Cloud Functions のログが gcloud functions logs read
コマンドで確認できる。
$ gcloud functions logs read helloworld --region asia-east1 LEVEL NAME TIME_UTC LOG I helloworld 2023-08-06 15:48:33.154 Default STARTUP TCP probe succeeded after 1 attempt for container "helloworld-1" on port 8080.
デプロイできたら、手動で Cloud Pub/Sub にメッセージを送って Cloud Functions を実行してみる。
$ gcloud pubsub topics publish projects/$(gcloud config get-value project)/topics/example-pubsub-topic --message "-"
うまくいけばメッセージの到着によって Cloud Functions が実行される。 次のようにログが出力されることを確認しよう。 なお、空白のログは Cloud Functions が起動されたことを示しているらしい。 空白のログが 2 回出るのはデプロイした後の初回の起動時だけのようだ。
$ gcloud functions logs read helloworld --region asia-east1 LEVEL NAME TIME_UTC LOG I helloworld 2023-08-06 15:50:14.490 Hello, World! I helloworld 2023-08-06 15:50:14.395 I helloworld 2023-08-06 15:50:14.260 I helloworld 2023-08-06 15:48:33.154 Default STARTUP TCP probe succeeded after 1 attempt for container "helloworld-1" on port 8080.
これで Cloud Functions が Cloud Pub/Sub のメッセージが到着した際に想定通り実行されることが確認できた。
Cloud Scheduler のジョブを作成する
最後に Cloud Scheduler を設定する。
まず、現在のジョブを gcloud scheduler jobs list
で確認する。
ここでは何も設定されていない。
$ gcloud scheduler jobs list --location=asia-east1 Listed 0 items.
続いて Cloud Scheduler のジョブを作成する。
ジョブのタイプとして pubsub
を指定する。
ここではジョブの名前に helloworld
を指定している。
$ gcloud scheduler jobs create pubsub helloworld \ --location asia-east1 \ --schedule "* * * * *" \ --topic "projects/$(gcloud config get-value project)/topics/example-pubsub-topic" \ --message-body "-"
指定しているオプションの意味は次のとおり。
--location asia-east1
- ジョブを作成するリージョンを指定している
--schedule "* * * * *"
- UNIX cron の書式でスケジュールが実行されるタイミングを指定している
--topic "projects/$(gcloud config get-value project)/topics/example-pubsub-topic"
- メッセージを送信する Cloud Pub/Sub のトピックを指定している
--message-body "-"
- メッセージの内容を指定している (今回、中身は使っていないためダミー)
ちなみに UNIX cron の書式は以下のようなサービスで確認すると効率が良い。
うまくいけば次のようにジョブが作成される。 これで 1 分ごとに Cloud Pub/Sub にメッセージが送信される。
$ gcloud scheduler jobs list --location=asia-east1 ID LOCATION SCHEDULE (TZ) TARGET_TYPE STATE helloworld asia-east1 * * * * * (Etc/UTC) Pub/Sub ENABLED
少し待って Cloud Functions のログを確認してみよう。 次のように 1 分ごとに処理が実行されてログが出力されていれば上手くいっている。
$ gcloud functions logs read helloworld --region asia-east1 | head -n 6 LEVEL NAME TIME_UTC LOG I helloworld 2023-08-06 15:58:03.741 Hello, World! I helloworld 2023-08-06 15:58:03.718 I helloworld 2023-08-06 15:57:04.491 Hello, World! I helloworld 2023-08-06 15:57:04.427 I helloworld 2023-08-06 15:50:14.490 Hello, World!
後片付け
動作の確認が終わったら後片付けしよう。
まずは Cloud Scheduler のジョブを削除する。
$ gcloud scheduler jobs delete helloworld --location=asia-east1
続いて Cloud Functions の定義を削除する。
$ gcloud functions delete helloworld --region asia-east1
そして Cloud Pub/Sub のトピックを削除する。
$ gcloud pubsub topics delete example-pubsub-topic
また、Cloud Functions のファイル群は Cloud Storage にアップロードされる。 今回の構成であれば、次のような名前のバケットが作成されているはず。
gcf-v2-sources-<project-id>-<region>
gcf-v2-uploads-<project-id>-<region>
そこで、まずは次のようにバケットを確認する。
$ gcloud storage buckets list | grep name
バケットが確認できたら、次のようにして削除する。
$ gcloud storage rm -r gs://<bucket-name>
いじょう。
まとめ
今回は Cloud Functions を Cloud Scheduler から定期実行する方法を試してみた。 また、一連の操作は基本的に Google Cloud SDK の CLI で実施した。