App Engine Memcache から Cloud Memorystore への移行(モジュール 13)

1. 概要

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

この Codelab の目的は、Python 2 App Engine デベロッパーが App Engine Memcache から Cloud MemorystoreRedis 用)に移行する方法を示すことです。App Engine ndb から Cloud NDB への暗黙的な移行もありますが、これは主にモジュール 2 の Codelab で説明しています。詳細な手順については、こちらをご覧ください。

GCP コンソールの

  • Cloud Memorystore インスタンスを設定する(Cloud コンソールまたは gcloud ツールから)
  • Cloud サーバーレス VPC アクセス コネクタを設定する(Cloud Console または gcloud ツールを使用)
  • App Engine Memcache から Cloud Memorystore に移行する
  • サンプルアプリで Cloud Memorystore を使用してキャッシュ保存を実装する
  • App Engine ndb から Cloud NDB への移行

必要なもの

アンケート

このチュートリアルの利用方法をお選びください。

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

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

初心者 中級者 上級者

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

初心者 中級者 上級者

2. 背景情報

この Codelab では、サンプルアプリを App Engine Memcache(および NDB)から Cloud Memorystore(および Cloud NDB)に移行する方法について説明します。このプロセスでは、App Engine バンドル サービスへの依存関係を置き換えて、アプリの移植性を高めます。App Engine を使い続けるか、前述の代替案への移行を検討できます。

この移行は、このシリーズの他の移行よりも多くの労力を必要とします。App Engine Memcache の推奨代替サービスは、フルマネージド型のクラウドベースのキャッシュ サービスである Cloud Memorystore です。Memorystore は、一般的なオープンソース キャッシュ エンジンである RedisMemcached をサポートしています。この移行モジュールは、Cloud Memorystore for Redis を使用します。詳細については、Memorystore と Redis の概要をご覧ください。

Memorystore には実行中のサーバーが必要なため、Cloud VPC も必要です。具体的には、App Engine アプリがプライベート IP アドレスを介して Memorystore インスタンスに接続できるように、サーバーレス VPC アクセス コネクタを作成する必要があります。この演習を完了すると、アプリの動作は以前と変わりませんが、Cloud Memorystore がキャッシュ サービスになり、App Engine の Memcache サービスが置き換えられます。

このチュートリアルは、Python 2 のモジュール 12 サンプルアプリから始まり、Python 3 への追加のマイナー アップグレード(オプション)が続きます。Python 3 App Engine SDK を介して Python 3 から App Engine バンドル サービスにアクセスする方法をすでに理解している場合は、代わりに Python 3 版のモジュール 12 サンプルアプリから始めることができます。これを行うには、Memorystore は App Engine バンドル サービスではないため、SDK の使用を削除する必要があります。Python 3 App Engine SDK の使用方法については、このチュートリアルの範囲外です。

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

  1. セットアップ/事前作業
  2. キャッシュ サービスを設定する
  3. 設定ファイルを更新する
  4. メイン アプリケーションを更新する

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

Cloud プロジェクトを準備する

モジュール 12 Codelab で使用したプロジェクトと同じプロジェクトを再利用することをおすすめします。または、新しいプロジェクトを作成するか、別の既存のプロジェクトを再利用することもできます。このシリーズの各 Codelab には、「START」(開始用のベースライン コード)と「FINISH」(移行後のアプリ)があります。問題が発生した場合に、ご自身のソリューションと Google のソリューションを比較できるように、FINISH コードが提供されています。何か問題が発生した場合は、いつでも START にロールバックできます。これらのチェックポイントは、移行の実行方法を確実に習得できるように設計されています。

使用する Cloud プロジェクトには、有効な請求先アカウントがあることを確認してください。また、App Engine が有効になっていることを確認してください。これらのチュートリアルを行う際の一般的な費用の影響を確認し、理解しておいてください。ただし、このシリーズの他の Codelab とは異なり、この Codelab では無料枠のない Cloud リソースを使用するため、演習を完了するには費用が発生します。より具体的な費用情報と、使用量を削減するための推奨事項が提供されます。最後に、請求額を最小限に抑えるためにリソースを解放する手順も記載されています。

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

