Flask アプリで App Engine Memcache を使用する方法(モジュール 12)

1. 概要

サーバーレス移行ステーション シリーズの Codelab(ご自分のペースで進められる実践型のチュートリアル)と関連動画は、主にレガシー サービスからの移行を 1 つ以上行うことで、Google Cloud サーバーレスのデベロッパーがアプリケーションをモダナイズできるよう支援することを目的としています。これにより、アプリの移植性が向上し、オプションと柔軟性が高まるため、幅広い Cloud プロダクトとの統合やアクセスが可能になり、新しい言語リリースへのアップグレードが容易になります。このシリーズは、当初は初期の Cloud ユーザー、主に App Engine(標準環境)のデベロッパーを対象としていましたが、Cloud FunctionsCloud Run などの他のサーバーレス プラットフォームや、該当する場合は他のプラットフォームも対象とするほど幅広くなっています。

この Codelab では、App Engine Memcacheモジュール 1 の Codelabサンプルアプリに組み込んで使用する方法を学びます。このモジュール 12 のチュートリアルでは Memcache の使用を追加し、次のモジュール 13 で Cloud Memorystore に移行します。

GCP コンソールの

  • App Engine Memcache API/ライブラリを使用する
  • 基本的な Python 2 Flask App Engine NDB アプリにキャッシュ保存を追加する

必要なもの

アンケート

このチュートリアルをどのように使用されますか?

通読のみ 通読して演習を行う

Python のご利用経験はどの程度ありますか?

初心者 中級者 上級者

Google Cloud サービスの使用経験はどの程度ありますか?

初心者 中級者 上級者

2. 背景情報

App Engine Memcache から移行するには、モジュール 1 の Codelab で作成した既存の Flask アプリと App Engine NDB アプリに Memcache の使用状況を追加します。サンプルアプリには、ユーザーが最近アクセスした 10 件のサイトが表示されます。同じユーザーがブラウザを更新した場合、新しい Visit エンティティを継続的に作成してデータストアから最新の訪問を取得するのは最適ではないため、最新の訪問をキャッシュに保存します。

同じユーザーがページにアクセスすると、そのアクセスはキャッシュから返されます。新しいユーザーがサイトにアクセスした場合、または 1 時間が経過した場合、キャッシュはフラッシュされ、最新のエントリに置き換えられます(新しいセッションも登録されます)。この App Engine Memcache の統合を実装したので、次の Codelab(モジュール 13)で Cloud Memorystore に移行できます。

このチュートリアルでは、次の手順について説明します。

  1. セットアップ / 事前作業
  2. 構成の更新
  3. アプリケーション コードを変更する

3. セットアップ/事前作業

チュートリアルの主要部分に進む前に、まずプロジェクトをセットアップし、コードを取得してから、ベースライン アプリをデプロイします。これで、作業コードを使って作業を開始できます。

1. プロジェクトのセットアップ

モジュール 1 の Codelab を完了している場合は、同じプロジェクト(とコード)を再利用することをおすすめします。または、新しいプロジェクトを作成するか、別の既存のプロジェクトを再利用することもできます。プロジェクトにアクティブな請求先アカウントがあり、App Engine が有効になっていることを確認します。

2. ベースライン サンプルアプリを入手する

この Codelab の前提条件の 1 つは、機能するモジュール 1 のサンプルアプリを用意することです。まだお持ちでない場合は、先に進む前にいずれかのチュートリアル(上のリンク)を完了してください。すでに内容に精通している場合は、以下のモジュール 1 のコーディングから開始してください。

ご自分のコードと Google で用意したコードのいずれを使用される場合も、モジュール 1 のコードから開始します。この Codelab では、各ステップを順を追って説明します。最後に、モジュール 11 のリポジトリ フォルダ(FINISH)にあるものに似たコードが完成します。

モジュール 1 の開始ファイル(独自のまたは Google のもの)のディレクトリは次のようになります。

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. ベースライン アプリを(再)デプロイする

この段階で実施する必要がある残りの事前作業のステップ:

  1. gcloud コマンドライン ツールを学びなおす
  2. gcloud app deploy を使用してサンプルアプリを再デプロイする
  3. アプリが App Engine で問題なく実行されることを確認する

これらの手順を正常に実行し、ウェブアプリが動作することを確認したら(次のような出力が表示されます)、アプリにキャッシュの使用を追加する準備が整います。

a7a9d2b80d706a2b.png

4. 構成を更新する

