モジュール 3: Google Cloud NDB から Cloud Datastore への移行

1. 概要

この一連の Codelab(ご自分のペースで進められる実践型のチュートリアル)は、一連の移行についてガイダンスを実施することにより、Google App Engine(標準環境)のデベロッパーがアプリをモダナイズできるよう支援することを目的としています。最も大きなステップは、元のランタイム バンドル サービスから移行することです。理由は、次世代のランタイムが柔軟性に富み、ユーザーにさまざまなサービス オプションが提供されるためです。新しい世代のランタイムに移行することで、Google Cloud プロダクトとの統合が容易になり、幅広いサポート対象サービスを使用し、現在の言語リリースをサポートできるようになります。

このチュートリアルでは、Cloud NDB から Cloud Datastore に移行して、Datastore サービスと通信するクライアント ライブラリとして使用する方法について説明します。NDB を好むデベロッパーは、NDB が Python 3 と互換性があるため、NDB を使い続けることができます。そのため、この移行は任意です。この移行は、Cloud Datastore をすでに使用している他のアプリと一貫性のあるコードベースと共有ライブラリを構築したいユーザーのみを対象としています。これについては、「背景」セクションで説明します。

方法を学ぶ対象

  • Cloud NDB を使用する(慣れていない場合)
  • Cloud NDB から Cloud Datastore に移行する
  • Python 3 へのアプリの移行をさらに進める

必要なもの

  • 有効な GCP 請求先アカウントを持つ Google Cloud Platform プロジェクト
  • 基本的な Python スキル
  • 基本的な Linux コマンドに関する実践的な知識
  • App Engine アプリの開発とデプロイに関する基本的な知識
  • 正常に機能するモジュール 2 App Engine 2.x または 3.x アプリ。

アンケート

この Codelab をどのように使用されますか?

全体を通して読むだけ 内容を読んで演習をやり遂げる

2. 背景情報

Cloud NDB は、長年 App Engine を使用してきたデベロッパーにとって優れた Datastore ソリューションであり、Python 3 への移行にも役立ちますが、App Engine デベロッパーが Datastore にアクセスできる唯一の方法ではありません。App Engine の Datastore が 2013 年に独自のプロダクトになったとき、すべてのユーザーが Datastore を使用できるように、新しい クライアント ライブラリである Google Cloud Datastore が作成されました。

Python 3 App Engine と App Engine 以外のデベロッパーは、Cloud Datastore(Cloud NDB ではない)を使用するように指示されます。Python 2 App Engine デベロッパーは、ndb から Cloud NDB に移行し、そこから Python 3 に移植することをおすすめしますが、Cloud Datastore に移行することもできます。これは、前述のような Cloud Datastore を使用するコードをすでに持っており、すべてのアプリケーションで共有ライブラリを作成したいデベロッパーにとって特に論理的な決定です。コードの再利用とコードの一貫性はベスト プラクティスであり、どちらもメンテナンス コストの削減に貢献します。

Cloud NDB から Cloud Datastore への移行

  • デベロッパーは Datastore アクセス用の単一のコードベースに集中できる
  • Cloud NDB を使用するコードと Cloud Datastore を使用するコードのメンテナンスを回避する
  • コードベースの整合性が高まり、コードの再利用性が向上する
  • 共通ライブラリや共有ライブラリを使用できるため、全体的なメンテナンス コストの削減に貢献します。

この移行では、次の主なステップに着目します。

  1. セットアップ / 事前作業
  2. Cloud NDB を Cloud Datastore クライアント ライブラリに置き換える
  3. アプリケーションの更新

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

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

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

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

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

前提条件の 1 つは、機能するモジュール 2 のサンプルアプリを用意することです。このチュートリアルを完了した場合は、そのソリューションを使用します。今すぐ完了することもできます(上記のリンク)。スキップする場合は、モジュール 2 のリポジトリをコピーしてください(下記のリンク)。

