App Engine Blobstore から Cloud Storage への移行(モジュール 16)

1. 概要

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

この Codelab では、App Engine Blobstore から Cloud Storage に移行する方法について説明します。次のものからの暗黙的な移行もあります。

詳細な手順については、関連する移行モジュールを参照してください。

GCP コンソールの

  • App Engine Blobstore API/ライブラリの使用を追加
  • ユーザーのアップロードを Blobstore サービスに保存する
  • Cloud Storage への移行の次のステップを準備する

必要なもの

アンケート

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

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

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

初心者 中級者 上級者

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

初心者 中級者 上級者

2. 背景情報

この Codelab では、モジュール 15 のサンプルアプリを使用して、Blobstore(および NDB)から Cloud Storage(および Cloud NDB)に移行する方法を説明します。移行プロセスでは、App Engine の以前のバンドル サービスへの依存関係を置き換えます。これにより、必要に応じてアプリを別の Cloud サーバーレス プラットフォームや他のホスティング プラットフォームに移行できます。

この移行は、このシリーズの他の移行と比較して、少し手間がかかります。Blobstore は元の webapp フレームワークに依存しているため、サンプルアプリでは Flask ではなく webapp2 フレームワークを使用しています。このチュートリアルでは、Cloud Storage、Cloud NDB、Flask、Python 3 への移行について説明します。

アプリはエンドユーザーの「アクセス」を登録し、最新の 10 件を表示しますが、前回の(モジュール 15)Codelab では、Blobstore の使用に対応するための新しい機能が追加されました。アプリはエンドユーザーに「アクセス」に対応するアーティファクト(ファイル)のアップロードを求めるようになりました。ユーザーは、この設定を行うか、[スキップ] を選択してオプトアウトできます。ユーザーの選択に関係なく、次のページにはこのアプリの以前のバージョンと同じ出力が表示され、最近のアクセスが表示されます。さらに、対応するアーティファクトを含むアクセスには、アクセス アーティファクトを表示するための「表示」リンクがあります。この Codelab では、前述の移行を実装しながら、説明した機能を維持します。

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

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

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

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

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

この Codelab の前提条件の 1 つは、機能するモジュール 15 のサンプルアプリを用意することです。まだお持ちでない場合は、モジュール 15 の「START」フォルダ(下のリンク)から入手できます。この Codelab では、各ステップを順を追って説明します。最後に、モジュール 16 の「FINISH」フォルダにあるコードに似たコードが完成します。

モジュール 15 の開始ファイルのディレクトリは次のようになります。

$ ls
README.md       app.yaml        main-gcs.py     main.py         templates

main-gcs.py ファイルは、モジュール 15 の main.py の代替バージョンです。プロジェクトの ID(PROJECT_ID.appspot.com)に基づいて、アプリの割り当てられた URL のデフォルトとは異なる Cloud Storage バケットを選択できます。このファイルは、この(モジュール 16)Codelab では使用されませんが、必要に応じて同様の移行手法を適用できます。

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

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

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

各手順を正常に実行して、モジュール 15 のアプリが動作することを確認します。最初のページには、ユーザーに訪問アーティファクト ファイルのアップロードを求めるフォームと、オプトアウトするための「スキップ」ボタンが表示されます。

f5b5f9f19d8ae978.png

ユーザーがファイルをアップロードするかスキップすると、アプリは「最近のアクセス」ページを表示します。

f5ac6b98ee8a34cb.png

アーティファクトを含むアクセスには、アクセス タイムスタンプの右側にアーティファクトを表示(またはダウンロード)するための [表示] リンクが表示されます。アプリの機能を確認したら、App Engine のレガシー サービス(webapp2、NDB、Blobstore)から最新の代替サービス(Flask、Cloud NDB、Cloud Storage)に移行する準備が整います。

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

アプリの更新バージョンでは、3 つの構成ファイルが使用されます。必要なタスクは次のとおりです。

  1. app.yaml で必要な組み込みのサードパーティ ライブラリを更新し、Python 3 への移行の可能性を残す
  2. 組み込みでない必要なライブラリをすべて指定する requirements.txt を追加します。
  3. appengine_config.py を追加して、アプリが組み込みのサードパーティ ライブラリと組み込み以外のサードパーティ ライブラリの両方をサポートするようにします。

app.yaml

libraries セクションを更新して、app.yaml ファイルを編集します。jinja2 を削除し、grpciosetuptoolsssl を追加しました。3 つのライブラリすべてで利用可能な最新バージョンを選択します。Python 3 の runtime ディレクティブも追加しますが、コメントアウトします。完了すると、次のようになります(Python 3.9 を選択した場合)。