この Codelab では、ベースラインのモジュール 12 のコードから移行を段階的に進めていきます。完了すると、FINISH フォルダのいずれかのコードに酷似した、動作するモジュール 13 アプリが完成します。リソースは次のとおりです。

START フォルダには次のファイルが含まれている必要があります。

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

Python 2 バージョンから始める場合は、appengine_config.py ファイルもあります。モジュール 12 の Codelab を完了している場合は、lib フォルダもある可能性があります。

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

残りの事前作業のステップ:

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

Python 2 ユーザーは、次のコマンドを使用して lib フォルダを削除して再インストールする必要があります。

rm -rf ./lib; pip install -t lib -r requirements.txt                

これで、すべてのユーザー(Python 2 と 3 のユーザー)が次のコマンドを使用してコードを App Engine にアップロードできるようになりました。

gcloud app deploy                

デプロイが完了したら、アプリの見た目と機能がモジュール 12 のアプリ(訪問を追跡し、同じユーザーに対して 1 時間キャッシュに保存するウェブアプリ)と同じであることを確認します。

dfe56a02ae59ddd8.png

最近のアクセスはキャッシュに保存されているため、ページの更新は比較的速く読み込まれます。

4. キャッシュ サービスを設定する

Cloud Memorystore はサーバーレスではありません。インスタンスが必要です。この場合は Redis を実行しているインスタンスです。Memcache とは異なり、Memorystore はスタンドアロンの Cloud プロダクトであり、無料枠ありません。続行する前に、Memorystore for Redis の料金情報を必ずご確認ください。この演習の費用を最小限に抑えるため、運用に必要な最小限のリソース(ベーシック サービスティアと 1 GB の容量)をおすすめします。

Memorystore インスタンスは App Engine アプリ(インスタンス)とは異なるネットワークにあるため、App Engine が Memorystore リソースにアクセスできるように、サーバーレス VPC アクセス コネクタを作成する必要があります。VPC の費用を最小限に抑えるには、インスタンス タイプ(f1-micro)と、リクエストするインスタンスの最小数(最小 2 個最大 3 個を推奨)を選択します。VPC の料金情報ページもご覧ください。

必要なリソースの作成手順を説明する際に、費用の削減に関する推奨事項を繰り返し説明します。また、Cloud コンソールで Memorystore と VPC リソースを作成すると、各プロダクトの料金計算ツールが右上隅に表示され、月額費用の見積もりを確認できます(下の図を参照)。オプションを変更すると、これらの値は自動的に調整されます。次のような結果が表示されます。

7eb35ebf7248c010.png

どちらのリソースも必須です。どちらを先に作成してもかまいません。Memorystore インスタンスを先に作成した場合、VPC コネクタがないと App Engine アプリからインスタンスにアクセスできません。同様に、最初に VPC コネクタを作成した場合、App Engine アプリが通信する VPC ネットワークには何もありません。このチュートリアルでは、まず Memorystore インスタンスを作成してから、VPC コネクタを作成します。

両方のリソースがオンラインになったら、関連情報を app.yaml に追加して、アプリがキャッシュにアクセスできるようにします。公式ドキュメントの Python 2 または Python 3 のガイドも参照してください。Cloud NDB 移行ページのデータ キャッシュ保存ガイド(Python 2 または Python 3)も参考になります。

Cloud Memorystore インスタンスを作成する

Cloud Memorystore には無料枠がないため、Codelab を完了するために必要な最小限のリソースを割り当てることをおすすめします。次の設定を使用すると、費用を最小限に抑えることができます。

  • 最も低いサービスティアである [Basic] を選択します(コンソールのデフォルト: [Standard]、gcloud のデフォルト: [Basic])。
  • 最小のストレージ容量(1 GB)を選択します(コンソールのデフォルト: 16 GB、gcloud のデフォルト: 1 GB)。
  • 通常、どのソフトウェアでも最新バージョンは最も多くのリソースを必要としますが、古いバージョンを選択することもおすすめできません。現在、2 番目に新しいバージョンは Redis バージョン 5.0 です(コンソールのデフォルト: 6.x)。

次のセクションでは、これらの設定を念頭に置いて、Cloud Console からインスタンスを作成する手順について説明します。コマンドラインから実行する場合は、次のセクションに進んでください。

