GCP - App Engine の概要

# App Engine の概要
App Engine アプリは、1 つ以上のサービスからなる単一のアプリケーション リソースで構成されます。各サービスは、それぞれ異なるランタイムを使用したり、異なるパフォーマンス設定で動作したりするように構成できます。各サービス内で、そのサービスの複数のバージョンをデプロイします。デプロイされた各バージョンは、そのバージョンに構成したトラフィックの処理量に応じて、1 つ以上のインスタンス内で実行されます。

「[App Engine の概要](https://cloud.google.com/appengine/docs/standard/python3/an-overview-of-app-engine?hl=ja)」より抜粋

#### [アプリケーションのコンポーネント](https://cloud.google.com/appengine/docs/standard/python3/an-overview-of-app-engine?hl=ja#components_of_an_application)
アプリケーション リソースを作成すると、Google Cloud プロジェクト内に App Engine アプリケーションが作成されます。App Engine アプリケーションは、アプリを構成するサービス、バージョン、およびインスタンスのリソースを格納する最上位のコンテナです。App Engine アプリケーションを作成すると、アプリコードや、設定、認証情報、アプリのメタデータなどのすべてのリソースが、選択したリージョン内に作成されます。

各 App Engine アプリケーションには、少なくとも 1 つのサービス（default サービス）が含まれています。このサービスのバージョンは、いくつでも保持できます。
Datastore など、他の Google Cloud サービスは App Engine アプリ全体で共有されます。

#### [サービス](https://cloud.google.com/appengine/docs/standard/python3/an-overview-of-app-engine?hl=ja#services)
App Engine 内のサービスを使用することで、大規模なアプリを論理コンポーネントに分解できます。これらのコンポーネントは、App Engine の機能を安全な方法で共有し、相互に通信できます。通常、App Engine サービスはマイクロサービスのように動作します。そのため、アプリ全体を単一のサービスで実行したり、複数のサービスを設計およびデプロイして、一連のマイクロサービスとして実行したりできます。

#### [バージョン](https://cloud.google.com/appengine/docs/standard/python3/an-overview-of-app-engine?hl=ja#versions)
サービス内にアプリの複数のバージョンを用意することで、ロールバック用、テスト用、その他の一時的なイベント用といった、アプリの各種バージョンをすばやく切り替えることができます。

#### [インスタンス](https://cloud.google.com/appengine/docs/standard/python3/an-overview-of-app-engine?hl=ja#instances)
サービスに含まれる各バージョンは、1 つ以上のインスタンスで実行されます。 デフォルトでは、App Engine は負荷に合わせてアプリのスケーリングを行います。アプリは、稼働中のインスタンスの数を増やしてパフォーマンスの一貫性を確保し、アイドル状態のインスタンスを最小限に減らしてコストを抑えます。

#### [アプリケーション リクエスト](https://cloud.google.com/appengine/docs/standard/python3/an-overview-of-app-engine?hl=ja#application_requests)

アプリの各サービスの名前やサービス内の各バージョンの名前は、一意でなければなりません。こうした一意の名前は、URL によってトラフィックを特定のリソースにターゲット指定およびルーティングするために使用できます。次に例を示します。

`https://VERSION_ID-dot-SERVICE_ID-dot-PROJECT_ID.REGION_ID.r.appspot.com`

# Python 3 ランタイム用の構成ファイルの準備
App Engine スタンダード環境の Python 3 ランタイムでアプリを実行する前に、App Engine で使用する構成ファイル(`app.yaml`)の一部を変更する必要がある。
※`app.yaml` ファイルには、ランタイムや最新バージョンの ID など、アプリのコードに関する情報が含まれる。
「[Python 3 ランタイム用の構成ファイルの準備](https://cloud.google.com/appengine/docs/standard/python/migrate-to-python3/config-files?hl=ja)」より抜粋
#### [app.yaml の更新](https://cloud.google.com/appengine/docs/standard/python/migrate-to-python3/config-files?hl=ja#updating_appyaml)
非推奨のフィールドを使用すると、App Engine はアプリをデプロイするときにエラーを返す。

#### [app.yaml 構成ファイルの詳細情報](https://cloud.google.com/appengine/docs/standard/python3/config/appref?hl=ja#entrypoint)
App Engine アプリの設定は app.yaml ファイルで構成します。 app.yaml ファイルには、ランタイムや最新バージョンの ID など、アプリコードについての情報も記載されています。

アプリ内の各サービスにはそれぞれ独自の app.yaml ファイルがあり、デプロイ記述子として機能します。アプリ内の追加サービス用に app.yaml ファイルを作成してデプロイする際は、事前に default サービス用の app.yaml ファイルを作成する必要があります。

Python 3.7 では、app.yaml には少なくとも runtime: python3 エントリを含める必要があります。概要については、ランタイム設定の定義をご覧ください。

# 依存関係の指定
Python アプリケーションの依存関係は標準 requirements.txt ファイルで宣言されています。

```requirements.txt
Flask==0.10.1
google-cloud-storage
```
App Engine にデプロイすると、デプロイしたアプリと合わせて、`requirements.txt` ファイルで指定した**依存関係が自動的にインストール**されます。Linux 対応の任意の Python パッケージを利用できます。これにはネイティブの C 拡張機能を必要とするパッケージも含まれます。

**デフォルトでは、App Engine は取得した依存関係をキャッシュに保存し、ビルド時間を短縮**します。キャッシュに保存されていないバージョンの依存関係をインストールするには、次のコマンドを使用します。

```
gcloud beta app deploy --no-cache
```

#### [プライベート依存関係](https://cloud.google.com/appengine/docs/standard/python3/specifying-dependencies?hl=ja#private_dependencies)
依存関係は、SSH キーにはアクセスできない Cloud Build 環境にインストールされます。
SSH ベースの認証を必要とするリポジトリでホストされているパッケージは、プロジェクト ディレクトリにコピーし、pip パッケージ マネージャーを使用してプロジェクト コードと一緒にアップロードする必要があります。
1. `pip install -t lib my_module` を実行して、lib という名前のローカル フォルダに依存関係をコピー。
2. 空の `__init__.py` ファイルを lib ディレクトリに追加して、モジュールに変換
3. モジュールをアプリにインポート

```sample.py
import lib.my_module
```

- [依存関係をローカルにインストールする](https://cloud.google.com/appengine/docs/standard/python3/specifying-dependencies?hl=ja#installing_dependencies_locally)  
 アプリケーションをローカルで開発してテストする場合、アプリケーションの依存関係をシステム パッケージから分離するために、venv を使用することをおすすめします。これにより、依存関係がローカルマシンとデプロイしたアプリケーションで確実に同じバージョンが使用されるようにすることもできます。

```
# プロジェクトの外部のディレクトリに隔離された Python 環境を作成して有効化
python3 -m venv env
source env/bin/activate
# プロジェクト ディレクトリに移動し、依存関係をインストール
cd YOUR_PROJECT
pip install  -r requirements.txt
```

こうすることでアプリをローカルで実行するときに、`requirements.txt` ファイルで宣言されている依存関係のみが使用できるようになります。デプロイ中に App Engine によってインストールされる依存関係は、env/ ディレクトリの内容ではなく、`requirements.txt` ファイルの内容に基づいています。

#### [ウェブ フレームワークのインストール](https://cloud.google.com/appengine/docs/standard/python3/specifying-dependencies?hl=ja#installing_a_web_framework)
アプリでウェブ リクエストに対応できるようにするには、ウェブ フレームワークを使用する必要があります。 
以下を含む任意の Python ウェブ フレームワークを使用できます。

- Flask
- Django
- Pyramid
- Bottle
- web.py
- Tornado

特定のウェブ フレームワークを使用するには、次のように requirements.txt に追加します。

```requirements.txt
Flask==0.10.1
```

「[依存関係の指定](https://cloud.google.com/appengine/docs/standard/python3/specifying-dependencies?hl=ja)」より抜粋

#### [WSGI サーバーをインストールする](https://cloud.google.com/appengine/docs/standard/python3/specifying-dependencies?hl=ja#installing_a_wsgi_server)

```requirements.txt
uwsgi==2.0.18
flask==1.1.2
```

# cron.yaml を使用したジョブのスケジューリング
App Engine Cron サービスを使用すると、指定した時刻または一定間隔で動作する定期スケジュール タスクを構成できます。これらのタスクは、一般的に cron ジョブと呼ばれます。cron ジョブは App Engine Cron サービスによって自動的にトリガーされます。これを使用して、レポートメールを毎日送信する、キャッシュ データを 10 分ごとに更新する、概要情報を 1 時間に 1 回更新するといったことを実現できます。

cron ジョブは、HTTP GET リクエストを使用して、1 日のうちの決められた時刻に URL を呼び出します。cron によって呼び出される HTTP リクエストは最大 60 秒間実行でき、他の HTTP リクエストと同じ期限が適用されます。

「[cron.yaml を使用したジョブのスケジューリング](https://cloud.google.com/appengine/docs/standard/python3/scheduling-jobs-with-cron-yaml?hl=ja)」より抜粋

# スタンダード環境
App Engine スタンダード環境では、リクエストを複数のサーバーに分散でき、トラフィック需要に合わせてサーバーがスケーリングされます。サーバーのハードウェア、オペレーティング システム、物理的な場所に関係なく、安全性と信頼性の高い独自の環境でアプリケーションが実行されます。

「[App Engin スタンダード環境](https://cloud.google.com/appengine/docs/standard?hl=ja)」より抜粋

# スタンダード環境の言語とランタイム
Python 3.7 ランタイムは、ウェブサービスのコードとその依存関係をインストールしてサービスを実行する役割を果たすソフトウェア スタックです。

スタンダード環境の App Engine 用 Python 3.7 ランタイムは、app.yaml ファイル内で次のように宣言されています。

```app.yaml
runtime: python37
```
#### Python 3 バージョン
Python 3.7 ランタイム環境では、最新の安定版である Python 3.7 が使用されています。 App Engine ではデプロイ時に新しいマイナー リビジョンに自動的に更新されますが、メジャー バージョンの更新は自動的に行われません。
#### 依存関係
デプロイ時に、App Engine は Python パッケージ マネージャー pip を使用して、プロジェクトのルート ディレクトリにある requirements.txt メタデータ ファイルで定義された依存関係をインストールします。依存関係は App Engine によって新しくインストールされるため、アップロードする必要はありません。

Pipfile / Pipfile.lock スタンダードを使用した依存関係の指定は現在サポートされていないため、プロジェクトではこれらのファイルを使用できません。

#### アプリケーションの起動
ランタイムは、app.yaml ファイルのオプションのエントリポイント フィールドの内容を使用してアプリケーションを起動します。

```app.yaml
runtime: python37
entrypoint: gunicorn -b :$PORT main:app
```
アプリで HTTP リクエストを受信するには、エントリポイントで、PORT 環境変数で指定されたポートでリッスンするウェブサーバーを起動する必要があります。エントリポイントを使用するかどうかは選択できます。アプリが以下の条件を満たしていれば、App Engine は gunicorn をウェブサーバーとして使用し、そのパッケージを自動的に requirements.txt ファイルに追加します。
1. アプリのディレクトリのルートに、`app` という WSGI 準拠のオブジェクトが設定された `main.py` ファイルが格納されている。
2. `app.yaml` にエントリポイント フィールドが含まれていない。
3. アプリに `Pipfile` ファイルまたは `Pipfile.lock` ファイルが含まれていない。

「[Python 3 ランタイム環境](https://cloud.google.com/appengine/docs/standard/python3/runtime?hl=ja)」より抜粋

#### エントリポイントのおすすめの方法
エントリポイントを指定しない場合は`requirements.txt` ファイルに `gunicorn` を含めない。
パフォーマンスの観点から、エントリポイントを軽量化することが重要です。
エントリポイントはアプリケーションの新しいインスタンスが作成されるたびに実行されるからです。

エントリポイント フィールドを使用して、アプリのパフォーマンスを調整できます。
たとえば、gunicorn をウェブサーバーとして使用する場合は、エントリポイント フィールドで --workers フラグ を使用して、アプリを処理するワーカーの数を構成できます。
(指定するワーカーの数は、App Engine アプリのインスタンス クラスと一致する必要があり。)

「[エントリポイントのおすすめの方法](https://cloud.google.com/appengine/docs/standard/python3/runtime?hl=ja#entrypoint_best_practices)」より抜粋

#### 環境変数
app.yaml ファイル内で追加の環境変数を定義できますが、NODE_ENV 以外、上記値のオーバーライドはできない。

「[環境変数](https://cloud.google.com/appengine/docs/standard/python3/runtime?hl=ja#environment_variables)」より抜粋

#### メタデータ サーバー
アプリケーションの各インスタンスは、App Engine メタデータ サーバーを使用してインスタンスとプロジェクトに関する情報を照会できる。

「[メタデータ サーバー](https://cloud.google.com/appengine/docs/standard/python3/runtime?hl=ja#metadata_server)」より抜粋