ご自分のコードと Google で用意したコードのいずれを使用される場合も、モジュール 2 のコードから開始します。このモジュール 3 の Codelab では、各ステップについて順を追って説明します。完了すると、終了ポイントのコードが次のように表示されます。このチュートリアルには Python 2 と 3 のバージョンがあります。以下の正しいコード リポジトリを取得してください。

Python 2

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

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

モジュール 2 のチュートリアルを完了している場合は、Flask とその依存関係を含む lib フォルダもあります。lib フォルダがない場合は、次のステップでこのベースライン アプリをデプロイできるように、pip install -t lib -r requirements.txt コマンドを使用して作成します。Python 2 と 3 の両方がインストールされている場合は、Python 3 との混同を避けるため、pip ではなく pip2 を使用することをおすすめします。

Python 3

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

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

Python 3 では libappengine_config.py も使用されません。

3. モジュール 2 アプリを(再)デプロイする

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

  1. gcloud コマンドライン ツールについて復習します(必要な場合)。
  2. モジュール 1 コードを App Engine に(再)デプロイします(必要な場合)。

各手順を正常に実行して、動作していることを確認したら、このチュートリアルに進み、構成ファイルを使用して作業を開始します。

4. Cloud NDB を Cloud Datastore クライアント ライブラリに置き換える

構成の変更は、requirements.txt ファイルでのマイナー パッケージの入れ替えのみです。

1. requirements.txt の更新

モジュール 2 を完了すると、requirements.txt ファイルは次のようになります。

  • 以前(Python 2 と 3):
Flask==1.1.2
google-cloud-ndb==1.7.1

Cloud NDB ライブラリ(google-cloud-ndb)を Cloud Datastore ライブラリ(google-cloud-datastore)の最新バージョンに置き換えて requirements.txt を更新します。Flask のエントリはそのまま残します。Python 2 と互換性のある Cloud Datastore の最終バージョンは 1.15.3 であることに注意してください。

  • 変更後(Python 2):
Flask==1.1.2
google-cloud-datastore==1.15.3
  • AFTER(Python 3):
Flask==1.1.2
google-cloud-datastore==2.1.0

リポジトリは、このチュートリアルよりも定期的にメンテナンスされているため、requirements.txt ファイルには新しいバージョンが反映されている可能性があります。各ライブラリの最新バージョンを使用することをおすすめしますが、適切に機能しない場合は、古いリリースにロールバックできます。上記のバージョン番号は、この Codelab が最後に更新された時点での最新バージョンです。

2. その他の構成ファイル

他の構成ファイル(app.yamlappengine_config.py)は、前の移行ステップから変更しないままにします。

  • app.yaml は(引き続き)サードパーティ バンドル パッケージ grpciosetuptools を参照する必要があります。
  • appengine_config.py は、pkg_resourcesgoogle.appengine.ext.vendorlib のサードパーティ リソースに(引き続き)ポイントする必要があります。

次に、アプリケーション ファイルに移ります。

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

template/index.html に変更はありませんが、main.py にはいくつかの更新があります。

1. インポート

インポート セクションの開始コードは次のようになります。

  • 変更前:
from flask import Flask, render_template, request
from google.cloud import ndb

google.cloud.ndb インポートを Cloud Datastore のインポート(google.cloud.datastore)に置き換えます。Datastore クライアント ライブラリはエンティティのタイムスタンプ フィールドの自動作成をサポートしていないため、標準ライブラリ datetime モジュールもインポートして手動で作成します。慣例により、標準ライブラリのインポートはサードパーティ パッケージのインポートの上に配置します。これらの変更が完了すると、次のようになります。

  • 変更後:
from datetime import datetime
from flask import Flask, render_template, request
from google.cloud import datastore

2. 初期化とデータモデル

Flask を初期化した後、モジュール 2 のサンプルアプリで NDB データモデル クラスとそのフィールドを作成するコードは次のようになります。

  • 変更前:
app = Flask(__name__)
ds_client = ndb.Client()

class Visit(ndb.Model):
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)