Cloud Console から

Cloud Console で Cloud Memorystore ページに移動します(お支払い情報の入力を求められることがあります)。Memorystore をまだ有効にしていない場合は、有効にするように求められます。

68318997e3105db6.png

有効にすると(場合によっては課金も)、Memorystore ダッシュボードが表示されます。ここでは、プロジェクトで作成されたすべてのインスタンスを確認できます。下のプロジェクトには行がないため、「表示する行がありません」と表示されています。Memorystore インスタンスを作成するには、上部の [インスタンスを作成] をクリックします。

63547aa575838a36.png

このページには、Memorystore インスタンスを作成するために必要な設定を入力するフォームがあります。

b77d927287fdf4c7.png

このチュートリアルとそのサンプルアプリの費用を抑えるには、前述の推奨事項に従ってください。選択が完了したら、[作成] をクリックします。作成プロセスには数分かかります。完了したら、インスタンスの IP アドレスポート番号をコピーして app.yaml に追加します。

コマンドラインから

Cloud Console から Memorystore インスタンスを作成すると、視覚的にわかりやすいですが、コマンドラインを好むユーザーもいます。先に進む前に、gcloudインストールされ、初期化されていることを確認してください。

Cloud Console と同様に、Cloud Memorystore for Redis を有効にする必要があります。次の例のように、gcloud services enable redis.googleapis.com コマンドを発行し、完了するまで待ちます。

$ gcloud services enable redis.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

サービスがすでに有効になっている場合、コマンドを(再度)実行しても(負の)副作用はありません。サービスが有効になったので、Memorystore インスタンスを作成しましょう。コマンドは次のようになります。

gcloud redis instances create NAME --redis-version VERSION \
    --region REGION --project PROJECT_ID

Memorystore インスタンスの名前を選択します。このラボでは、「demo-ms」という名前と「my-project」というプロジェクト ID を使用します。このサンプルアプリのリージョンは us-central1us-central と同じ)ですが、レイテンシが気になる場合は、より近いリージョンを使用できます。App Engine アプリと同じリージョンを選択する必要があります。任意の Redis バージョンを選択できますが、ここでは前述のとおり推奨のバージョン 5 を使用します。これらの設定を指定して発行するコマンドと、関連する出力は次のようになります。

$ gcloud redis instances create demo-ms --region us-central1 \
    --redis-version redis_5_0 --project my-project

Create request issued for: [demo-ms]
Waiting for operation [projects/my-project/locations/us-central1/operations/operation-xxxx] to complete...done.
Created instance [demo-ms].

Cloud コンソールのデフォルトとは異なり、gcloud は最小限のリソースにデフォルト設定されます。その結果、このコマンドではサービスティアもストレージ容量も必要ありませんでした。Memorystore インスタンスの作成には数分かかります。完了したら、インスタンスの IP アドレスとポート番号をメモします。これらはすぐに app.yaml に追加されます。

インスタンスが作成されたことを確認する

Cloud コンソールまたはコマンドラインから

Cloud Console またはコマンドラインからインスタンスを作成した場合は、次のコマンドを使用して、インスタンスが使用可能で、使用準備が整っていることを確認できます。gcloud redis instances list --region REGION

リージョン us-central1 のインスタンスを確認するコマンドと、作成したインスタンスを示す出力例を次に示します。

$ gcloud redis instances list --region us-central1
INSTANCE_NAME  VERSION    REGION       TIER   SIZE_GB  HOST         PORT  NETWORK  RESERVED_IP     STATUS  CREATE_TIME
demo-ms        REDIS_5_0  us-central1  BASIC  1        10.aa.bb.cc  6379  default  10.aa.bb.dd/29  READY   2022-01-28T09:24:45

インスタンス情報の入力やアプリの構成を求められたら、必ず HOSTPORT を使用してください(RESERVED_IP は使用しないでください)。Cloud Console の Cloud Memorystore ダッシュボードに、このインスタンスが表示されるようになります。

c5a6948ec1c056ed.png

Compute Engine 仮想マシンから

Compute Engine 仮想マシン(VM)がある場合は、VM から Memorystore インスタンスに直接コマンドを送信して、動作を確認することもできます。VM の使用には、すでに使用しているリソースとは別に費用が発生する場合があります。

