Python ランタイム

概要

Python ランタイムは、アプリケーションのコードと依存関係をインストールしてアプリケーションを実行するためのソフトウェア スタックです。標準ランタイムは、次のように app.yaml 内で runtime: python として宣言されます。

runtime: python
env: flex

フレキシブル環境のランタイムは、Docker を使用してビルドされています。Python ランタイムは Ubuntu 16.04 に基づいています。Python ランタイムのソースコードは、GitHub で公開されています。

インタプリタ

デフォルトのインタプリタは Python 2.7.9 です。アプリケーションの app.yamlruntime_config を設定することで、Python 2 と Python 3 のどちらを使用するかを指定できます。

runtime: python
env: flex

runtime_config:
    python_version: 3

サポートされているインタプリタのバージョンは次のとおりです。

  • Python 2.7.9。2 と指定します。
  • Python 3.7.2。3 と指定します。

依存関係

ランタイムは、アプリケーションを起動する前に、アプリケーションのソース ディレクトリで requirements.txt ファイルを検索し、pip を使用して依存関係をインストールします。パッケージの宣言と管理については、Python ライブラリの使用をご覧ください。

Python での C ライブラリの使用

C 拡張を必要とする Python パッケージを使用できるように、現在の Python バージョンと次の Ubuntu パッケージのヘッダーがあらかじめシステムにインストールされています。

これらのパッケージを使用すると、よく利用されている Python ライブラリをインストールできます。アプリケーションで追加のオペレーティング システムレベルの依存関係が必要な場合は、このランタイムに基づいてカスタム ランタイムを使用し、適切なパッケージをインストールする必要があります。

アプリケーションの起動

ランタイムは、app.yaml で定義された entrypoint を使用してアプリケーションを起動します。エントリ ポイントは、環境変数 PORT で定義されたポートで HTTP リクエストのレスポンス処理を開始する必要があります。

ほとんどのウェブ アプリケーションは、GunicornuWSGIWaitress などの WSGI サーバーを使用します。

これらのサーバーのいずれかを使用する前に、それらのサーバーをアプリケーションの requirements.txt に依存関係として追加する必要があります。ランタイムは、エントリ ポイントが呼び出される前に、すべての依存関係がインストールされていることを確認します。

Flask==0.10.1
gunicorn==19.3.0

Flask アプリケーションで gunicorn を使用したエントリ ポイントの例:

entrypoint: gunicorn -b :$PORT main:app

Django アプリケーションで gunicorn を使用したエントリ ポイントの例:

entrypoint: gunicorn -b :$PORT mydjangoapp:wsgi

Gunicorn はおすすめの WSGI サーバーですが、他の WSGI サーバーを使用することもできます。たとえば、Flask で uWSGI を使用するエントリ ポイントの例を示します。

entrypoint: uwsgi --http :$PORT --wsgi-file main.py --callable app

WSGI サーバーなしでリクエストを処理できるアプリケーションの場合には、Python スクリプトを実行します。

entrypoint: python main.py

上のエントリ ポイントの例は基本的なものにすぎませんが、お使いのウェブ アプリケーションが機能する可能性はあります。ただしほとんどのアプリケーションでは WSGI サーバーの構成がさらに必要となります。エントリ ポイントにすべての設定を指定する代わりに、プロジェクト ルート ディレクトリ(app.yaml がある場所)に gunicorn.conf.py ファイルを作成し、これをエントリ ポイントに指定します。

entrypoint: gunicorn -c gunicorn.conf.py -b :$PORT

Gunicorn の構成値の詳細については、Gunicorn のドキュメントをご覧ください。

ワーカー

Gunicorn は、リクエストの処理にワーカーを使用します。デフォルトでは、Gunicorn はシンクワーカーを使用します。このワーカークラスはすべてのウェブ アプリケーションと互換性がありますが、各ワーカーは一度に 1 つのリクエストしか処理できません。デフォルトでは、gunicorn はこれらのワーカーの 1 つを使用します。このため、インスタンスが十分に活用されず、負荷の高いアプリケーションではレイテンシが長くなることが少なくありません。