標準の App Engine 構成ファイル(app.yamlrequirements.txtappengine_config.py)を変更する必要はありません。

5. アプリケーション ファイルを変更する

App Engine API のみを追加するため、外部パッケージは含まれません。つまり、構成ファイル(app.yamlrequirements.txtappengine_config.py)を更新する必要はありません。アプリケーション ファイルは main.py の 1 つだけなので、このセクションの変更はすべてそのファイルにのみ影響します。

インポート

最も重要な手順は、Memcache ライブラリ google.appengine.api.memcache をインポートすることです。最新のアクセスを 1 時間キャッシュに保存するので、1 時間の秒数を表す定数も追加しましょう。変更前後のコードは次のようになります。

変更前:

from flask import Flask, render_template, request
from google.appengine.ext import ndb

app = Flask(__name__)

変更後:

from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb

app = Flask(__name__)
HOUR = 3600

Memcache サポートによるキャッシュを追加する

最も大きな変更は、アプリケーションでのキャッシュの使用を追加することです。具体的には、最新のアクセスをキャッシュに保存し、キャッシュに保存されたアクセスが利用可能かどうかを確認し、プランに基づいてキャッシュに保存された結果をできるだけ使用するようにします。アプリが目標を達成するために行う手順は次のとおりです。

  1. 現在の訪問を設定し、visitor と呼びます。
  2. キャッシュから最新の visits を取得しようとします
  3. キャッシュが空の場合、または最新の訪問者(visits[0]['visitor'])が現在の visitor と異なる場合: この最新の訪問を保存し、最新の訪問を取得して 1 時間キャッシュに保存します。
  4. ウェブ テンプレートを介してユーザーに visits を表示する

これらの更新による変更前後の様子は次のとおりです。

変更前:

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

変更後:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    visits = memcache.get('visits')

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0]['visitor'] != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        memcache.set('visits', visits, HOUR)  # set() not add()

    return render_template('index.html', visits=visits)

変更内容を図で表すと次のようになります。

b1242503602f7bf0.png

これで、App Engine memcache の使用をモジュール 1 のサンプルアプリに追加するために必要な変更はすべて完了しました。このアプリをビルドしてデプロイし、動作を確認しましょう。

6. 概要/クリーンアップ

このセクションでは、アプリをデプロイし、意図したとおりに動作することと、出力に反映されることを確認して、この Codelab を終了します。アプリの検証が完了したら、クリーンアップの手順を実行し、次の手順を検討します。

アプリケーションをデプロイして検証する

gcloud app deploy を使用してアプリを再デプロイし、アプリが動作していることを確認します。これで、コードは FINISH(モジュール 12 フォルダ)の内容と一致するはずです。出力は、以前にデプロイしたモジュール 1 アプリと同じになります。

a7a9d2b80d706a2b.png

ユーザー エクスペリエンスを高速化しただけです。更新すると、新しいセッションが作成されたり、Datastore の取得が行われたりすることなく、キャッシュから直接結果を取得できます。

サンプル アプリケーションに App Engine memcache サービスを追加するモジュール 12 の Codelab はこれで完了です。ボーナス ステップでは、この Python 2 アプリを Python 3 に移植できます。

クリーンアップ

全般

現時点で完了した場合は、課金が発生しないように App Engine アプリを無効にすることをおすすめします。ただし、さらにテストや実験を行う場合は、App Engine プラットフォームに無料割り当てがあります。この使用量枠を超えない限り、課金されることはありません。これはコンピューティングの料金ですが、関連する App Engine サービスの料金も発生する可能性があります。詳細については、料金ページをご覧ください。この移行に他の Cloud サービスが含まれる場合は、それらのサービスは別途請求されます。どちらの場合も、該当する場合は、以下の「この Codelab に固有」のセクションをご覧ください。

完全に開示すると、App Engine などの Google Cloud サーバーレス コンピューティング プラットフォームにデプロイすると、ビルドとストレージの費用がわずかに発生しますCloud Build には独自の無料割り当てがあり、Cloud Storage にも独自の無料割り当てがあります。そのイメージの保存には、その割り当ての一部が使用されます。ただし、お住まいの地域でこのような無料枠が提供されていない可能性もあります。そのため、保存容量の使用状況を把握して、費用を最小限に抑えるようにしてください。確認する必要がある特定の Cloud Storage の「フォルダ」は次のとおりです。

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • 上記のストレージ リンクは、PROJECT_ID と *LOC*ーションによって異なります。たとえば、アプリが米国でホストされている場合は「us」になります。