Cloud Datastore ライブラリにはこのようなクラスがないため、Visit クラス宣言を削除します。Datastore と通信するにはクライアントが必要なため、ndb.Client()datastore.Client() に変更します。Datastore ライブラリはより柔軟性が高く、NDB のように構造を事前に宣言しなくてもエンティティを作成できます。この更新後、main.py のこの部分は次のようになります。

  • 変更後:
app = Flask(__name__)
ds_client = datastore.Client()

3. Datastore へのアクセス

Cloud Datastore に移行するには、Datastore エンティティの作成、保存、クエリの方法(ユーザーレベル)を変更する必要があります。アプリケーションの場合、この移行の難易度は Datastore コードの複雑さによって異なります。サンプルアプリでは、更新をできるだけ簡単に行えるようにしました。開始コードは次のとおりです。

  • 変更前:
def store_visit(remote_addr, user_agent):
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    with ds_client.context():
        return (v.to_dict() for v in Visit.query().order(
                -Visit.timestamp).fetch_page(limit)[0])

Cloud Datastore を使用して、汎用エンティティを作成し、エンティティ内のグループ化されたオブジェクトを「キー」で識別します。Key-Value ペアの JSON オブジェクト(Python dict)を使用してデータレコードを作成し、予期される put() を使用して Datastore に書き込みます。クエリは似ていますが、Datastore の方が簡単です。同等の Datastore コードの違いは次のとおりです。

  • 変更後:
def store_visit(remote_addr, user_agent):
    entity = datastore.Entity(key=ds_client.key('Visit'))
    entity.update({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })
    ds_client.put(entity)

def fetch_visits(limit):
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    return query.fetch(limit=limit)

上記のように store_visit()fetch_visits() の関数本体を更新し、シグネチャを以前のバージョンと同じにします。メイン ハンドラ root() に変更はありません。これらの変更が完了すると、アプリは Cloud Datastore を使用するように設定され、テストの準備が整います。

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

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

gcloud app deploy を使用してアプリを再デプロイし、アプリが動作していることを確認します。これで、コードはモジュール 3 リポジトリ フォルダの内容と一致するはずです。

先行するいずれの Codelab の取り組みも行わずにこのシリーズに進んだ場合、アプリ自体は変更されません。このアプリは、メインのウェブページ(/)へのすべての訪問を登録します。一定回数以上サイトにアクセスすると、ウェブページは次のように表示されます。

visitme アプリ

このモジュール 3 の Codelab はこれで完了です。Cloud NDB と Cloud Datastore の両方のクライアント ライブラリを使用して Datastore にアクセスできることがわかりました。後者に移行することで、共有ライブラリ、共通コード、コードの再利用による一貫性の維持、メンテナンス コストの削減といったメリットが得られます。

オプション: クリーンアップ

次の移行 Codelab に進む準備が整うまで、課金されるのを回避するためのクリーンアップを行うにはどうすればよいでしょうか。既存のデベロッパーの方は、App Engine の料金に関する情報に関する最新の内容をすでにご存じと思われます。

オプション: アプリを無効にする

次のチュートリアルに進む準備がまだ完了していない場合は、アプリを無効にすることで課金されないようにできます。次の Codelab に進む準備ができた時点で、再度有効にできます。アプリが無効になっている間、料金のかかるトラフィックは発生しません。ただし、もう 1 つの課金対象は、Datastore の使用量です。無料割り当て量を超過した場合は課金が発生するため、上限を超えないよう削除してください。

ただし、移行を続けず、すべてを完全に削除する場合は、プロジェクトをシャットダウンしてください。

次のステップ