変更前:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

変更後:

#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1

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

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

この変更は主に、App Engine サーバーで使用可能な Python 2 組み込みライブラリ(自分でバンドルする必要はありません)を対象としています。Jinja2 は Flask に付属しているため、削除しました。Flask は reqs.txt に追加します。Cloud NDB や Cloud Storage などの Google Cloud クライアント ライブラリを使用する場合は、grpcio と setuptools が必要です。最後に、Cloud Storage 自体で ssl ライブラリが必要です。上部のコメントアウトされたランタイム ディレクティブは、このアプリを Python 3 に移植する準備ができたときに使用します。このトピックについては、このチュートリアルの最後で説明します。

requirements.txt

requirements.txt ファイルを追加します。このファイルでは、Flask フレームワーク、Cloud NDB クライアント ライブラリ、Cloud Storage クライアント ライブラリが必要です。これらのライブラリは組み込みではありません。次の内容のファイルを作成します。

flask
google-cloud-ndb
google-cloud-storage

Python 2 App Engine ランタイムでは、組み込み以外のサードパーティ ライブラリのセルフバンドルが必要なため、次のコマンドを実行してこれらのライブラリを lib フォルダにインストールします。

pip install -t lib -r requirements.txt

開発マシンに Python 2 と 3 の両方がある場合は、pip2 コマンドを使用して、これらのライブラリの Python 2 バージョンを取得する必要があります。Python 3 にアップグレードすると、セルフバンドルは不要になります。

appengine_config.py

組み込みと非組み込みのサードパーティ ライブラリをサポートする appengine_config.py ファイルを追加します。次の内容のファイルを作成します。

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

完了した手順は、App Engine ドキュメントの Python 2 アプリ用のライブラリのインストール セクションに記載されている手順と類似しているか、同じであるはずです。特に、appengine_config.py の内容は、そのセクションの手順 5 の内容と一致しているはずです。

構成ファイルの作業が完了したので、アプリケーションに進みましょう。

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

インポート

main.py の最初の変更セットには、置き換えられるすべてのもののスワップアウトが含まれます。変更内容は次のとおりです。

  1. webapp2 は Flask に置き換えられます
  2. webapp2_extras の Jinja2 を使用する代わりに、Flask に付属の Jinja2 を使用します。
  3. App Engine Blobstore と NDB が Cloud NDB と Cloud Storage に置き換えられる
  4. webapp の Blobstore ハンドラは、io 標準ライブラリ モジュール、Flask、werkzeug ユーティリティの組み合わせに置き換えられます。
  5. デフォルトでは、Blobstore はアプリの URL(PROJECT_ID.appspot.com)にちなんだ名前の Cloud Storage バケットに書き込みます。Cloud Storage クライアント ライブラリに移植するため、google.auth を使用してプロジェクト ID を取得し、まったく同じバケット名を指定します。(バケット名はハードコードされなくなったため、変更できます)。

変更前:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

上記のリストの変更を実装するには、main.py の現在のインポート セクションを次のコード スニペットに置き換えます。

変更後:

import io

from flask import (Flask, abort, redirect, render_template,
        request, send_file, url_for)
from werkzeug.utils import secure_filename

import google.auth
from google.cloud import exceptions, ndb, storage

初期化と不要な Jinja2 のサポート

次に置き換えるコードブロックは、webapp2_extras から Jinja2 の使用を指定する BaseHandler です。Jinja2 は Flask に付属しており、デフォルトのテンプレート エンジンであるため、これは不要です。削除します。

モジュール 16 側では、以前のアプリにはなかったオブジェクトをインスタンス化します。これには、Flask アプリの初期化、Cloud NDB と Cloud Storage の API クライアントの作成が含まれます。最後に、インポート セクションで前述のように Cloud Storage バケット名をまとめます。これらの更新を実装する前後の例を以下に示します。

変更前:

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

変更後:

app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID

Datastore へのアクセスを更新する

Cloud NDB は、App Engine NDB とほぼ互換性があります。すでに説明した違いの 1 つは、API クライアントが必要なことです。もう 1 つは、後者では API クライアントの Python コンテキスト マネージャーによって Datastore へのアクセスを制御する必要があることです。つまり、Cloud NDB クライアント ライブラリを使用するすべての Datastore アクセス呼び出しは、Python with ブロック内でのみ発生します。

1 つ目の変更は、Blobstore とそのオブジェクト(BlobKey など)が Cloud Storage でサポートされていないため、file_blobndb.StringProperty に変更することです。以下は、これらの変更を反映したデータモデル クラスと更新された store_visit() 関数と fetch_visits() 関数です。