サーバーレス VPC アクセス コネクタを作成する

Cloud Memorystore と同様に、サーバーレス Cloud VPC コネクタは Cloud コンソールまたはコマンドラインで作成できます。同様に、Cloud VPC には無料枠がないため、費用を最小限に抑えるために、この設定でコードラボを完了するのに必要な最小限のリソースを割り当てることをおすすめします。

  • インスタンスの最大数を最小の 3 に選択します(コンソールと gcloud のデフォルト: 10)。
  • 最もコストの低いマシンタイプを選択します。f1-micro(コンソールのデフォルト: e2-microgcloud のデフォルトなし)

次のセクションでは、上記の Cloud VPC 設定を使用して Cloud Console からコネクタを作成する手順について説明します。コマンドラインから実行する場合は、次のセクションに進みます。

Cloud コンソールから

Cloud Console の [Cloud Networking] の [Serverless VPC access] ページに移動します(請求情報の入力を求められることがあります)。API をまだ有効にしていない場合は、有効にするように求めるメッセージが表示されます。

e3b9c0651de25e97.png

API を有効にすると(課金も有効にしている場合はそれも含む)、作成されたすべての VPC コネクタが表示されるダッシュボードが表示されます。下のスクリーンショットで使用されているプロジェクトには行がないため、「No rows to display」と表示されています。コンソールの上部にある [コネクタを作成] をクリックします。

b74b49b9d73b7dcf.png

フォームに希望の設定を入力します。

6b26b2aafa719f73.png

独自のアプリケーションに適した設定を選択します。このチュートリアルと最小限のニーズを満たすサンプルアプリでは、コストを最小限に抑えることが理にかなっているので、前述の推奨事項に従ってください。選択が完了したら、[作成] をクリックします。VPC コネクタの要求が完了するまでに数分かかります。

コマンドラインから

VPC コネクタを作成する前に、まず Serverless VPC Access API を有効にします。次のコマンドを発行すると、同様の出力が表示されます。

$ gcloud services enable vpcaccess.googleapis.com
Operation "operations/acf.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

API が有効になっている場合、次のようなコマンドで VPC コネクタが作成されます。

gcloud compute networks vpc-access connectors create CONNECTOR_NAME \
    --range 10.8.0.0/28 --region REGION --project PROJECT_ID

コネクタの名前と、未使用の /28 CIDR ブロックの開始 IP アドレスを選択します。このチュートリアルでは、次のことを前提としています。

  • プロジェクト ID: my-project
  • VPC コネクタ名: demo-vpc
  • 最小インスタンス数: 2(デフォルト)、最大インスタンス数: 3
  • インスタンス タイプ: f1-micro
  • リージョン: us-central1
  • IPv4 CIDR ブロック: 10.8.0.0/28(Cloud コンソールで推奨)

上記の前提条件を踏まえて次のコマンドを実行すると、次のような出力が表示されます。

$ gcloud compute networks vpc-access connectors create demo-vpc \
    --max-instances 3 --range 10.8.0.0/28 --machine-type f1-micro \
    --region us-central1  --project my-project

Create request issued for: [demo-vpc]
Waiting for operation [projects/my-project/locations/us-central1/operations/xxx] to complete...done.
Created connector [demo-vpc].

上記のコマンドでは、最小インスタンス数 2 や default という名前のネットワークなどのデフォルト値の指定が省略されています。VPC コネクタの作成が完了するまでに数分かかります。

コネクタが作成されたことを確認する

プロセスが完了したら、リージョン us-central1 であることを前提として、次の gcloud コマンドを発行し、作成されて使用できる状態になっていることを確認します。

$ gcloud compute networks vpc-access connectors list --region us-central1
CONNECTOR_ID  REGION       NETWORK  IP_CIDR_RANGE  SUBNET  SUBNET_PROJECT  MIN_THROUGHPUT  MAX_THROUGHPUT  STATE
demo-vpc      us-central1  default  10.8.0.0/28                            200             300             READY

同様に、ダッシュボードには作成したコネクタが表示されます。

e03db2c8140ed014.png

Cloud プロジェクト ID、VPC コネクタ名、リージョンをメモします。