次の移行モジュールをご覧ください。

  • モジュール 3 ボーナス: ボーナス セクションに進み、Python 3 と次世代の App Engine ランタイムへの移行方法をご確認ください。
  • モジュール 7: App Engine の push タスクキュー([push] タスクキューを使用する場合に必要)
    • App Engine taskqueue プッシュタスクをモジュール 1 アプリに追加する
    • モジュール 8 で Cloud Tasks に移行するユーザーの準備を行う
  • モジュール 4: Docker を使用して Cloud Run に移行する
    • Docker を使用して、Cloud Run で実行できるようにアプリをコンテナ化します。
    • Python 2 を引き続き使用できるようにする
  • モジュール 5: Cloud Buildpacks を使用して Cloud Run に移行する
    • Cloud Build を使用して Cloud Run で実行するようにアプリをコンテナ化します。
    • Docker、コンテナ、または Dockerfile についての知識は必要ありません
    • アプリを Python 3 に移行済みであることが必要です
  • モジュール 6: Cloud Firestore への移行。
    • Cloud Firestore に移行して Firebase の機能にアクセスします。
    • Cloud Firestore は Python 2 をサポートしていますが、この Codelab は Python 3 でのみ利用できます。

7. ボーナス: Python 3 に移行する

最新の App Engine のランタイムと機能にアクセスするには、Python 3 に移行することをおすすめします。サンプルアプリでは、Datastore は使用した唯一の組み込みサービスでした。ndb から Cloud NDB に移行したため、App Engine の Python 3 ランタイムに移植できるようになりました。

概要

Python 3 への移植は Google Cloud チュートリアルでは取り上げませんが、Codelab のこの部分では、Python 3 App Engine ランタイムの相違点についてデベロッパーの皆さんに説明します。次世代ランタイムの優れた機能の 1 つは、サードパーティ パッケージへのアクセスが簡素化されていることです。app.yaml で組み込みパッケージを指定する必要はありません。また、組み込みでないライブラリをコピーまたはアップロードする必要もありません。これらは、requirements.txt のリストに記載された中から暗黙的にインストールされます。

サンプルは非常に基本的なものであり、Cloud Datastore は Python 2 ~ 3 と互換性があるため、アプリケーション コードの 3.x への明示的な移植は不要です。変更を加えられていないアプリが 2.x と 3.x で実行されている場合は、必要な変更のみが構成に含まれていることを示しています。

  1. app.yaml を Python 3 を参照するように簡略化し、バンドルされたサードパーティのライブラリへの参照を削除します。
  2. 不要になった時点で appengine_config.py フォルダと lib フォルダを削除します。

main.py アプリケーション ファイルと templates/index.html アプリケーション ファイルは変更されません。

requirements.txt の更新

Python 2 をサポートする Cloud Datastore の最終バージョンは 1.15.3 です。requirements.txt を Python 3 の最新バージョンに更新します(現時点では新しいバージョンになっている可能性があります)。このチュートリアルの作成時点での最新バージョンは 2.1.0 でした。この行を次のように編集します(最新バージョンが異なる場合は、そのバージョンに置き換えます)。

google-cloud-datastore==2.1.0

app.yaml を簡略化する

変更前:

このサンプルアプリに対して実際に行った唯一の変更は、app.yaml を大幅に短縮したことです。リマインダーとして、モジュール 3 の最後に app.yaml で行った操作の内容を以下に記載します。

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

変更後:

Python 3 では、threadsafeapi_versionlibraries ディレクティブはすべて非推奨になりました。すべてのアプリがスレッドセーフであると想定され、Python 3 では api_version は使用されません。App Engine サービスにサードパーティの組み込みパッケージがプリインストールされなくなったため、libraries も非推奨になりました。今回の変更について詳しくは、app.yaml の変更に関するドキュメントをご覧ください。そのため、app.yaml から 3 つすべてを削除し、サポートされている Python 3 バージョンに更新する必要があります(下記を参照)。

省略可: handlers ディレクティブの使用

また、App Engine アプリケーションにトラフィックを転送する handlers ディレクティブも非推奨になりました。次世代ランタイムではウェブ フレームワークがアプリのルーティングを管理することを想定しているため、すべての「ハンドラ スクリプト」を「auto」に変更する必要があります。上記の変更を組み合わせると、次の app.yaml になります。

