App Engine フレキシブル環境に Python Flask ウェブ アプリケーションをデプロイする

概要

この Codelab では、Python Flask ウェブ アプリケーションを App Engine フレキシブル環境にデプロイする方法について学びます。デプロイするアプリケーションはサンプル アプリケーションです。人の顔写真をアップロードして、その人が楽しい気分である可能性を調べることができます。このアプリケーションは、Vision、Storage、Datastore の Google Cloud API を使用しています。

App Engine について

Google App Engine アプリケーションは作成や管理が簡単で、トラフィックやデータ ストレージの需要の変動に合わせて容易にスケーリングできます。App Engine 環境では、サーバーを管理する手間がかかりません。必要な作業は、アプリケーションをアップロードすることだけです。

App Engine のアプリケーションは、受信したトラフィック量に応じて自動的にスケーリングします。また、App Engine はロード バランシングやマイクロサービス、認証、SQL データベース、NoSQL データベース、トラフィック分散、ロギング、検索、バージョニング、ロールアウトとロールバック、セキュリティ スキャニングにネイティブに対応しており、どれも高度にカスタマイズすることができます。

App Engine のフレキシブル環境は、C#、Go、Java、Node.js、PHP、Python、Ruby のすべてのプログラミング言語をサポートしています。App Engine フレキシブル環境では、Google Compute Engine 仮想マシンで実行されている Docker コンテナ内でアプリケーションが実行されます。App Engine のスタンダード環境は、Python などの一部の言語に対応しています。App Engine スタンダードは、より制限の厳しいサンドボックス環境でアプリケーションを実行します。詳しくは、App Engine 環境の選択をご確認ください。

学習内容

  • App Engine フレキシブル環境にシンプルなウェブ アプリケーションをデプロイする方法
  • Vision、Storage、Datastore の Google Cloud クライアント ライブラリにアクセスする方法
  • Google Cloud コンソールと Google Cloud SDK を使用してさまざまなクラウド リソースを管理する方法
  • Cloud Shell を使用する方法

必要なもの

  • Python の基本知識があること
  • Linux の標準的なテキスト エディタ(vim、emacs、nano など)を使い慣れていること

プロジェクトの作成

Google アカウント(Gmail または Google Apps)をお持ちでない場合は、1 つ作成する必要があります。Google Cloud Platform のコンソール(console.cloud.google.com)にログインし、新しいプロジェクトを作成します。

プロジェクト ID を忘れないようにしてください。プロジェクト ID はすべての Google Cloud プロジェクトを通じて一意の名前にする必要があります(上記の名前はすでに使用されているので使用できません)。以降、この Codelab では PROJECT_ID と呼びます。

お支払い

次に、Google Cloud リソースを使用するために、Cloud Console で課金を有効にする必要があります。

この Codelab の操作をすべて行って、費用が生じたとしても、少額です。ただし、リソースの使用量を増やしたり、実行したままにしたりすると、費用が増加する可能性があります。

Google Cloud Platform の新規ユーザーは、300 ドル分の無料トライアルをご利用いただけます。

Google Cloud はノートパソコンからリモートで操作できますが、この Codelab では Google Cloud Shell(Cloud 上で動作するコマンドライン環境)を使用します。この Debian ベースの仮想マシンには、必要なすべての開発ツール(gcloudpythonvirtualenvpip など)が用意されています。また、5 GB の永続的なホーム ディレクトリが提供され、Google Cloud で実行されるため、ネットワーク パフォーマンスと認証が大幅に向上します。つまり、この Codelab に必要なのはブラウザだけです(Chromebook でも動作します)。

Google Cloud Shell を有効にするには、デベロッパー コンソールの右上にあるボタンをクリックします(環境のプロビジョニングと接続に若干時間を要します)。

Cloud Shell に接続すると、すでに認証は完了しており、プロジェクトに各自の PROJECT_ID が設定されていることがわかります。

gcloud auth list
Credentialed accounts:
- <myaccount>@<mydomain>.com (active)
gcloud config list project
[core]
Project = <PROJECT_ID>

なんらかの理由でプロジェクトが設定されていない場合は、次のコマンドを実行します。

gcloud config set project <PROJECT_ID>

PROJECT_ID が見つからない場合は、設定手順で使用したプロジェクト ID を確認するか、コンソールのダッシュボードで検索します。

Cloud Shell のコマンドラインで次のコマンドを実行して、GitHub リポジトリのクローンを作成します。

git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

python-docs-samples/codelabs/flex_and_vision ディレクトリに移動します。

cd python-docs-samples/codelabs/flex_and_vision

Vision、Storage、Datastore の各 API を使用する前に、次のコマンドで API を有効にする必要があります。

gcloud services enable vision.googleapis.com
gcloud services enable storage-component.googleapis.com
gcloud services enable datastore.googleapis.com

Vision、Storage、Datastore の各 API にリクエストを送信するには、サービス アカウントの認証情報が必要です。プロジェクトのサービス アカウントの認証情報は、gcloud ツールを使用して生成できます。

PROJECT_ID の環境変数を設定します。[YOUR_PROJECT_ID] は実際のプロジェクト ID に置き換えてください。

