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

1. 概要

Serverless Migration Station の Codelab シリーズ(セルフペース型のハンズオン チュートリアル)と関連動画は、Google Cloud サーバーレス デベロッパーが主にレガシー サービスからの移行を 1 つ以上の移行を通じてガイドし、アプリをモダナイズできるようにすることを目的としています。これにより、アプリのポータビリティが高まり、選択肢と柔軟性が増し、より広範な 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 コンソールまたは gcloud ツールから)
  • App Engine Memcache から Cloud Memorystore に移行する
  • サンプルアプリで Cloud Memorystore を使用してキャッシュを実装する
  • App Engine ndb から Cloud NDB への移行

必要なもの

アンケート

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

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

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

初心者 中級者 上級者

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

<ph type="x-smartling-placeholder"></ph> 初心者 中級 上達 をご覧ください。

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 バンドル サービスにアクセスすることにすでに慣れている場合は、Module 12 サンプルアプリの Python 3 バージョンから開始できます。Memorystore は App Engine のバンドル サービスではないため、これによって SDK の使用がなくなります。このチュートリアルでは、Python 3 App Engine SDK の使用方法について説明しません。

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

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

3. 設定/事前作業

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

モジュール 12 の Codelab で使用したプロジェクトと同じプロジェクトを再利用することをおすすめします。あるいは、新しいプロジェクトを作成することも、別の既存のプロジェクトを再利用することもできます。このシリーズのすべての Codelab には「開始」という言葉があります。(開始時のベースライン コード)と "FINISH" の(移行されたアプリ)を選択します。問題が発生した場合に備え、FINISH コードが提供されているので、自社のソリューションと Google のソリューションを比較できます。問題が発生した場合には、いつでもロールバックして開始することができます。これらのチェックポイントは、移行の実施方法の学習が成功していることを確認するためのものです。

どの 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 のアプリと同様に機能することを確認します。このモジュール 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 インスタンスを作成すると、App Engine アプリは VPC コネクタなしではそのインスタンスにアクセスできません。同様に、先に VPC コネクタを作成した場合、App Engine アプリが通信する VPC ネットワークはありません。このチュートリアルでは、まず Memorystore インスタンスを作成し、次に VPC コネクタを作成します。

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

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

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

  • 最下位のサービスティアとして [基本] を選択します(コンソールのデフォルト: [スタンダード]、gcloud のデフォルト: [ベーシック])。
  • 最小容量として [1 GB] を選択します(コンソールのデフォルト: 16 GB、gcloud のデフォルト: 1 GB)。
  • 通常、どのソフトウェアでも、最新バージョンには大量のリソースが必要になりますが、最も古いバージョンを選択するのはおすすめしません。現在の 2 番目の最新バージョンは Redis バージョン 5.0 です(コンソールのデフォルト: 6.x)

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

Cloud Console から

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

68318997e3105db6.png

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

63547aa575838a36.png

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

b77d927287fdf4c7.png

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

コマンドラインから

Cloud コンソールから Memorystore インスタンスを作成することは、視覚的にわかりやすいといえますが、コマンドラインのほうが好まれる場合もあります。次に進む前に、必ず gcloudインストールして初期化してください。

Cloud コンソールと同様に、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」を使用します。プロジェクト ID「my-project」と一緒に名前として使用します。このサンプルアプリのリージョンは 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 コンソールかコマンドラインかにかかわらず、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

インスタンス情報やアプリの構成を求められたら、RESERVED_IP ではなく HOSTPORT を使用します。Cloud コンソールの Cloud Memorystore ダッシュボードにそのインスタンスが表示されます。

c5a6948ec1c056ed.png

Compute Engine 仮想マシンから

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

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

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

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

次のセクションでは、上記の Cloud VPC 設定を使用して Cloud コンソールからコネクタを作成する手順を説明します。コマンドラインから行う場合は、次のセクションに進んでください。

Cloud コンソールから

[クラウド ネットワーキング] の [サーバーレス VPC アクセス] に移動します。] ページをクリックします(お支払い情報の入力を求められる場合があります)。API をまだ有効にしていない場合は、有効にするよう求められます。

e3b9c0651de25e97.png

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

b74b49b9d73b7dcf.png

必要な設定でフォームに入力します。

6b26b2aafa719f73.png

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

コマンドラインから

VPC コネクタを作成する前に、まずサーバーレス VPC アクセス 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 コネクタの作成が完了するまでに数分かかります。

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

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

$ 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 クライアント ライブラリ自体は存在しないため、標準の Python 用 Redis クライアント(redis)を使用するだけで十分です。redisgoogle-cloud-ndb の両方を requirements.txt に追加し、モジュール 12 の flask を結合します。

flask
redis
google-cloud-ndb