runtime: python38

handlers:
- url: /.*
  script: auto

script: auto の詳細については、app.yaml リファレンス ページをご覧ください。

handlers ディレクティブの削除

handlers はサポートが終了しているため、app.yaml の 1 行を残してセクション全体を削除することもできます。

runtime: python38

これによってデフォルトでは、すべてのアプリケーションで使用可能な Gunicorn WSGI ウェブサーバーが起動されます。gunicorn に精通されている場合は、このコマンドがベアボーン app.yaml で最初に起動すると実行されます。

gunicorn main:app --workers 2 -c /config/gunicorn.py

省略可: entrypoint ディレクティブの使用

ただし、特定の起動コマンドをアプリケーションが必要とする場合は、entrypoint ディレクティブで指定でき、app.yaml は次のようになります。

runtime: python38
entrypoint: python main.py

この例では、gunicorn ではなく Flask 開発用サーバーを使用するように明示的にリクエストしています。開発環境サーバーを起動するコードもアプリに追加する必要があります。この小さなセクションを main.py の下部に追加することで、ポート 8080 の 0.0.0.0 インターフェースで起動できます。

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

entrypoint の詳細については、app.yaml リファレンス ページをご覧ください。その他の例とベスト プラクティスについては、App Engine スタンダード環境のスタートアップ ドキュメントApp Engine フレキシブル環境のスタートアップ ドキュメントをご覧ください。

appengine_config.pylib を削除します。

appengine_config.py ファイルと lib フォルダを削除します。Python 3 に移行する際、App Engine は requirements.txt に記載されているパッケージを取得してインストールします。

appengine_config.py 構成ファイルは、サードパーティのライブラリまたはパッケージを、ご自分でコピーしたか、App Engine サーバーですでに使用可能なもの(組み込み)を使用しているかを認識するために使用されます。Python 3 に移行する際の、大きな変更の概要は次のとおりです。

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

必要であるのは、すべてのサードパーティ ライブラリを requirements.txt に記載することのみです。

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

再デプロイしてアプリが動作するようにします。ご自分のソリューションが、モジュール 3 のサンプル Python 3 コードにどの程度類似したものであるかを確認することもできます。Python 2 との相違を可視化するには、コードを Python 2 バージョンと比較します。

モジュール 3 のボーナス ステップを完了しました。Python 3 ランタイム用の構成ファイルの準備に関するドキュメントをご覧ください。最後に、上記の概要で次のステップとクリーンアップを確認します。

ご自分のアプリケーションを準備する

アプリケーションを移行する際は、main.py とその他のアプリケーション ファイルを 3.x に移植する必要があります。そのため、可能な限り 2.x アプリケーションを「前方互換性」を有するものにすることをおすすめします。

これを実現するうえで有用なオンライン リソースは多数ありますが、重要なヒントをいくつか紹介します。

  1. すべてのアプリケーションの依存関係が 3.x と完全互換であることを確認します。
  2. アプリケーションが 2.6 以上で実行されるようにします(推奨は 2.7)。
  3. アプリケーションがテストスイート全体(および 80% 以上のカバレッジ)に合格していることを確認します。
  4. six、Future、Modernize などの互換性ライブラリを使用します。
  5. 下位互換性のない主な 2.x と 3.x の相違について認識します。
  6. I/O を行うと、Unicode とバイト文字列の非互換性が発生する可能性があります。

サンプルアプリは、これらすべてを念頭に置いて設計されました。そのため、アプリは 2.x と 3.x で初期設定の状態で実行できます。これにより、次世代プラットフォームを使用するために変更が必要な箇所を示すことにフォーカスできます。

8. 参考情報

App Engine 移行モジュールの Codelab に関する問題 / フィードバック

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

移行に関するリソース

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

Codelab

Python 2

Python 3

モジュール 2

コード

コード

モジュール 3

コード

コード

App Engine リソース

この特定の移行に関する追加リソースは以下のとおりです。