ただし、このアプリケーションや関連する移行 Codelab を続行せず、すべてを完全に削除する場合は、プロジェクトをシャットダウンしてください。

この Codelab に固有

以下のサービスは、この Codelab 固有のものです。詳細については、各プロダクトのドキュメントをご覧ください。

  • App Engine Memcache サービスには 2 つの異なるフレーバーがあり、それぞれに独自の料金体系があります。そのため、課金に関連する使用状況を追跡する必要があります。
  • App Engine Datastore サービスは Cloud Datastore(Datastore モードの Cloud Firestore)によって提供されます。これにも無料枠があります。詳細については、料金ページをご覧ください。

次のステップ

次に検討すべき論理移行については、モジュール 13 で説明します。ここでは、App Engine memcache サービスから Cloud Memorystore に移行する方法をデベロッパーに示します。これらの移行はすべてオプションであり、アプリケーションのモダナイズのためにさまざまな手順を実行したいユーザーが利用できます。Cloud Memorystore サービスは、次の理由から App Engine の memcache の大幅なアップグレードです。

  • Cloud Memorystore はサーバーレスではありません。つまり、キャッシュ用にサーバーを割り当てる必要があります。Cloud Memorystore にも無料枠はありません。これらの要因は、費用に大きな影響を与える可能性があります。
  • Cloud Memorystore は、RedisMemcached という 2 つの異なる基盤となるストレージ メカニズム(キャッシュ エンジン)をサポートしています。
  • Cloud Memorystore(for Redis)には、App Engine Memcache よりもはるかに豊富で詳細な機能セットがあります。
  • Cloud Memorystore を使用するには、Cloud Memorystore サーバーを設定して Google Cloud VPC ネットワークに追加し、App Engine アプリがそのネットワークを使用して Memorystore サーバーと通信するようにする必要があります。

Cloud Memorystore のすべての機能が必要ない場合や、費用への影響が気になる場合は、App Engine Memcache を引き続きご利用いただけます。

モジュール 13 以降には、Cloud NDB、Cloud Datastore、Cloud Tasks など、他の移行の可能性が多数あります。Cloud Run と Cloud Functions へのプロダクト間の移行もあります。これらはすべて 移行リポジトリにあります。

次のステップとして、Python 3 への移植も考えられます。これは、次のセクションでオプションのステップとして説明します。

7. ボーナス: Python 3 への移行

概要

このセクションでは、上記で完了したモジュール 12 アプリケーションを Python 3 に移行するオプションのボーナス コンテンツについて説明します。まず構成から始め、次にアプリケーションに進みます。

app.yaml を簡素化する

Python 3 ランタイムの利点の 1 つは、app.yaml を大幅に簡素化できることです。

変更前:

モジュール 12 の最後に app.yaml に含まれる内容は次のとおりです。

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

Python 3 ランタイムではウェブ フレームワークが独自のルーティングを行う必要があるため、app.yaml のすべてのルート ハンドラを auto に変更する必要があります。静的ファイルが提供されていない場合は、handlers: セクション全体を削除できます。また、threadsafeapi_version の両方が非推奨になりました

変更後:

前述の必要な変更を加えた Python 3 の代替 app.yaml は次のとおりです。

runtime: python39
app_engine_apis: true

説明が必要な行は app_engine_apis: true だけです。2021 年に第 2 世代ランタイムで以前の App Engine サービスが利用可能になったとき、Python 3 などの一部のランタイムでは、ndbtaskqueuememcache などの API にアクセスするために追加のブートストラップが必要になります。構成のこの行は、その目的を果たします。

requirements.txt を更新する

requirements.txt では、元の API の別のブートストラップが必要です。新しい App Engine SDK へのアクセスを含める必要があります。

変更前:

モジュール 12 の最後に app.yaml に含まれる内容は次のとおりです。

flask

変更後:

App Engine Python SDK を追加するだけで、次のようになります。

flask
appengine-python-standard

appengine_config.py と lib を削除する

次世代の App Engine ランタイムでは、サードパーティ パッケージの使用方法が変更されます。

  • 組み込みライブラリは、Google によって審査され、App Engine サーバーで利用可能になったライブラリです。これは、デベロッパーがクラウドにデプロイできない C/C++ コードが含まれているためです。これらのライブラリは、第 2 世代のランタイムでは利用できなくなりました。
  • 第 2 世代ランタイムでは、組み込みでないライブラリのコピー(「ベンダーリング」または「セルフ バンドル」とも呼ばれます)は不要になりました。代わりに、requirements.txt にリストする必要があります。ビルドシステムは、デプロイ時に自動的にインストールします。