インスタンスの CPU コア数を 2~4 倍して 1 を加えた数に設定することをおすすめします。gunicorn.conf.py で次のように指定します。

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1

さらに、ほとんどの I/O がバインドされているウェブ アプリケーションの中には、別のワーカークラスを使用することでパフォーマンスが向上するものもあります。ワーカークラスが gevent や tornado などの依存関係を必要とする場合、その依存関係をアプリケーションの requirements.txt で宣言する必要があります。

HTTPS プロキシと転送プロキシ

App Engine はロードバランサで HTTPS 接続を終了し、リクエストをアプリケーションに転送します。ほとんどのアプリケーションは、リクエストが HTTPS 経由で送信されたかどうかを確認する必要がありません。この情報が必要なアプリケーションは、gunicorn.conf.py で App Engine プロキシを信頼するように Gunicorn を構成する必要があります。

forwarded_allow_ips = '*'
secure_scheme_headers = {'X-Forwarded-Proto': 'https'}

これにより、Gunicorn は wsgi.url_scheme'https' にします。大半のウェブ フレームワークは、これを使用してリクエストの安全性を示します。WSGI サーバーまたはフレームワークがこの機能をサポートしていない場合は、X-Forwarded-Proto ヘッダーの値を手動で確認ください。

一部のアプリケーションでは、ユーザーの IP アドレスの確認が必要になります。これは、X-Forwarded-For ヘッダーにあります。

ランタイムの拡張

標準の Python ランタイムからカスタム ランタイムを作成できます。カスタム ランタイムは Dockerfile で構成します。gen-config を使用して、標準の Python ランタイムに基づく Dockerfile を生成できます。

gcloud beta app gen-config --custom

Dockerfile.dockerignore を必要に応じてカスタマイズします。最後に、app.yamlruntime: python の代わりに runtime: custom を指定します。詳細については、Python ランタイムのカスタマイズをご覧ください。

環境変数

次の環境変数が、ランタイム環境によって設定されます。

環境変数 説明
GAE_INSTANCE 現在のインスタンスの名前。
GAE_MEMORY_MB アプリケーション プロセスで使用可能なメモリ量。
GAE_SERVICE アプリケーションの app.yaml ファイルで指定されたサービス名。サービス名が指定されていない場合は、default に設定されます。
GAE_VERSION 現在のアプリケーションのバージョン ラベル。
GOOGLE_CLOUD_PROJECT アプリケーションに関連付けられたプロジェクト ID。この ID は、Google Cloud Platform Console に表示されます。
PORT HTTP リクエストを受信するポート。

その他の環境変数は app.yaml で設定できます。

メタデータ サーバー

アプリケーションのインスタンスは、ホスト名、外部 IP アドレス、インスタンス ID、カスタム メタデータ、サービス アカウント情報など、インスタンスに関する情報を Compute Engine メタデータ サーバーから取得します。App Engine では、インスタンスごとにカスタム メタデータを設定することはできませんが、プロジェクト単位のカスタム メタデータを設定して、App Engine インスタンスや Compute Engine インスタンスから読み取ることができます。

次のサンプル関数では、メタデータ サーバーからインスタンスの外部 IP アドレスを取得します。

METADATA_NETWORK_INTERFACE_URL = \
    ('http://metadata/computeMetadata/v1/instance/network-interfaces/0/'
     'access-configs/0/external-ip')

def get_external_ip():
    """Gets the instance's external IP address from the Compute Engine metadata
    server. If the metadata server is unavailable, it assumes that the
    application is running locally.
    """
    try:
        r = requests.get(
            METADATA_NETWORK_INTERFACE_URL,
            headers={'Metadata-Flavor': 'Google'},
            timeout=2)
        return r.text
    except requests.RequestException:
        logging.info('Metadata server could not be reached, assuming local.')
        return 'localhost'