おはようございます、今日はGCPのサーバレスサービス、Cloud Functionsと、NoSQLサーバレス、Cloud Firestoreを用いたアプリケーションを作ってみます。
Cloud Functions、Cloud Firestoreについてはそれぞれ以下の記事でもどうぞ。
今回のテーマはこちら!
- 今回作成するもの
- サービスアカウントの設定をする
- Cloud Firestoreの設定
- Cloud Functions関数の作成
- Cloud Funtions関数をデプロイする
- Cloud Schedulerの設定
- 実行結果
- まとめ
今回作成するもの
今回作成するものは以下のとおりです。
当ブログのRSSデータをCloud Functionsで収集し、データをCloud Firestoreに書き込みます。
Cloud FunctrionsはHTTP関数とし、Cloud Schedulerでスケジュール実行されるようにします。
サービスアカウントの設定をする
GCPコンソールから、[IAMと管理] > [サービスアカウント] > [サービスアカウントを作成]と進みます。
名前や説明は任意です。 サービスアカウントに「編集者」ロールを付与します。
その後、認証情報(秘密鍵)をservice_account.json
というファイル名でローカルに保存しておきます。
Cloud Firestoreの設定
「true-fly-rss」という新しいコレクションを作成しておきます。
最初のドキュメントは適当に作成し、後で削除します。
Cloud Functions関数の作成
今回はPython3.8で作成していきます。
ローカルディレクトリ構成
ディレクトリ構成は以下の通りになります。
まずはローカルで動くようにプログラムを書いていきます。
. ├── .gcloudignore ├── main.py ├── requirements.txt └── service_account.json
環境変数の設定
service_account.json
があるディレクトリで以下を実行します。プログラム上で参照する環境変数です。
export PROJECT_ID=自分のGCPのプロジェクトID export GOOGLE_APPLICATION_CREDENTIALS="$PWD/service_account.json"
Pythonライブラリのインストール
以下のrequirements.txt
をローカルに作成します。
cachetools==4.2.2 certifi==2021.5.30 charset-normalizer==2.0.4 google-api-core==2.0.1 google-auth==2.0.2 google-cloud-core==2.0.0 google-cloud-firestore==2.3.1 googleapis-common-protos==1.53.0 grpcio==1.39.0 idna==3.2 packaging==21.0 proto-plus==1.19.0 protobuf==3.17.3 pyasn1==0.4.8 pyasn1-modules==0.2.8 pyparsing==2.4.7 requests==2.26.0 rsa==4.7.2 six==1.16.0 urllib3==1.26.6 xmltodict==0.12.0
その後、以下のコマンドでローカルにライブラリをインストールしましょう。
pip install -r requirements.txt
.gcloudignoreの作成
.gcloudignore
ファイルを作成します。
今回はCloud Functions関数をgcloudコマンドでローカルからデプロイするため、サービスアカウントのJSONファイルだったり、不要なファイルをデプロイしないように記述しておきます。
service_account.json
Pythonファイルの作成
以下のファイルをmain.py
として作成しておきます。
本ブログからRSSデータを取得し、Cloud Firestoreに書き込むプログラムです。
ローカルで実行しても動くように作成しています。デプロイする前にローカル環境でも実行できることを確認しておきましょう。
import json from datetime import datetime import os from google.cloud import firestore from google.cloud.firestore_v1 import collection import requests import xmltodict def __get_rss_data(): res = requests.get('https://www.true-fly.com/rss') res_xml = xmltodict.parse(res.text) json_object = json.dumps(res_xml) dic = json.loads(json_object) return_json = [] for row in dic['rss']['channel']['item']: return_json.append({ 'key': row['link'].replace('https://www.true-fly.com/entry/', '') .replace('/', ''), 'url': row['link'], 'title': row['title'], 'description': row['description'], 'published_at': datetime.strptime(row['pubDate'], '%a, %d %b %Y %H:%M:%S %z'), 'categories': row['category'], }) return return_json def __set_documents(data): db = firestore.Client() my_collection = db.collection('true-fly-rss') for row in data: doc_ref = my_collection.document(row['key']) row.pop('key') doc_ref.set(row, merge=True) def execute(request): rss_data = __get_rss_data() __set_documents(rss_data) # returnを書かないとHTTP関数がエラーになるので、空dictを返します return {} if __name__ == '__main__': execute(None)
Cloud Funtions関数をデプロイする
Cloud Functions関数をデプロイします。今回はgcloudコマンドでデプロイします。
以下のコマンドで、Python3.8のHTTP関数を作成します。
--entry-point
はプログラムのエントリポイントとなる関数名を書きます。
--no-allow-unauthenticated
は、関数呼び出し時に認証を必要とさせるオプションです。
--service-account
は、どのサービスアカウントで関数を実行するかを設定するオプションです。
gcloud config set [プロジェクトID] gcloud functions deploy get-rss-data \ --region asia-northeast1 \ --entry-point execute \ --runtime python38 \ --trigger-http \ --no-allow-unauthenticated \ --service-account=[サービスアカウント]
コマンド実行し、以下のメッセージと、関数の設定詳細が標準出力されたら成功です!
Deploying function (may take a while - up to 2 minutes)...done.
WebUIで関数が見られることを確認しましょう。
Cloud Schedulerの設定
以下を参考にHTTP関数を呼び出しするようにジョブを設定します。詳細は省略。 www.true-fly.com
実行結果
Cloud Scheculerから手動実行して、結果を確認してみましょう。
Cloud FirestoreのWeb UIからtrue-fly-rssコレクションを確認してみます。
無事データが登録されていることが確認できました!
まとめ
以上、今回はCloud Scheduker + Cloud Functions+ Cloud Firestoreを組み合わせて一つのサービスを開発する方法について学びました。
フルクラウドで、サーバレスで、プログラムのスケジュール実行と、データの読み書きができます。
今回の例のように、RSSデータだったり、スクレイピング、外部APIなどでデータを収集し、それをスキーマレスのCloud Firestoreに貯めるといった流れは、実際の業務のデータ収集基盤としても応用できそうです!