コマンドラインまたはコンソールで必要な追加の Cloud リソースを作成したので、それらの使用をサポートするようにアプリケーション構成を更新します。

5. 構成ファイルを更新する

最初の手順は、構成ファイルに必要な更新をすべて行うことです。この Codelab の主な目的は、Python 2 ユーザーの移行を支援することですが、通常、以下の各セクションで Python 3 への移行に関する情報が提供されます。

requirements.txt

このセクションでは、Cloud Memorystore と Cloud NDB をサポートするパッケージを追加します。Cloud Memorystore for Redis の場合、Cloud Memorystore クライアント ライブラリ自体が存在しないため、標準の Redis クライアント for Python(redis)を使用するだけで十分です。redisgoogle-cloud-ndb の両方を requirements.txt に追加し、モジュール 12 の flask を結合します。

flask
redis
google-cloud-ndb

この requirements.txt ファイルにはバージョン番号が含まれていないため、最新バージョンが選択されます。互換性の問題が発生した場合は、バージョン番号を指定して動作するバージョンをロックします。

app.yaml

追加する新しいセクション

Python 2 App Engine ランタイムで Cloud NDB などの Cloud API を使用する場合は、grpciosetuptools という特定のサードパーティ パッケージが必要です。Python 2 ユーザーは、app.yaml で、これらの組み込みライブラリと利用可能なバージョンをリストする必要があります。libraries セクションがまだない場合は、作成して、次のように両方のライブラリを追加します。

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest

アプリを移行する場合、すでに libraries セクションが存在している可能性があります。その場合は、grpciosetuptools のいずれかが欠落している場合は、既存の libraries セクションに追加してください。

次に、サンプルアプリには Cloud Memorystore インスタンスと VPC コネクタの情報が必要になるため、使用している Python ランタイムに関係なく、app.yaml に次の 2 つの新しいセクションを追加します。

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

必要な更新は以上です。更新された 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

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

以下は、app.yaml に適用する必要がある更新を示す「更新前と更新後」の例です。

ec2bb027a67debb6.png

*Python 3 の違い

このセクションは省略可能で、Python 3 に移植する場合にのみ必要です。そのためには、Python 2 の構成にいくつかの変更を加える必要があります。現時点でアップグレードしない場合は、このセクションをスキップしてください。

Python 3 ランタイムでは threadsafeapi_version も使用されないため、これらの設定を両方削除します。最新の App Engine ランタイムでは、組み込みのサードパーティ ライブラリ組み込みでないライブラリのコピーがサポートされていません。サードパーティ パッケージの要件は、requirements.txt に記載することのみです。その結果、app.yamllibraries セクション全体を削除できます。

次に、Python 3 ランタイムでは独自のルーティングを行うウェブ フレームワークを使用する必要があるため、モジュール 1 で webapp2 から Flask に移行する方法を紹介しました。そのため、すべてのスクリプト ハンドラを auto に変更する必要があります。このアプリは静的ファイルを提供しないため、ハンドラをリストに含めるのは「無意味」です(すべて auto であるため)。したがって、handlers セクション全体を削除することもできます。その結果、Python 3 用に調整された新しい短縮形の app.yaml は次のように短縮されます。

runtime: python39

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

Python 3 に移植する際の app.yaml の違いをまとめると、次のようになります。

  • threadsafeapi_version の設定を削除する
  • libraries セクションを削除
  • handlers セクションを削除します(アプリが静的ファイルを提供している場合は script ハンドラのみを削除します)。

値を置き換える

Memorystore と VPC コネクタの新しいセクションの値はプレースホルダです。大文字の値(YOUR_REDIS_HOST, YOUR_REDIS_PORT, PROJECT_ID, REGION, CONNECTOR_NAME)は、これらのリソースを以前に作成したときに保存した値に置き換えます。Memorystore インスタンスについては、RESERVED_IP ではなく HOSTPORT を使用してください。インスタンス名が demo-ms で、REGIONus-central1 であると仮定して、HOSTPORT を取得するコマンドラインの簡単な方法を次に示します。

$ gcloud redis instances describe demo-ms --region us-central1 \
    --format "value(host,port)"
10.251.161.51   6379

