今回は Google Cloud の Cloud Functions で実行した処理の中で Cloud Storage にオブジェクトを保存する方法について。 Cloud Functions で実行した何らかの処理の成果物を保存する先として Cloud Storage を使うイメージになる。
操作は、基本的に Google Cloud SDK の gcloud コマンドから実施する。 なお、操作の対象となる Google Cloud API が有効化されていない場合には、別途有効化するかを確認する表示が出ることもある。
使った環境は次のとおり。
$ sw_vers ProductName: macOS ProductVersion: 13.5 BuildVersion: 22G74 $ gcloud version Google Cloud SDK 442.0.0 bq 2.0.96 core 2023.08.04 gcloud-crc32c 1.0.0 gsutil 5.25
下準備
まずは Google Cloud SDK をインストールしておく。
$ brew install google-cloud-sdk
そして、利用したいアカウントにログインする。
$ gcloud auth login
必要に応じて、デフォルトで操作する対象のプロジェクトを指定する。
$ gcloud config set project <project-id>
Cloud Pub/Sub のトピックを作成する
Cloud Functions のトリガーとして Cloud Pub/Sub を使いたい。
そこで、まずはトピックを作成しておく。
ここでは example-pubsub-topic
という名前にした。
$ gcloud pubsub topics create example-pubsub-topic
Cloud Storage のバケットを作成する
続いて Cloud Storage にオブジェクトを保存する先となるバケットを作成する。 バケットに付ける名前は、Cloud Storage のシステム全体でユニークな必要がある。
今回はユーザ名や日付などから、ユニークになりやすい組み合わせでサンプルとなるバケットの名前を作った。 別にこれでなくとも誰かが使っているバケットの名前と衝突しなければ何でも構わない。
$ UNIQUE_BUCKET_NAME=$(echo $(whoami)-example-bucket-$(date +%Y%m%d)) $ echo $UNIQUE_BUCKET_NAME amedama-example-bucket-20230806
バケットは gcloud storage buckets create
コマンドで作成する。
基本的に Cloud Storage の操作をするときは、対象を URI で指定する。
その際、スキーマとして先頭に gs://
をつける必要がある。
また、--location
オプションを指定しない場合はマルチリージョンで us
にバケットが作成される。
$ gcloud storage buckets create \ gs://${UNIQUE_BUCKET_NAME} \ --location=asia
Cloud Functions を作成する
続いては Cloud Storage のバケットにオブジェクトを作成する Cloud Functions を作成する。
まずは必要なファイルを入れるディレクトリを用意する。
ここでは helloworld
という名前で作成した。
$ mkdir helloworld
続いて Cloud Functions の本体となる処理を Python のモジュールとして作成する。
ポイントは google.cloud.storage
パッケージを使って Cloud Storage にオブジェクトを作成しているところ。
バケットの名前は BUCKET_NAME
という環境変数から取得するように作ってある。
なお、環境変数が指定されていない場合のエラーハンドリングは省略してある。
$ cat << 'EOF' > helloworld/main.py import logging import os from datetime import datetime from google.cloud import logging as gcloud_logging from google.cloud import storage as gcloud_storage gcloud_logging.Client().setup_logging() LOG = logging.getLogger(__name__) def main(event, context): gcs_client = gcloud_storage.Client() bucket_name = os.environ.get("BUCKET_NAME") bucket = gcs_client.bucket(bucket_name) now = datetime.now() file_name = now.strftime("%Y-%m-%d/%H:%M:%S.log") blob = bucket.blob(file_name) timestamp = now.strftime("%Y%m%d%H%M%S") file_data = f"executed: {timestamp}\n" blob.upload_from_string(file_data) LOG.info( "successfully saved to %s in %s", file_name, bucket_name ) EOF
オブジェクトには Cloud Functions が実行された時刻をタイムスタンプとして書き込んでいる。
動作に必要なパッケージは requirements.txt
に記述する。
$ cat << 'EOF' > helloworld/requirements.txt google-cloud-logging google-cloud-storage EOF
上記で次のようなファイル構成が作られる。
$ tree helloworld helloworld ├── main.py └── requirements.txt 1 directory, 2 files
Cloud Functions をデプロイする
先ほどのディレクトリを元に Cloud Functions をデプロイするには gcloud functions deploy
コマンドを使う。
このとき --set-env-vars
オプションを使って環境変数を設定できる。
バケットの名前として BUCKET_NAME
を忘れずに指定しよう。
また --trigger-topic
を指定することで、指定した Cloud Pub/Sub のトピックにメッセージが到着した際に処理がトリガーされる。
$ gcloud functions deploy helloworld \ --gen2 \ --no-allow-unauthenticated \ --runtime python310 \ --memory 128Mi \ --region asia-northeast1 \ --trigger-topic example-pubsub-topic \ --source helloworld \ --entry-point main \ --set-env-vars BUCKET_NAME=${UNIQUE_BUCKET_NAME}
うまくいけば gcloud functions list
にデプロイした Cloud Functions が表示される。
$ gcloud functions list
NAME STATE TRIGGER REGION ENVIRONMENT
helloworld ACTIVE topic: example-pubsub-topic asia-northeast1 2nd gen
また gcloud functions logs read
コマンドでエラーなどが出ていないかも確認しておこう。
$ gcloud functions logs read helloworld --region asia-northeast1 LEVEL NAME TIME_UTC LOG I helloworld 2023-08-06 14:56:35.116 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 "-"
少ししたら、また gcloud functions logs read
コマンドを実行してログを確認しよう。
うまくいけば次のようなログが出力される。
$ gcloud functions logs read helloworld --region asia-northeast1 LEVEL NAME TIME_UTC LOG I helloworld 2023-08-06 14:59:00.192 successfully saved to 2023-08-06/14:58:57.log in amedama-example-bucket-20230806 I helloworld 2023-08-06 14:59:00.191 I helloworld 2023-08-06 14:58:57.341 I helloworld 2023-08-06 14:56:35.116 Default STARTUP TCP probe succeeded after 1 attempt for container "helloworld-1" on port 8080.
Cloud Storage の内容を確認する
Cloud Functions から作成された Cloud Storage のオブジェクトを確認しよう。
gcloud storage ls -r
コマンドを使うことでバケットの中身を再帰的に表示できる。
$ gcloud storage ls -r gs://${UNIQUE_BUCKET_NAME} gs://amedama-example-bucket-20230806/: gs://amedama-example-bucket-20230806/2023-08-06/: gs://amedama-example-bucket-20230806/2023-08-06/14:58:57.log
オブジェクトの内容は gcloud storage cat
コマンドで確認できる。
$ gcloud storage cat gs://${UNIQUE_BUCKET_NAME}/2023-08-06/14:58:57.log executed: 20230806145857
どうやら意図した通りに作成されているようだ。
後片付けする
動作の確認が終わったら後片付けをしよう。
まずは Cloud Storage のオブジェクトとバケットを削除する。
gcloud storage rm -r
を使うとバケットの中身とバケット自体が再帰的に削除できる。
$ gcloud storage rm -r gs://${UNIQUE_BUCKET_NAME}
続いて gcloud functions delete
コマンドを使って Cloud Functions の関数を削除する。
$ gcloud functions delete helloworld --region asia-northeast1
そして gcloud pubsub topics delete
コマンドを使って 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 Storage にオブジェクトを保存する方法を確認した。