export PROJECT_ID=[YOUR_PROJECT_ID]

ローカルでのテストの際に Google Cloud API にアクセスするためのサービス アカウントを作成します。

gcloud iam service-accounts create codelab \
  --display-name "My Codelab Service Account"

新しく作成したサービス アカウントに適切な権限を付与します。

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:codelab@${PROJECT_ID}.iam.gserviceaccount.com \
--role roles/owner

サービス アカウントを作成したら、サービス アカウントキーを生成します。

gcloud iam service-accounts keys create ~/key.json \
--iam-account codelab@${PROJECT_ID}.iam.gserviceaccount.com

このコマンドで、サービス アカウントキーが生成され、ホーム ディレクトリにある key.json という名前の JSON ファイルに保存されます。

生成されたキーの絶対パスを使用して、Cloud Shell でサービス アカウント キーの環境変数を設定します。

export GOOGLE_APPLICATION_CREDENTIALS="/home/${USER}/key.json"

Vision API に対する認証の詳細については、こちらをご確認ください。

仮想環境を起動して依存関係をインストールする

virtualenv を使用して、env という名前の隔離された Python 3 環境を作成します。

virtualenv -p python3 env

新しく作成した env という名前の virtualenv に入ります。

source env/bin/activate

pip を使用して、プロジェクトの依存関係を requirements.txt ファイルからインストールします。

pip install -r requirements.txt

requirements.txt ファイルは、このプロジェクトに必要なパッケージ依存関係のリストです。上のコマンドを実行すると、リストのすべてのパッケージ依存関係がこの virtualenv にダウンロードされます。

App Engine アプリを作成する

次に、以下のコマンドを使用して App Engine インスタンスを作成します。

gcloud app create

ストレージ バケットを作成する

まず、環境変数 CLOUD_STORAGE_BUCKET の値に PROJECT_ID の名前を設定します。(通常は利便性のため、PROJECT_ID と同じ名前をバケットに付けることをおすすめします)。

export CLOUD_STORAGE_BUCKET=${PROJECT_ID}

このアプリケーションでは Cloud Storage バケットを使用します。このバケットは、Cloud Shell から gsutil というツールを使用して作成する必要があります。次のコマンドを実行して、PROJECT_ID と同じ名前のバケットを作成します。

gsutil mb gs://${PROJECT_ID}

アプリケーションを実行する

python main.py

アプリケーションが起動したら、Cloud Shell ツールバーの「ウェブでプレビュー」アイコン をクリックし、[プレビューのポート: 8080] を選択します。

ブラウザのタブが開き、起動したサーバーに接続されます。次のように表示されます。

Screen Shot 2017-02-23 at 7.22.50 PM.png

人物の顔が写っている写真をアップロードしてみてください。[ファイルを選択] ボタンをクリックし、パソコンで画像を選択して、[送信] をクリックします。

写真をアップロードすると、次のように表示されます。

Screen Shot 2017-02-23 at 7.32.08 PM.png

サンプルコードのレイアウト

このサンプルは次のようなレイアウトになっています。

templates/
  homepage.html   /* HTML template that uses Jinja2 */
app.yaml          /* App Engine application configuration file */
main.py           /* Python Flask web application */
requirements.txt  /* List of dependencies for the project */

main.py

この Python ファイルは Flask ウェブ アプリケーションです。このアプリケーションでは、写真(できれば顔の写真)を送信すると、その写真が Cloud Storage に保存され、Cloud Vision API の顔検出機能を使用して分析されます。また、写真の主な情報が Datastore(Google Cloud Platform の NoSQL データベース)に保存されて、ユーザーがウェブサイトを訪れるたびに参照されます。

このアプリケーションは、Storage、Datastore、Vision の Google Cloud Platform クライアント ライブラリを使用しています。これらのクライアント ライブラリを使用すると、任意のプログラミング言語から簡単に Cloud API にアクセスできます。

コードの重要なスニペットについていくつか見てみましょう。

一番上の imports セクションは、コードに必要な各種パッケージをインポートする場所です。Datastore、Storage、Vision の Google Cloud クライアント ライブラリはこちらでインポートします。

from google.cloud import datastore
from google.cloud import storage
from google.cloud import vision

次のコードは、ユーザーがウェブサイトのルート URL にアクセスしたときに実行される処理を表しています。まず、Datastore クライアント ライブラリへのアクセスに使用される Datastore クライアント オブジェクトが作成されます。次に、Datastore に対するクエリが実行されて、種類が Faces のエンティティが取得されます。最後に、HTML テンプレートをレンダリングして、Datastore から抽出した image_entities を変数として渡します。

@app.route('/')
def homepage():
    # Create a Cloud Datastore client.
    datastore_client = datastore.Client()

    # Use the Cloud Datastore client to fetch information from Datastore about
    # each photo.
    query = datastore_client.query(kind='Faces')
    image_entities = list(query.fetch())

    # Return a Jinja2 HTML template and pass in image_entities as a parameter.
    return render_template('homepage.html', image_entities=image_entities)