たとえば、Redis インスタンスの IP アドレスが 10.10.10.10 で、ポート 6379 を使用し、リージョン us-central1 にあるプロジェクト my-project で VPC コネクタ名が demo-vpc の場合、app.yaml のこれらのセクションは次のようになります。

env_variables:
    REDIS_HOST: '10.10.10.10'
    REDIS_PORT: '6379'

vpc_access_connector:
    name: projects/my-project/locations/us-central1/connectors/demo-vpc

appengine_config.py を作成または更新する

組み込みサードパーティ ライブラリのサポートを追加

先ほど app.yaml で行ったように、grpcio ライブラリと setuptools ライブラリの使用を追加します。組み込みのサードパーティ ライブラリをサポートするように appengine_config.py を変更します。この手順は、モジュール 2 で App Engine ndb から Cloud NDB に移行したときにも必要でした。必要な変更は、lib フォルダを setuptools.pkg_resources ワーキング セットに追加することです。

4140b3800694f77e.png

*Python 3 の違い

このセクションは省略可能で、Python 3 に移植する場合にのみ必要です。App Engine 第 2 世代の変更点の 1 つは、app.yaml で(組み込みでない)サードパーティ パッケージのコピー(「ベンダーリング」と呼ばれることもあります)と組み込みのサードパーティ パッケージの参照が不要になったことです。つまり、appengine_config.py ファイル全体を削除できます。

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

アプリケーション ファイルは main.py の 1 つだけなので、このセクションの変更はすべてそのファイルにのみ影響します。このアプリケーションを Cloud Memorystore に移行するために行う変更を図で示します。これは説明のみを目的としており、詳細な分析を意図したものではありません。すべての作業は、コードの変更で行います。

5d043768ba7be742.png

上から順に、各セクションを 1 つずつ見ていきましょう。

インポートを更新する

モジュール 12 の main.py のインポート セクションでは、Cloud NDB と Cloud Tasks を使用しています。インポートは次のとおりです。

変更前:

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

Memorystore に切り替えるには環境変数を読み取る必要があります。つまり、Python Redis クライアントである redis と Python os モジュールも必要になります。Redis は Python オブジェクトをキャッシュに保存できないため、pickle を使用して最新のアクセス リストをマーシャルします。そのため、これもインポートします。Memcache のメリットの 1 つは、オブジェクトのシリアル化が自動的に行われることです。一方、Memorystore はもう少し「DIY」です。最後に、google.appengine.ext.ndbgoogle.cloud.ndb に置き換えて、App Engine ndb から Cloud NDB にアップグレードします。これらの変更を行うと、インポートは次のようになります。

変更後:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

初期化を更新

モジュール 12 の初期化では、Flask アプリケーション オブジェクト app をインスタンス化し、1 時間分のキャッシュ保存の定数を設定します。

変更前:

app = Flask(__name__)
HOUR = 3600

Cloud API を使用するにはクライアントが必要なので、Flask の直後に Cloud NDB クライアントをインスタンス化します。次に、app.yaml で設定した環境変数から Memorystore インスタンスの IP アドレスとポート番号を取得します。この情報を使用して、Redis クライアントをインスタンス化します。更新後のコードは次のようになります。

変更後:

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

*Python 3 への移行

このセクションは省略可能です。モジュール 12 アプリの Python 3 バージョンから始める場合は、インポートと初期化に関連するいくつかの必要な変更があります。

まず、Memcache は App Engine バンドル サービスであるため、Python 3 アプリで使用するには App Engine SDK が必要です。具体的には、WSGI アプリケーションをラップします(他の必要な構成も同様です)。

変更前:

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

Cloud Memorystore(Memcache などの App Engine バンドル サービスではない)に移行するため、SDK の使用を削除する必要があります。これは、memcachewrap_wsgi_app の両方をインポートする行全体を削除するだけなので、簡単です。wrap_wsgi_app() を呼び出す行も削除します。これらの更新により、アプリのこの部分(実際にはアプリ全体)は Python 2 バージョンと同じになります。

変更後:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

最後に、app.yamlapp_engine_apis: true 行を削除)と requirements.txtappengine-python-standard 行を削除)から SDK の使用を削除します。

Cloud Memorystore(および Cloud NDB)に移行する