この requirements.txt ファイルにはバージョン番号がありません。つまり、最新バージョンが選択されます。互換性の問題がある場合は、バージョン番号を指定して作業中のバージョンをロックします。

app.yaml

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

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

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

アプリを移行するときに、すでに libraries セクションが含まれている場合があります。存在する場合で、grpciosetuptools のいずれかがない場合は、既存の libraries セクションに追加します。

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

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 で webp2 から 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-msREGIONus-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 で、リージョン us-central1 にあるプロジェクト my-project でポート 6379 を使用し、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 を変更します。App Engine ndb から Cloud NDB に移行する際にモジュール 2 でも必要だったからです。厳密に必要な変更は、setuptools.pkg_resources ワーキング セットに lib フォルダを追加することです。

4140b3800694f77e.png

*Python 3 の違い

このセクションは、Python 3 に移植する場合にのみ省略できます。App Engine の第 2 世代で歓迎される変更点の一つは、(非組み込み)サードパーティ パッケージのコピー(ベンダリング)と app.yaml での組み込みサードパーティ パッケージの参照が不要になることです。つまり、appengine_config.py ファイル全体を削除できるようになります。

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

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

5d043768ba7be742.png

これらのセクションを上から順番に説明していきましょう。

インポートを更新する

モジュール 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 os モジュールと、Python Redis クライアントである redis が必要です。Redis は Python オブジェクトをキャッシュに保存できないため、pickle を使用して最新の訪問リストをマーシャリングし、それもインポートします。Memcache の利点の一つは、オブジェクトのシリアル化が自動的に行われるのに対し、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 APIs を使用するにはクライアントが必要であるため、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 の移行

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

まず、Memcache は App Engine のバンドル サービスであるため、Python 3 アプリで使用するには、WSGI アプリケーション(およびその他の必要な構成)をラップする App Engine 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

今回は Memcache のような App Engine バンドル サービスではなく Cloud Memorystore に移行するため、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 には「set」呼び出すことができます。それぞれのクライアント ライブラリを入れ替えるだけですよね?ほぼ正確です。前述のように、Python リストを Redis でキャッシュに保存することはできません(最初にシリアル化する必要があるため、Memcache が自動的に処理します)。そのため、set() 呼び出しで「pickle」を実行します。アクセスを pickle.dumps() の文字列に変換します。同様に、キャッシュから訪問を取得する場合は、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)

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

HTML テンプレート ファイルを更新し、ポートを Python 3 に変更しますか?

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

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

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

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

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

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

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

Python 2 と Python 3 のデベロッパーは、どちらも以下を使用してアプリをデプロイする必要があります。

gcloud app deploy

内部ですべてを再構築してまったく別のキャッシュ サービスにするだけなので、アプリ自体はモジュール 12 アプリとまったく同じように動作するはずです。

モジュール 7 Visitme アプリ

これで Codelab は終了です。更新したサンプルアプリを、モジュール 13 のフォルダ mod13a(Python 2)または mod13b(Python 3)のいずれかと比較してください。

クリーンアップ

全般

現時点で完了したら、課金が発生しないように App Engine アプリを無効にすることをおすすめします。さらにテストや実験を行う場合は、App Engine プラットフォームに無料の割り当てが用意されています。この使用量ティアを超えない限り、料金は発生しません。これはコンピューティングに関するものですが、関連する App Engine サービスに対して料金が発生する場合もあります。詳細については、料金ページをご覧ください。この移行に他のクラウド サービスが含まれる場合、それらは別途請求されます。いずれの場合も、該当する場合は「この 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 サーバーレス VPC アクセス コネクタにはインスタンスが必要ですが、無料枠はありません。使用料金の詳細については、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

プロジェクト ID を gcloud config set project で設定していない場合は、--project PROJECT_ID の指定が必要になることがあります。Memorystore インスタンスの名前が demo-ms で、demo-vpc という 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 を使用せずに

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

次に検討する移行モジュールに関係なく、Serverless Migration Station のすべてのコンテンツ(Codelab、動画、ソースコード(利用可能な場合))には、オープンソース リポジトリからアクセスできます。リポジトリの README には、検討すべき移行や関連する「順序」に関するガイダンスも用意されています。概要をまとめたものです

8. 参考情報

以下に、本モジュールや関連する移行モジュールと関連プロダクトについて詳しく学ぶデベロッパー向けの追加リソースを示します。これには、このコンテンツに関するフィードバックを提供する場所、コードへのリンク、役立つさまざまなドキュメントが含まれます。

Codelab の問題/フィードバック

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

移行に関するリソース

以下の表に、モジュール 12(START)とモジュール 13(FINISH)のリポジトリ フォルダへのリンクを示します。これらは、すべての 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

Cloud のその他の情報

ライセンス

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