変更前:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()

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

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

変更後:

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.StringProperty()

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

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

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

a8f74ca392275822.png

ハンドラの更新

アップロード ハンドラ

webapp2 のハンドラはクラスですが、Flask では関数です。Flask では、HTTP 動詞メソッドの代わりに、動詞を使用して関数をデコレートします。Blobstore とその webapp ハンドラは、Cloud Storage の機能と Flask とそのユーティリティに置き換えられます。

変更前:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

変更後:

@app.route('/upload', methods=['POST'])
def upload():
    'Upload blob (POST) handler'
    fname = None
    upload = request.files.get('file', None)
    if upload:
        fname = secure_filename(upload.filename)
        blob = gcs_client.bucket(BUCKET).blob(fname)
        blob.upload_from_file(upload, content_type=upload.content_type)
    store_visit(request.remote_addr, request.user_agent, fname)
    return redirect(url_for('root'), code=307)

このアップデートに関する注意事項:

  • blob_id ではなく、ファイル アーティファクトは、存在する場合はファイル名(fname)で識別され、それ以外の場合は None で識別されます(ユーザーがファイルのアップロードをオプトアウトした場合)。
  • Blobstore ハンドラはアップロード プロセスをユーザーから抽象化しますが、Cloud Storage はそうではありません。そのため、ファイルの BLOB オブジェクトとロケーション(バケット)を設定する新しく追加されたコードと、実際のアップロードを実行する呼び出しを確認できます。(upload_from_file())を更新します。
  • webapp2 はアプリケーション ファイルの下部にあるルーティング テーブルを使用しますが、Flask ルートは装飾された各ハンドラにあります。
  • どちらのハンドラも、HTTP 307 戻りコードで POST リクエストを保持しながら、ホーム(/)にリダイレクトすることで機能をラップアップします。

ダウンロード ハンドラ

ダウンロード ハンドラの更新は、アップロード ハンドラと似たパターンで行われますが、コードの量ははるかに少なくなります。Blobstore と webapp の機能を Cloud Storage と Flask の同等の機能に置き換えます。

変更前:

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

変更後:

@app.route('/view/<path:fname>')
def view(fname):
    'view uploaded blob (GET) handler'
    blob = gcs_client.bucket(BUCKET).blob(fname)
    try:
        media = blob.download_as_bytes()
    except exceptions.NotFound:
        abort(404)
    return send_file(io.BytesIO(media), mimetype=blob.content_type)