Cloud NDB のデータモデルは App Engine ndb と互換性があるように設計されています。つまり、Visit オブジェクトの定義は同じままです。モジュール 2 の Cloud NDB への移行を模倣して、store_visit()fetch_visits() のすべての Datastore 呼び出しが拡張され、新しい with ブロックに埋め込まれます(Cloud NDB コンテキスト マネージャーの使用が必要なため)。変更前の呼び出しは次のとおりです。

変更前:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

両方の関数に with ds_client.context() ブロックを追加し、Datastore 呼び出しをその内側に(インデントして)配置します。この場合、呼び出し自体に変更を加える必要はありません。

変更後:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

次に、キャッシュ保存の変更点を見ていきましょう。モジュール 12 の main() 関数は次のとおりです。

変更前:

@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)

Redis には、Memcache と同様に「get」呼び出しと「set」呼び出しがあります。それぞれのクライアント ライブラリを入れ替えるだけですよね?ほぼ正確です。前述のように、Redis で Python リストをキャッシュに保存することはできません(最初にシリアル化する必要があるため。Memcache はこれを自動的に処理します)。そのため、set() 呼び出しで、pickle.dumps() を使用してアクセス数を文字列に pickle 化します。同様に、キャッシュからアクセスを取得する場合は、get() の直後に pickle.loads() でアンピクルする必要があります。これらの変更を実装した後のメイン ハンドラは次のようになります。

変更後:

@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)
    rsp = REDIS.get('visits')
    visits = pickle.loads(rsp) if rsp else None

    # 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))
        REDIS.set('visits', pickle.dumps(visits), ex=HOUR)

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

これで、main.py でサンプルアプリの Memcache の使用を Cloud Memorystore に変換するために必要な変更は完了です。HTML テンプレートと Python 3 への移植はどうなりますか?

HTML テンプレート ファイルを更新して Python 3 に移植する

サプライズ!このアプリケーションは、コードの変更や互換性ライブラリなしで Python 2 と 3 の両方で実行できるように設計されているため、ここでは何もする必要はありません。main.py が表示されます。mod13a(2.x)と mod13b(3.x)の「FINISH」フォルダで同じです。requirements.txt も同様です(バージョン番号が異なる場合を除く)。ユーザー インターフェースは変更されないため、templates/index.html も更新されません。

Python 3 App Engine でこのアプリを実行するために必要なすべての作業は、構成で完了しました。不要なディレクティブは app.yaml から削除され、appengine_config.pylib フォルダは Python 3 で使用されていないため削除されました。

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

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

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

最後のチェックは、常にサンプルアプリをデプロイすることです。Python 2 デベロッパーは、次のコマンドを使用して lib を削除して再インストールします。(システムに Python 2 と 3 の両方がインストールされている場合は、代わりに pip2 を明示的に実行する必要がある場合があります)。

rm -rf ./lib
pip install -t lib -r requirements.txt

Python 2 と 3 の両方のデベロッパーは、アプリをデプロイする際に次のコマンドを使用する必要があります。

gcloud app deploy

内部で完全に異なるキャッシュ サービスに配線を変更しただけなので、アプリ自体はモジュール 12 のアプリと同じように動作します。

モジュール 7 の visitme アプリ