次に、エンティティがどのように Datastore に保存されるかについて見ていきましょう。Datastore は、Google Cloud の NoSQL データベース ソリューションです。データは「エンティティ」と呼ばれるオブジェクトに保存され、各エンティティに固有の識別「キー」が割り当てられます。このキーは、「種類」と「キー名」の文字列を使用して作成します。種類はエンティティを分類するためのもので、たとえば、写真、人、動物などの種類を作ることができます。

各エンティティには、デベロッパーが定義する複数の「プロパティ」を割り当てることができます。プロパティでは、整数、浮動小数点数、文字列、日付、バイナリデータなど、さまざまな型の値を使用できます。

    # Create a Cloud Datastore client.
    datastore_client = datastore.Client()

    # Fetch the current date / time.
    current_datetime = datetime.now()

    # The kind for the new entity.
    kind = 'Faces'

    # The name/ID for the new entity.
    name = blob.name

    # Create the Cloud Datastore key for the new entity.
    key = datastore_client.key(kind, name)

    # Construct the new entity using the key. Set dictionary values for entity
    # keys blob_name, storage_public_url, timestamp, and joy.
    entity = datastore.Entity(key)
    entity['blob_name'] = blob.name
    entity['image_public_url'] = blob.public_url
    entity['timestamp'] = current_datetime
    entity['joy'] = face_joy

    # Save the new entity to Datastore.
    datastore_client.put(entity)

Storage と Vision のクライアント ライブラリにプログラムでアクセスする方法も Datastore と同様です。「vim」、「emacs」、「nano」 を使用して main.py ファイルを開くと、すべてのサンプルコードを確認できます。

Flask の詳細: http://flask.pocoo.org/

クライアント ライブラリの詳細については、https://googlecloudplatform.github.io/google-cloud-python/ をご覧ください。

homepage.html

Flask ウェブ フレームワークでは、テンプレート エンジンに Jinja2 を使用しています。そのため、main.py から homepage.html に変数と式を渡して、ページがレンダリングされる際に値に置き換えることができます。

Jinja2 の詳細については、http://jinja.pocoo.org/docs/2.9/templates/ をご確認ください。

次の Jinja2 HTML テンプレートは、データベースに写真を送信するためのフォームを表示します。このフォームには、以前に送信された写真も表示され、そのファイル名およびアップロード日時と、Vision API によって検出された顔の人物が楽しい気分である可能性が示されます。

homepage.html

<h1>Google Cloud Platform - Face Detection Sample</h1>

<p>This Python Flask application demonstrates App Engine Flexible, Google Cloud
Storage, Datastore, and the Cloud Vision API.</p>

<br>

<html>
  <body>
    <form action="upload_photo" method="POST" enctype="multipart/form-data">
      Upload File: <input type="file" name="file"><br>
      <input type="submit" name="submit" value="Submit">
    </form>
    
  </body>
</html>

App Engine フレキシブル環境では、アプリケーションのデプロイ構成が記述された app.yaml というファイルが使用されます。このファイルが存在しない場合、App Engine はデプロイ構成の推定を試みますが、このファイルを指定することをおすすめします。

次に、「vim」、「nano」、「emacs」 などの任意のエディタを使用して app.yaml に変更を加えます。ここでは nano エディタを使用します。

nano app.yaml

app.yaml

runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:app

runtime_config:
    python_version: 3

env_variables:
    CLOUD_STORAGE_BUCKET: <your-cloud-storage-bucket>

これは、App Engine フレキシブル環境の Python 3 アプリケーションをデプロイするために必要な基本構成です。App Engine の構成の詳細については、こちらをご覧ください。

app.yaml を開いたら、< your-cloud-storage-bucket > を実際の Cloud Storage バケットの名前に置き換えます。(Cloud Storage バケットの名前を忘れてしまった場合は、Qwiklabs から「GCP プロジェクト ID」をコピーします。これは同じものです)。env_variables セクションでは、アプリケーションのデプロイ後に main.py で使用される環境変数を設定します。

完了したらファイルを保存して閉じます。nano の場合は Ctrl+X キーを押します。次のようなプロンプトが表示されます。

Screen Shot 2017-02-17 at 4.47.12 PM.png

文字 y を入力し、次のプロンプトでもう一度 ENTER キーを押してファイル名を確認します。

Screen Shot 2017-02-24 at 4.18.23 PM.png

gcloud を使用してアプリを App Engine にデプロイします。

gcloud app deploy

アプリケーションがデプロイされたら、ウェブブラウザで https://< PROJECT_ID >.appspot.com を開いて、アプリケーションを確認できます。

概要

このステップでは、Python ウェブ アプリケーションをセットアップして App Engine フレキシブル環境にデプロイしました。

App Engine フレキシブル ウェブ アプリケーションを初めて作成し、デプロイする方法を学習しました。

クリーンアップ

このクイックスタートで使用するリソースに対して Google Cloud Platform アカウントに課金されないようにするには:

  • Cloud Platform Console に移動します。
  • シャットダウンするプロジェクトを選択し、上部の [削除] をクリックします。これにより、プロジェクトの削除がスケジュールされます。

詳細

ライセンス

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