[Python] Flask を Google App Engine 上で動作させる

Python の Web フレームワーク Flask を Google App Engine 上で動作させる手順をまとめた自分用メモ。
なお、下記手順を実施するにあたり、多くの部分において以下の記事を参考にさせていただいております。

 - [Flask を Google App Engine で動作させる]
(http://blog.kaneshin.co/entry/2016/09/05/010804)

 - [Google App EngineでFlaskを使うまで]
(http://mw17.hatenablog.jp/entry/2015/09/18/004714)

※ 環境
　macOS Sierra バージョン 10.12.3
　MacBook Air (Early 2014)

###1. Python version 2.7 (anaconda2-4.2.0) をインストール
Google App Engine (SE) では Python version 2.7 を使用する必要がある。なお、自分は先に Django 環境を構築した際、指定したバージョンの anaconda 仮想環境を使えるように設定しているのでそれをこちらでも利用する。
(※ 詳細は下記記事の手順 3 ～ 7 を参照。)
 - [[Python] Django の環境構築 (pyenv + pyenv-virtualenv + Anaconda) for macOS]
(http://qiita.com/togoturns/items/b2ae361a669933c823f5)

以下、続き。

```Terminal:Terminal
$ pyenv global anaconda2-4.2.0 (# 全てのディレクトリに対して、指定したバージョンの仮想環境が設定される)
$ pyenv virtualenv anaconda2-4.2.0 flask001
 (# "flask001" という名前で、バージョン "anaconda2-4.2.0" の仮想環境を新規に作成)
$ python --version (# python のバージョン確認)
    Python 2.7.12 :: Anaconda 4.2.0 (x86_64)  
$ pyenv versions
    system
  * anaconda2-4.2.0
    anaconda3-4.2.0
    flask001
 (# pyenv で指定可能な仮想環境に、"flask001" が追加される)
```

###2. Flask をインストールするディレクトリを作成後、当該ディレクトリに手順 1 で作成した仮想環境を設定
```Terminal:Terminal
$ mkdir myflask (# Flask をインストールをするディレクトリ "myflask" を作成)
$ cd myflask (# "myflask" ディレクトリに移動)
$ pyenv local flask001 (# "myflask" ディレクトリに仮想環境 "flask001" を設定)
$ pyenv versions
    system
    anaconda2-4.2.0
    anaconda3-4.2.0
  * flask001
 (# 指定したディレクトリに移動するだけで、自動的に virtualenv で作成した仮想環境に入ることが可能に)
```

###3. Google Cloud SDK パッケージファイルのダウンロード
下記ページより、Mac OS X（x86_64）用の SDK アーカイブパッケージをダウンロードし、解凍後に展開された全てのファイルを任意のディレクトリ配下に配置。
- [Mac OS X 用のクイックスタート (Cloud SDK のインストール)]
(https://cloud.google.com/sdk/docs/quickstart-mac-os-x)

```Terminal:Terminal
$ cd $HOME
$ mkdir .py_appengine
$ cd .py_appengine

(# ".py_appengine" ディレクトリを作成し、当該ディレクトリ配下にダウンロード・展開した Cloud SDK ファイルを配置)
```

###4. .bash_profile に SDK ディレクトリのパスを追加
```Terminal:Terminal
$ cd $HOME
$ vim ~/.bash_profile (# .bash_profile ファイル内に下記内容を記述)

  # Set path for Python_GoogleAppEngine
  export PATH="$PATH:$HOME/.py_appengine:$HOME/.py_appengine/google-cloud-sdk/platform/google_appengine"
```
```Terminal:Terminal
source ~/.bash_profile (# 設定を反映させる)
```

###5. Google Cloud SDK のインストール
```Terminal:Terminal
$ cd $HOME/.py_appengine
$ ./google-cloud-sdk/install.sh (# install.sh を実行して SDK を初期化)

  # "You must log in to continue. Would you like to log in (Y/n)?"
  # "Y" を入力するとブラウザーが起動し、Google Cloud Platformページが開く。
  # ログインすると Google Cloud SDK の認証完了。

$ ./google-cloud-sdk/bin/gcloud init (# gcloud init を実行して SDK を初期化)
```

###6. Flask のインストール
```Terminal:Terminal
$ cd $HOME/myflask
$ mkdir lib (# Flask のインストール先として、lib ディレクトリを作成)
$ pip install -t lib flask (# lib ディレクトリに Flask をインストール)
```

###7. lib ディレクトリと同じ階層に 3 ファイルを配置
github 上にある 3 ファイルをダウンロードし、lib ディレクトリと同じ階層に置く。(※ ここでは "myflask" ディレクトリ配下に配置。また 3 ファイル共、デフォルト設定のまま使用)

- [A skeleton for creating Python applications using the Flask framework on App Engine]
(https://github.com/GoogleCloudPlatform/appengine-flask-skeleton)

```Terminal:
myflask
 |_ lib/
 |_ app.yaml - (1)
 |_ appengine_config.py - (2)
 |_ main.py - (3)
```

 (1) app.yaml ファイル
　App Engine へのリクエストハンドラや静的ファイルへのパス・アプリケーションの設定を記述。

```Terminal:Terminal
$ cd $HOME/myflask
```

```Terminal:[app.yaml]
# This file specifies your Python application's runtime configuration
# including URL routing, versions, static file uploads, etc. See
# https://developers.google.com/appengine/docs/python/config/appconfig
# for details.

runtime: python27
api_version: 1
threadsafe: yes

# Handlers define how to route requests to your application.
handlers:

# App Engine serves and caches static files contained in the listed directories
# (and subdirectories). Uncomment and set the directory as needed.
#- url: /client
#  static_dir: client

# This handler tells app engine how to route requests to a WSGI application.
# The script value is in the format <path.to.module>.<wsgi_application>
# where <wsgi_application> is a WSGI application object.
- url: .*  # This regex directs all routes to main.app
  script: main.app

# Third party libraries that are included in the App Engine SDK must be listed
# here if you want to use them.  See
# https://developers.google.com/appengine/docs/python/tools/libraries27 for
# a list of libraries included in the SDK.  Third party libs that are *not* part
# of the App Engine SDK don't need to be listed here, instead add them to your
# project directory, either as a git submodule or as a plain subdirectory.
# TODO: List any other App Engine SDK libs you may need here.
#libraries:
#- name: jinja2
#  version: latest
```

 (2) appengine_config.py ファイル
　lib ディレクトリを App Engine の実行時にロードするための設定を記述。

```Terminal:[appengine_config.py]
# `appengine_config.py` is automatically loaded when Google App Engine
# starts a new instance of your application. This runs before any
# WSGI applications specified in app.yaml are loaded.
from google.appengine.ext import vendor

# Third-party libraries are stored in "lib", vendoring will make
# sure that they are importable by the application.
vendor.add('lib')
```

 (3) main.py ファイル
　ファイル内に Flask をインポートし、ルーティングのための設定を記述。

```Terminal:[main.py]
# `main` is the top level module for your Flask application.

# Import the Flask Framework
from flask import Flask
app = Flask(__name__)
# Note: We don't need to call run() since our application is embedded within
# the App Engine WSGI application server.

@app.route('/')
def hello():
    """Return a friendly HTTP greeting."""
    return 'Hello World!'

@app.errorhandler(404)
def page_not_found(e):
    """Return a custom 404 error."""
    return 'Sorry, Nothing at this URL.', 404

@app.errorhandler(500)
def application_error(e):
    """Return a custom 500 error."""
    return 'Sorry, unexpected error: {}'.format(e), 500
```
(参照)
　- [[Python] デコレーターに入門する]
(http://www.yoheim.net/blog.php?q=20160607)

###8. ローカル環境での動作確認

```Terminal:Terminal
$ dev_appserver.py . (# App Engine の SDK の中にある dev_appserver.py ファイルを実行)

  # "Do you want to continue (Y/n)?" と表示されたら "y" を入力
```
コマンド実行後、ブラウザーのアドレス欄に "http://localhost:8080" を入力。"Hello World!" と表示されれば成功。

###9. Google Cloud Platform 管理画面でプロジェクトを作成
Google Cloud Platform ページにサインインし、管理画面からデプロイするプロジェクトを作成する。

　1) [Google Cloud Platform 管理画面 (ダッシュボード)] (https://console.cloud.google.com/home/dashboard) にサインイン
　2) 画面左上のハンバーガーメニュー (ツールとサービス) をクリック
　3) "IAM と管理" をクリック
　4) "すべてのプロジェクト" をクリック
　5) "+ プロジェクトを作成" をクリック
　6) "新しいプロジェクト" にプロジェクト名を入力し、"作成" をクリック
　7) 新規作成されたプロジェクトに割り当てられた <プロジェクト ID> をコピー

###10. Google App Engine にデプロイ

```Terminal:Terminal
$ open https://appengine.google.com/start (# App Engine サイトにサインインし、先にプロジェクトで利用する App Engine リソースを作成 ※"asia-northeast1" を選択)

$ appcfg.py update -A <プロジェクト ID> -V v1 . (# <プロジェクト ID> には手順 9 で用意したプロジェクト ID を入力)

<参考>
# 初めてのデプロイではない場合、先に下記コマンドを実行して当該プロジェクトをデフォルトに設定した後、あらためて上記コマンドを実施
$ appcfg.py set_default_version -V v1 -A <プロジェクト ID>
```
コマンド実行後、ブラウザーのアドレス欄に "https://<プロジェクト ID>.appspot.com" を入力。"Hello World!" と表示されれば成功。

(参照)
　- [GCPのAEでGoの環境設定のメモ]
(http://qiita.com/mgoldchild/items/4934819f91cc628f3b1f)