GAEへpythonとFirestoreを使ったサービスをデプロイする

はじめに

Python3.7のruntimeがGAE standard environmentで使えるようになったため、flaskでアプリを作ってGAEへデプロイしている。DBにDatastoreとFirestoreが選択肢に入ってくるが、GoogleがFirestoreが後継だと強く言っているようなので、今回はこちらを選択した。

開発環境の設定

  1. GCPのコンソール上でFirebaseをenableにする
  2. gcloudコマンドのインストール
  3. サービスアカウントJSON fileをダウンロードし、GOOGLE_APPLICATION_CREDENTIALSへ割り当てる

FirebaseのサービスアカウントのJSONファイルはここから手に入れることができる。

$ curl https://sdk.cloud.google.com | bash
$ exec -l $SHELL
$ gcloud init
$ export GOOGLE_APPLICATION_CREDENTIALS=path/to/creds.json

サービスの実装

準備するファイルは下記。 - requirements.txt: dependenciesを宣言 - main.py: アプリのソースコード - app.yaml: GAEへのデプロイ用

まずはrequirements.txtgoogle-cloud-firestoreをあえて入れる理由はpipのバグがあるかららしい。本来はfirebase-adminだけで十分とのこと。

Flask==1.0.2
firebase-admin==2.13.0
google-cloud-firestore==0.29.0

次にmain.py。Firebase Admin SDKでクライアントを作っている。

import firebase_admin
import flask
from firebase_admin import firestore
from flask import request

app = flask.Flask(__name__)

firebase_admin.initialize_app()
SUPERHEROES = firestore.client().collection('superheroes')


@app.route('/', methods=['GET'])
def index():
    return """
    <h1> Create hero? </h1>
    <form method="post" action='/heroes'>
        <input type="text" size="30" name="hero name">
        <input type="submit" value="create hero">
    </form>
    <h1> Read hero? </h1> 
    <form method="post" action='/read'>
        <input type="text" size="30"name="id">
        <input type="submit" value="read hero">
    </form> 
    """


@app.route('/heroes', methods=['POST'])
def create_hero():
    req = {"name": request.form['hero name']}
    hero = SUPERHEROES.document()
    hero.set(req)
    return """
    <h1> id': %s </h1>
    <form method="get" action='/'>
        <input type="submit" size="30" value="back to the index">
    </form>
    """ % hero.id


@app.route('/read', methods=['POST'])
def read_hero():
    id = request.form['id']
    heroname = _ensure_hero(id).to_dict()
    return """
    <h1> hero is %s </h1>
    <form method="get" action='/'>
        <input type="submit" value="back to the index">
    </form>
    """ % heroname['name']


def _ensure_hero(id):
    try:
        return SUPERHEROES.document(id).get()
    except:
        flask.abort(404)


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080, debug=True)

最後にapp.yaml。runtimeにpython3.7を指定。

runtime: python37
service: heroe

GAEへのデプロイと動作の確認

GAEへのデプロイはgcloud app deployで行う。

Beginning deployment of service [heroes]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 files to Google Cloud Storage                      ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [heroes]...done.
Setting traffic split for service [heroes]...done.
Deployed service [heroes] to [https://heroes-dot-my-project.appspot.com]

ヒーローの名前を入力すると、Firestore上で割り当てられたidが返ってくる。

f:id:tkzs:20190406190242p:plain

f:id:tkzs:20190406190608p:plain

知っているidを入力すると、ヒーローの名前を知ることができる。

f:id:tkzs:20190406190900p:plain

まとめ

GAEからFirestoreを使うには、firestoreのクライアントを呼び出して使うだけで簡単。

参考

Firebase: Developing an App Engine service with Python and Cloud Firestore