このアップデートに関する注意事項:

  • Flask はハンドラ関数をルートで装飾しますが、webapp は下部のルーティング テーブルで装飾します。そのため、後者のパターン マッチング構文 ('/view/([^/]+)?' と Flask の構文 '/view/<path:fname>' を認識してください。
  • アップロード ハンドラと同様に、Blobstore ハンドラによって抽象化された機能、つまり問題のファイル(Blob)の特定と、Blobstore ハンドラの単一の send_blob() メソッド呼び出しに対するバイナリの明示的なダウンロードについては、Cloud Storage 側で少し追加の作業が必要になります。
  • どちらの場合も、アーティファクトが見つからない場合は、HTTP 404 エラーがユーザーに返されます。

メイン ハンドラ

メイン アプリケーションに対する最終的な変更は、メイン ハンドラで行われます。webapp2 HTTP 動詞メソッドは、それらの機能を組み合わせた単一の関数に置き換えられます。次のように、MainHandler クラスを root() 関数に置き換え、webapp2 ルーティング テーブルを削除します。

変更前:

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

変更後:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

get() メソッドと post() メソッドを別々に使用するのではなく、これらは基本的に root()if-else ステートメントです。また、root() は単一の関数であるため、GETPOST の両方のテンプレートをレンダリングする呼び出しは 1 つだけです。これは webapp2 では実現できません。

main.py に対する 2 回目(最後)の変更を図で表すと次のようになります。

5ec38818c32fec2.png

(省略可)下位互換性の「強化」

上記のソリューションは完全に機能しますが、最初から作成する場合や、Blobstore で作成されたファイルがない場合に限られます。BlobKey ではなくファイル名でファイルを識別するようにアプリを更新したため、モジュール 16 の完成版アプリをそのままでは Blobstore ファイルを表示できません。つまり、この移行を行うことで、下位互換性のない変更が行われました。このギャップを埋めるために、main.py の代替バージョンである main-migrate.py(リポジトリにあります)を紹介します。

Blobstore で作成されたファイルをサポートする最初の「拡張機能」は、BlobKeyProperty(Cloud Storage で作成されたファイルの StringProperty に加えて)を持つデータモデルです。

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()  # backwards-compatibility
    file_gcs  = ndb.StringProperty()

file_blob プロパティは Blobstore によって作成されたファイルを識別するために使用され、file_gcs は Cloud Storage ファイルに使用されます。新しい訪問を作成するときに、file_blob ではなく file_gcs に値を明示的に保存するようになったため、store_visit は次のようになります。

変更前:

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

変更後:

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

最新のアクセスを取得するときは、データを「正規化」してからテンプレートに送信します。

変更前:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

変更後:

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = etl_visits(fetch_visits(10))
    return render_template('index.html', **context)

次に、file_blob または file_gcs のいずれか(または両方)が存在することを確認します。使用可能なファイルがある場合は、既存のファイルを選択して、その識別子(Blobstore で作成されたファイルの場合は BlobKey、Cloud Storage で作成されたファイルの場合はファイル名)を使用します。「Cloud Storage で作成されたファイル」とは、Cloud Storage クライアント ライブラリを使用して作成されたファイルを意味します。Blobstore は Cloud Storage にも書き込みますが、この場合は Blobstore で作成されたファイルになります。

さらに重要なのは、エンドユーザーのデータを正規化または ETL(抽出、変換、読み込み)するために使用される etl_visits() 関数とは何かということです。たとえば、次のようになります。

def etl_visits(visits):
    return [{
            'visitor': v.visitor,
            'timestamp': v.timestamp,
            'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
                    and v.file_gcs else v.file_blob
            } for v in visits]

おそらく、期待どおりの結果が得られるでしょう。コードはすべてのアクセスをループし、各アクセスについて訪問者とタイムスタンプのデータをそのまま取得し、file_gcs または file_blob が存在するかどうかを確認します。存在する場合は、いずれか 1 つを選択します(どちらも存在しない場合は None を選択します)。

main.pymain-migrate.py の違いを次の図に示します。

718b05b2adadb2e1.png

Blobstore で作成されたファイルがない状態で最初から始める場合は main.py を使用しますが、移行して Blobstore Cloud Storage の両方で作成されたファイルをサポートする場合は、main-migrate.py をシナリオの処理方法の例として確認し、独自のアプリの移行を計画してください。複雑な移行を行う場合は、特殊なケースが発生する可能性が高いため、この例は、実際のデータを使用して実際のアプリを最新化する際の親和性を示すことを目的としています。

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

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

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

アプリを再デプロイする前に、必ず pip install -t lib -r requirements.txt を実行して、セルフバンドルされたサードパーティ ライブラリを lib フォルダに取得してください。下位互換性のあるソリューションを実行する場合は、まず main-migrate.py の名前を main.py に変更します。gcloud app deploy を実行し、アプリがモジュール 15 アプリと同じように動作することを確認します。フォーム画面は次のようになります。

f5b5f9f19d8ae978.png

[最近の訪問] ページは次のようになります。

f5ac6b98ee8a34cb.png

App Engine Blobstore を Cloud Storage に、App Engine NDB を Cloud NDB に、webapp2 を Flask に置き換えるこの Codelab を完了しました。これで、コードは FINISH(モジュール 16)フォルダの内容と一致するはずです。代替の main-migrate.py もそのフォルダにあります。

Python 3 への「移行」

app.yaml の先頭にある Python 3 の runtime ディレクティブをコメントアウトするだけで、このアプリを Python 3 に移植できます。ソースコード自体はすでに Python 3 と互換性があるため、変更は必要ありません。これを Python 3 アプリとしてデプロイするには、次の手順を行います。

  1. app.yaml の先頭にある Python 3 の runtime ディレクティブのコメントを解除します。
  2. app.yaml の他の行をすべて削除します。
  3. appengine_config.py ファイルを削除します。(Python 3 ランタイムでは使用されません)
  4. lib フォルダが存在する場合は削除します。(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 固有のものです。詳細については、各プロダクトのドキュメントをご覧ください。

モジュール 15 から 16 に移行した場合、Blobstore にデータが残っているため、上記の料金情報に Blobstore の料金情報が含まれています。

次のステップ

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

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 には、考慮すべき移行と、移行モジュールの関連する「順序」に関するガイダンスも記載されています。

7. 参考情報

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

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

移行に関するリソース

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

Codelab

Python 2

Python 3

モジュール 15

コード

なし

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

コード

(Python 2 と同じ)

オンライン リソース

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

App Engine Blobstore と Cloud Storage

App Engine プラットフォーム

その他のクラウド情報

Python

動画

ライセンス

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