サードパーティ パッケージ管理の変更により、appengine_config.py ファイルも lib フォルダも不要になったため、削除します。第 2 世代のランタイムでは、App Engine は requirements.txt にリストされているサードパーティ パッケージを自動的にインストールします。要約:

  1. セルフバンドルまたはコピーされたサードパーティ ライブラリがない。requirements.txt に記載されている
  2. pip installlib フォルダにない。つまり、lib フォルダ期間がない
  3. app.yaml に組み込みのサードパーティ ライブラリが記載されていない(そのため libraries セクションがない)。requirements.txt に記載する
  4. アプリから参照するサードパーティ ライブラリがない場合は、appengine_config.py ファイルもありません。

必要なサードパーティ ライブラリをすべて requirements.txt に記載することが、デベロッパーの唯一の要件です。

App Engine SDK を使用するようにアプリケーションを更新する

前述のように、Python 3 アプリが App Engine バンドル サービスにアクセスするには、いくつかの変更が必要です。

  1. App Engine SDK をバンドル(requirements.txt 内)
  2. App Engine SDK を有効にする(app.yaml 内)
  3. WSGI オブジェクトをラップする(main.py 内)

最初のペアは上記で完了しているため、最後の要件は main.py を更新することです。

変更前:

モジュール 12 の最後に作成した Python 2 の main.py を以下に示します。

from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb

app = Flask(__name__)
HOUR = 3600

変更後:

Python 3 ポートの場合、SDK をインポートして Flask アプリ オブジェクトを SDK ラッパーでラップします。結果は次のようになります。

from flask import Flask, render_template, request
from google.appengine.api import memcache, wrap_wsgi_app
from google.appengine.ext import ndb

app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600

デベロッパーは、2.x から 3.x に移植する際に、バンドル サービスにアクセスするために、Python アプリにこれらの変更を加える必要があります。Flask を使用していない場合は、ドキュメントの Django と Pyramid のサンプルをご覧ください。Python 2 コードがウェブアプリでない場合は、Python 3 に移植する際に SDK パッケージを含めるだけで十分です。アプリケーション コードは元々 Python 2 と 3 で動作するように作成されているため、互換性に関する追加の変更は必要ありません。

アプリケーションのデプロイ

上記の変更が完了したら、更新されたサンプルアプリをデプロイできます(同じ GCP プロジェクト内の元の Python 2 バージョンに Python 3 バージョンのアプリをデプロイしても問題はありません)。アプリの動作は変わりません。更新したアプリを Google のアプリと比較する必要がある場合は、移行リポジトリの Module 12b フォルダをご覧ください。Python 3 などの最新のランタイムでの App Engine バンドル サービスのサポートの詳細については、機能のリリースに関するお知らせModule 17 Codelab をご覧ください。

モジュール 12 のボーナス ステップを完了しました。Python 3 ランタイム用の構成ファイルの準備に関するドキュメントもご覧ください。次のステップとクリーンアップについては、上記の「概要/クリーンアップ」セクションをご覧ください。

8. 参考情報

以下に、デベロッパーがこの移行モジュールまたは関連する移行モジュールや関連プロダクトをさらに詳しく調べるための追加リソースを示します。このコンテンツに関するフィードバックを送信できる場所、コードへのリンク、役立つ可能性のあるさまざまなドキュメントなどが含まれます。

Codelab に関する問題/フィードバック

この Codelab に問題が見つかった場合は、提出する前にまず問題を検索してください。新しい問題の検索と登録を行うためのリンク:

移行に関するリソース

モジュール 2(開始)とモジュール 12(終了)のリポジトリ フォルダへのリンクを以下の表に示します。これらのフォルダには、すべての App Engine Codelab 移行のリポジトリからアクセスすることもでき、クローンを作成する、または ZIP ファイルをダウンロードすることができます。

Codelab

Python 2

Python 3

モジュール 1

コード

コード(このチュートリアルでは取り上げません)

モジュール 12(このコードラボ)

コード

コード

オンライン リファレンス

このチュートリアルに関連する可能性のあるオンライン リソースは次のとおりです。

App Engine

Cloud Memorystore と Cloud Datastore

その他のクラウド情報

動画

ライセンス

この作業はクリエイティブ・コモンズの表示 2.0 汎用ライセンスにより使用許諾されています。