これで、この Codelab は完了です。更新したサンプルアプリを、モジュール 13 のフォルダ mod13a(Python 2)または mod13b(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 固有のものです。詳細については、各プロダクトのドキュメントをご覧ください。

  • Cloud Memorystore にはインスタンスが必要であり、無料枠はありません。使用料金の詳細については、料金ページをご覧ください。
  • Cloud Serverless VPC Access コネクタにはインスタンスが必要であり、無料枠はありません。使用料金の詳細については、Cloud VPC の料金ページの該当するセクションをご覧ください。
  • Cloud Datastore(Datastore モードの Cloud Firestore)には無料枠があります。詳細については、料金ページをご覧ください。

このチュートリアルでは、次の 4 つの Cloud プロダクトを使用しました。

  • App Engine
  • Cloud Datastore
  • Cloud Memorystore
  • Cloud VPC

以下に、これらのリソースを解放して課金を回避または最小限に抑える手順を示します。

Memorystore インスタンスと VPC コネクタをシャットダウンする

これらのプロダクトには無料枠がないため、現在、請求が発生しています。Cloud プロジェクトをシャットダウンしない場合(次のセクションを参照)、課金を停止するには、Memorystore インスタンスと VPC コネクタの両方を削除する必要があります。これらのリソースを作成したときと同様に、Cloud コンソールまたはコマンドラインからリリースすることもできます。

Cloud コンソールから

Memorystore インスタンスを削除するには、Memorystore ダッシュボードに戻り、インスタンス ID をクリックします。

2b09baf1aa2e0a25.png

インスタンスの詳細ページで、[削除] をクリックして確定します。

f9d9eb1c1d4c6107.png

VPC コネクタを削除するには、そのダッシュボードに移動し、削除するコネクタの横にあるチェックボックスをオンにして、[削除] をクリックして確認します。

ca5fbd9f4c7c9b60.png

コマンドラインから

次の gcloud コマンドのペアは、それぞれ Memorystore インスタンスと VPC コネクタを削除します。

  • gcloud redis instances delete INSTANCE --region REGION
  • gcloud compute networks vpc-access connectors delete CONNECTOR --region REGION

gcloud config set project でプロジェクト ID を設定していない場合は、--project PROJECT_ID を指定する必要があります。Memorystore インスタンスの名前が demo-ms、VPC コネクタの名前が demo-vpc で、両方がリージョン us-central1 にある場合は、次のコマンドのペアを発行して確認します。

$ gcloud redis instances delete demo-ms --region us-central1
You are about to delete instance [demo-ms] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-ms]
Waiting for operation [projects/PROJECT/locations/REGION/operations/operation-aaaaa-bbbbb-ccccc-ddddd] to complete...done.
Deleted instance [demo-ms].
$
$ gcloud compute networks vpc-access connectors delete demo-vpc --region us-central1
You are about to delete connector [demo-vpc] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-vpc]
Waiting for operation [projects/PROJECT/locations/REGION/operations/aaaaa-bbbb-cccc-dddd-eeeee] to complete...done.
Deleted connector [demo-vpc].

各リクエストの実行には数分かかります。前述のように Cloud プロジェクト全体をシャットダウンする場合は、これらの手順は省略可能ですが、シャットダウン プロセスが完了するまでは課金が発生します。

次のステップ

このチュートリアル以外にも、以前のバンドル サービスからの移行に焦点を当てた移行モジュールがあります。

App Engine は、Google Cloud の唯一のサーバーレス プラットフォームではなくなりました。小規模な App Engine アプリや、機能が制限されているアプリをスタンドアロンのマイクロサービスに変換したい場合や、モノリシック アプリを複数の再利用可能なコンポーネントに分割したい場合は、Cloud Functions への移行を検討する理由として十分です。コンテナ化がアプリケーション開発ワークフローの一部になっている場合(特に CI/CD(継続的インテグレーション/継続的デリバリーまたはデプロイ)パイプラインで構成されている場合)は、Cloud Run への移行を検討してください。これらのシナリオは、次のモジュールで取り上げます。

  • App Engine から Cloud Functions に移行する: モジュール 11 をご覧ください。
  • App Engine から Cloud Run に移行する: モジュール 4 で Docker を使用してアプリをコンテナ化するか、モジュール 5 でコンテナ、Docker の知識、Dockerfile を使用せずにコンテナ化します。

別のサーバーレス プラットフォームへの切り替えは任意です。変更を行う前に、アプリとユースケースに最適なオプションを検討することをおすすめします。

次にどの移行モジュールを検討する場合でも、すべてのサーバーレス移行ステーションのコンテンツ(Codelab、動画、ソースコード [利用可能な場合])は、オープンソース リポジトリからアクセスできます。リポジトリの README には、考慮すべき移行と、移行モジュールの関連する「順序」に関するガイダンスも記載されています。

8. 参考情報

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

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

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

移行に関するリソース

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

Codelab

Python 2

Python 3

モジュール 12

コード

コード

モジュール 13(この Codelab)

コード

コード

オンライン リファレンス

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

App Engine

App Engine NDB と Cloud NDB

App Engine Memcache と Cloud Memorystore

Cloud VPC

その他のクラウド情報

ライセンス

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