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

1. 概要

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

このオプションのチュートリアルでは、Datastore サービスと通信するために、Cloud NDB から Cloud Datastore をクライアント ライブラリとして移行する方法をデベロッパーに説明します。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 をどのように使用されますか?

<ph type="x-smartling-placeholder"></ph> 最後まで読んでください 内容を読んで演習を済ませる をご覧ください。

2. 背景情報

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

Python 3 App Engine 開発者と App Engine 以外の開発者は、(Cloud NDB ではなく)Cloud Datastore を使用するよう指示されます。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 のリポジトリ(以下のリンク)をコピーします。

使用するコードにかかわらず、モジュール 2 のコードから開始します。このモジュール 3 の Codelab では各ステップを説明します。完了すると、FINISH ポイントのコードに似ています。このチュートリアルには Python 2 バージョンと Python 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 と Python 3 の両方をインストールしている場合は、Python 3 との混乱を避けるため、pip ではなく pip2 を使用することをおすすめします。

Python 3

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

$ 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)に置き換え、Flask のエントリはそのままにして requirements.txt を更新します。Python 2 と互換性のある Cloud Datastore の最終バージョンは 1.15.3 であることに注意してください。

  • 変更後(Python 2):
Flask==1.1.2
google-cloud-datastore==1.15.3
  • 変更後(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. インポート

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

  • 変更前:
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 ライブラリはより「柔軟性」が高く、「事前宣言」なしでエンティティを作成できるその構造を使用します。この更新後、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 ランタイムの相違点についてデベロッパーの皆さんに説明します。次世代ランタイムの優れた機能の一つは、サードパーティ パッケージへのアクセスが簡素化されることです。app.yaml で組み込みパッケージを指定する必要がなく、非組み込みライブラリをコピーまたはアップロードしたりする必要はありません。requirements.txt にリストされない状態で暗黙的にインストールされます。

このサンプルは非常に基本的なものであり、Cloud Datastore は Python 2 ~ 3 と互換性があるため、アプリケーション コードを 3.x に明示的に移植する必要はありません。アプリはそのまま 2.x と 3.x で動作します。つまり、必要な変更は構成にのみ行います。

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

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

requirements.txt の更新

Python 2 をサポートする Cloud Datastore の最終バージョンは 1.15.3 です。Python 3 の最新バージョン(現時点では新しい可能性があります)で requirements.txt を更新します。このチュートリアルの作成時点では、最新バージョンは 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 ディレクティブはすべて非推奨になりました。すべてのアプリはスレッドセーフと想定されており、api_version は Python 3 では使用されません。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 開発用サーバーを使用することを明示的にリクエストします。開発用サーバーを起動するコードもアプリに追加して、ポート 8080 の 0.0.0.0 インターフェースで起動されるようにする必要があります。そのためには、次の小さなセクションを main.py の下部に追加します。

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. lib フォルダに pip install が含まれていない(つまり、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(START)とモジュール 3(FINISH)のリポジトリ フォルダへのリンクを示します。また、これらのファイルには、すべての App Engine 移行のリポジトリからアクセスすることもできます。このクローンの作成や ZIP ファイルのダウンロードも可能です。

Codelab

Python 2

Python 3

モジュール 2

コード

コード

モジュール 3

コード

コード

App Engine リソース

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