RORO

ふつうの日記

Google Cloud Functionsを試す with Python 3.7

Cloud Functionsは、端的にいえばAWS LambdaのGoogle Cloud版だ。要するに、比較的小規模なコードをデプロイしておいて、何らかのトリガに応じてそれを実行させて、実行された時間分だけ課金される、という仕組みで、俗に「サーバレス」と呼ばれているものの礎でもある。

AWS Lambdaと比べて

Cloud Functionsの特徴としては:

  • HTTPトリガー(要するにWebhook)が最も基本的なトリガーである。
    • 汎用的な仕組みなのでロックインされにくい。
    • 外部サービスなどからのWebhook連携がシンプルに実現できる。HTTPエンドポイントを別途に設定しなくていいので、構成がシンプルだし、ロックインも軽減できる。
  • 使える言語: Python 3.x, Node.js, Go, (近日サポート?: Ruby, Java, PHP)
  • Pythonの場合は:
    • 依存パッケージは、pipのrequirements.txtに書いておくだけでインストールされる。
    • HTTPトリガの処理にはFlaskが使われる。

AWS Lambdaと比べて、簡便であることを重視している印象を受ける。

Functionを作る

基本的には公式ドキュメントのYour First Function: Pythonの通りにすればいいので、そこに載ってないことだけ書いておく。

Functions Frameworkを使う

最近になってFunctions Frameworkというライブラリが用意されたようだ。これは、実行環境(ローカル環境 / Cloud Functions / Cloud Run)を選ばずに、Functionを実行するためのもので…といっても大げさなものではなくて、例えばPython版の場合は単にFlaskやGunicornによる実行を遮蔽しているに過ぎない。

Functions Frameworkを利用して、Functionを作ってみる。

$ pip3 install functions-framework -U

main.py

def hello(request):
    return "Hi"

requirements.txt

# 今回は空っぽ

そして以下のように実行すると、Flaskアプリケーションとして実行される:

$ functions-framework --target=hello --debug

Functionをデプロイする

以下のコマンドでデプロイできる。デプロイを上書きする時も同じ。

$ gcloud functions deploy <name> \
    --project <project-name> \
    --region=asia-northeast1 \
    --runtime=python37 \
    --entry-point=hello \
    --trigger-http \
    --allow-unauthenticated

ここでは以下を指定している。

  • リージョンはasia-northeast1(東京)
  • ランタイムはPython3.7
  • トリガはHTTP
  • 認証なし

デプロイには1分くらいかかる。

他のGoogle Cloudサービスを呼ぶ

作ったFunctionから他のGoogle Cloudサービスを呼ぶには当然ながらCredentials(認証情報)が必要になる。Cloud Functionsにおいては、環境変数GOOGLE_APPLICATION_CREDENTIALSを明示的に設定していない限り、デフォルトのCredentialsが自動的に取得される(内部的には、公式ライブラリがMetadata Serviceから取得してきてくれるっぽい)。

https://google-auth.readthedocs.io/en/latest/reference/google.auth.html#google.auth.default

この仕組みによって、コードベースなどにCredentialsを入れることなしに、他のGoogle Cloudのサービスを呼ぶことができる。例えばCloud Visionを使いたいなら、以下のようにするだけでいい。

client = vision.ImageAnnotatorClient()

Credentials自体が必要なときは、google-authモジュールを使えばいい。

import google.auth
(creds, _) = google.auth.default(scopes=["https://www.googleapis.com/auth/drive"])
drive_service = build("drive", "v3", credentials=creds)

データストア / 永続化

これはどうすればいいのかまだ考えていない。「ちょっとした自動化」程度のアプリケーションを除けば、多くの場合に、状態を保存するための場所が必要になる。Cloud Firestoreが最も手軽だろうか。

デプロイ後の監視など

エラー追跡

  • 標準の仕組み: 発生した例外は Cloud Error Reporting に集積される。
    • ただし通知はメール通知のみ
  • Sentryなどのサードパーティのエラーモニタリングサービスのほうが高機能
    • サーバレス環境用のPythonデコレータが提供されている
    • Slackへの通知などもできる

ロギング

  • 標準の仕組み: 以下は Cloud Logging に記録される
    • stdout, stderrへの出力
    • Cloud Logging ライブラリによるログ出力(Pythonのloggingモジュール用のハンドラあり)
  • 用途によってはPapertraillogDNAといった、ログをLive tailできるサービスも便利かもしれない(これらにはPythonのloggingモジュール用のハンドラもある)