Google Cloud Functions で Python3 が使えるということだったので使ってみました。実際のプロダクトで使うことも考えて、環境変数の扱い、ローカルでの開発についても説明しています。
なお、この記事はタスク管理にGitHubを使う一連の記事の中の一つです。
- 情シスのタスクをGitHubのissueで管理するようにしたら捗った
- プロジェクト管理ツールとしてGitHubを"普通に"使う
- Google Cloud Functions (Python) を使ってみた ←ここ
- GitHub App を作ってPythonからAPIを叩いてみた
- Google Apps Script から Google Cloud Functions のHTTPトリガーを実行してみた
前提
以下のことが完了している前提で説明します。
- Google Cloud Platform のアカウント作成
-
gcloudコマンドのインストール
- ログイン (
gcloud auth login
)
- ログイン (
クイックスタート
まずは簡単に関数を作ってみます。
関数の作成
設定
今回指定した設定は以下の表のとおりです。
項目 | |
---|---|
メモリ | 256 MB |
トリガー | HTTP |
ランタイム | Python 3.7 |
ソースコード | インライン エディタ |
実行する関数 | hello_world |
確認
Google Cloud Platform のコンソール画面からも確認できますが、 gcloud でログインしていればローカルからのコマンドでも確認できます。
$ gcloud functions list
結果
NAME STATUS TRIGGER REGION
function-1 ACTIVE HTTP Trigger us-central1
実行
実行のためのトリガーは以下のように複数の選択肢があります。
- HTTP
- Cloud Storage
- Cloud Pub/Sub
- Firebase
今回はHTTPのトリガーを作成したので、ブラウザや curl
コマンドで直接 GET
リクエストを送って確認できます。URLはコンソール画面でに表示されています。
Python3 関連ファイル
Python3で Cloud Functions を作成すると、2つのファイルができています。
- main.py
- requirements.txt
実行したい関数は main.py の中に適当な名前で実装し、「実行する関数」でその名前を指定すると実行できます。サードパーティ製の必要なライブラリがあったら requirements.txt に書いておけばデプロイしたときに自動的にインストールしてくれます。また、Pythonファイルは一つだけではなくPythonパッケージを作成して main.py から import
することもできます。
ローカルからのデプロイ
できるならコードを毎回ブラウザ上のエディタではなくローカルで開発してGit管理するほうが望ましいと思われます。Cloud Source Repositories を使うと Google Cloud Platform 上での管理もできますが、ここではGitHubを想定します。
gcloudコマンドによるデプロイ
とりあえずコピーしてくるなり何なりして同様の環境をローカルに作り、ローカルからデプロイコマンドを実行すればデプロイできます。
$ gcloud functions deploy function-1 --trigger-http --runtime=python37
少し変更を加えて先程のエンドポイントにアクセスするとローカルからのデプロイができていることがわかると思います。
不要なファイルをアップロードしないようにする
ローカルに適当なファイルを置いておけばコマンド一つでデプロイしてくれるのですが、何もしなければGit管理用のファイルなど、関係ないファイルまでアップロードしてしまいます。
そこで .gcloudignore というファイルを作成しておきます。.gitignore のように、ここにアップロードしたくないファイルやディレクトリを記載しておけば、デプロイの際にアップロードされることがありません。
なお、 .gcloudignore から他のファイルを参照することもできるので、 .gitignore を参照すると良いかもしれません。
.gcloudignore
.gitignore
Makefile
README.md
requirements_local.txt
test/
venv/
#!include:.gitignore
ローカルでの開発
簡単にデプロイして確認ができる Cloud Functions ですが、毎回アップロードしなければ確認できないのは不便です。そのためにローカルでエミュレートする仕組みを作ります。
仮想環境の作成 (venv)
必須ではありませんが、必要に応じて仮想環境を用意しておくと便利です。
$ python3 venv venv
$ source venv/bin/activate
Flaskによるエミュレート
Google Cloud Function で始めに実行される関数は、Flaskの flask.Request
オブジェクトを受け取ります。ローカルで開発する際にはlocalhostにFlaskの開発用サーバーが立ち上がるようにすることでエミュレートできます。
ライブラリのインストール
$ pip install flask
実装
from flask import Flask, request
def hello_world(request):
# ...
return 'HelloWorld!'
if __name__ == "__main__":
app = Flask(__name__)
@app.route('/')
def index():
return hello_world(request)
app.run('127.0.0.1', 8000, debug=True)
このように、 main.py が直接呼ばれた場合は開発用サーバーが立ち上がり、 localhost:8000 にアクセスすると hello_world
が実行されます。
環境変数
作成するアプリケーションによっては、他のサービスのAPIキーなど、ソースコードに書きたくない情報を含んでいる場合があります。そういった場合には環境変数を設定することができます。
設定方法
コマンドの引数を使う方法
一つの方法は、デプロイする際にコマンドの引数で指定する方法です。
$ gcloud functions deploy function-1 --trigger-http --runtime=python37 --set-env-vars FOO=bar,BAZ=boo
Yamlを使う方法
FOO: bar
BAZ: boo
$ gcloud functions deploy function-1 --trigger-http --runtime=python37 --env-vars-file=./env.yaml
読み込み
Google Cloud Function に設定した環境変数を使う方法は自分でサーバーを立ち上げたときなど、他の環境と同じです。
import os
FOO = os.getenv('FOO') # 'bar'
BAZ = os.getenv('BAZ') # 'boo'
Yamlを使うときの運用方法
コマンドの引数を使う方法とYamlを使う方法がありますが、どちらかといえばファイルで管理できるYamlを使うほうが好みです。しかし、Git管理はしたくないので、そのために少し工夫を加えます。
ローカルでの確認
Yamlで環境変数を設定する場合は、ローカル環境でもそのYamlを読み込むようにすると便利です。そこで以下のようにYamlから環境変数を設定するように手を加えます。
ライブラリのインストール
$ pip install PyYAML
※ ImportError にならないようにするために requirements.txt にもPyYAMLを書き加えておきます。
実装
import os
import yaml
try:
# local
with open('./env.yaml') as f:
os.environ.update(yaml.load(f))
except FileNotFoundError as e:
# Google Cloud Functions
pass
FOO = os.getenv('FOO') # 'bar'
BAZ = os.getenv('BAZ') # 'boo'
Google Cloud Storage を使う
Git管理をしたくないので、適当な Google Cloud Storage のバケットを作って、そこに env.yaml を保存しておき、デプロイする際にコピーしてくるようにします。 .gitignore に env.yaml を書き加えるのも忘れずに。
アップロード
$ gsutil cp ./env.yaml gs://[bucket_name]/env.yaml
ダウンロード
$ gsutil cp gs://[bucket_name]/env.yaml ./env.yaml
ちなみに gsutil
コマンドは Google Cloud SDK をインストールしたときにインストールされているかと思います。
環境変数を使わない運用
公開したくない情報をGit管理しないために環境変数を使う方法もありますが、 Google Cloud Storage を直接 Google Cloud Function から読み込んで環境変数を使わない方法もあります。
IAMの設定
Google Cloud Functions から Cloud Storage の情報を取得するために、必要に応じてサービスアカウントに対して権限を付与します。ちなみにサービスアカウントとは Google Cloud Platform の各サービスが、疑似ユーザーのように振る舞う仕組みです。
Google Cloud Functions のサービスアカウント
サービスアカウントはコンソール画面から確認できます。
サービスアカウントに権限を付与
おそらくデフォルトのままでも大丈夫ですが、権限が足りない場合は「IAM と管理」から対象のサービスアカウントを編集して↓の権限を付与します。
ストレージ→ストレージ オブジェクトの閲覧者
※ なお、これは「バケットレベルで権限を一様に設定(バケットポリシーのみ)」のアクセス制御モデルで作成したバケットを使用しています。
ライブラリのインストール
ここでは google-cloud-storage
を利用してみます。
$ pip install google-cloud-storage
実装
google-cloud-storage
を利用したときの実装例です。
import os
import yaml
from google.cloud import storage
def get_data():
client = storage.Client()
bucket = client.get_bucket('[bucket_name]')
blob = storage.Blob('env.yaml', bucket)
return yaml.load(blob.download_as_string())
os.environ.update(get_data())
FOO = os.getenv('FOO') # 'bar'
BAZ = os.getenv('BAZ') # 'boo'
ローカルでの開発
なお、ローカルで開発する場合は↓のようにログインする必要があります。
$ gcloud auth application-default login
サンプルコード