Environnement d'exécution Python

Présentation

L'environnement d'exécution Python est la pile logicielle chargée d'installer le code de l'application et ses dépendances, ainsi que d'exécuter l'application. L'environnement d'exécution standard est déclaré dans le fichier app.yaml en tant que runtime: python :

runtime: python
env: flex

Les environnements d'exécution flexibles sont créés à l'aide de Docker. L'environnement d'exécution Python est basé sur Ubuntu 16.04. Le code source pour l'environnement d'exécution Python est publiquement accessible sur GitHub.

Interpréteur

L'interpréteur par défaut est Python 2.7.9. Dans le fichier app.yaml de l'application, vous pouvez indiquer s'il faut utiliser Python 2 ou Python 3 au moyen du paramètre runtime_config :

runtime: python
env: flex

runtime_config:
    python_version: 3

Les versions suivantes de l'interpréteur sont compatibles :

  • Python 2.7.9 (spécifié par 2)
  • Python 3.7.2 (spécifié par 3)

Dépendances

L'environnement d'exécution recherche un fichier requirements.txt dans le répertoire source de votre application et, avant de démarrer cette dernière, utilise pip pour installer les dépendances. Pour plus d'informations sur la déclaration et la gestion des packages, consultez Utiliser les bibliothèques Python.

Utiliser les bibliothèques C avec Python

Pour permettre l'utilisation de packages Python nécessitant des extensions C, les en-têtes correspondant à la version actuelle de Python ainsi que les packages Ubuntu suivants sont préinstallés sur le système :

Ces packages permettent d'installer les bibliothèques Python les plus populaires. Si votre application possède des dépendances supplémentaires au niveau du système d'exploitation, vous devrez utiliser un environnement d'exécution personnalisé basé sur l'environnement d'exécution standard pour installer les packages appropriés.

Démarrage de l'application

L'environnement d'exécution démarre l'application à l'aide de l'élément entrypoint défini dans app.yaml. Le point d'entrée doit démarrer un processus qui répond aux requêtes HTTP sur le port défini par la variable d'environnement PORT.

La plupart des applications Web utilisent un serveur WSGI, tel que Gunicorn, uWSGI ou Waitress.

Avant de pouvoir utiliser l'un de ces serveurs, vous devez l'ajouter en tant que dépendance dans le fichier requirements.txt de votre application. L'environnement d'exécution s'assure que toutes les dépendances sont installées avant d'appeler votre point d'entrée.

Flask==0.10.1
gunicorn==19.3.0

Voici un exemple de point d'entrée utilisant Gunicorn pour une application Flask :

entrypoint: gunicorn -b :$PORT main:app

Voici un exemple de point d'entrée utilisant Gunicorn pour une application Django :

entrypoint: gunicorn -b :$PORT mydjangoapp:wsgi

Gunicorn est le serveur WSGI recommandé, mais il est tout à fait possible d'utiliser un autre serveur WSGI. Par exemple, voici un point d'entrée qui utilise uWSGI avec Flask :

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

Pour les applications capables de gérer des requêtes sans serveur WSGI, vous pouvez simplement exécuter un script Python :

entrypoint: python main.py

Les exemples élémentaires de points d'entrée présentés ci-dessus sont destinés à servir de points de départ et peuvent convenir à vos applications Web. Cependant, la plupart des applications nécessitent une configuration plus avancée du serveur WSGI. Au lieu de spécifier tous les paramètres du point d'entrée, créez un fichier gunicorn.conf.py dans le répertoire racine de votre projet, dans lequel se trouve le fichier app.yaml, et spécifiez-le dans votre point d'entrée :

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

La documentation Gunicorn vous renseignera davantage sur toutes les valeurs de configuration que vous pouvez définir.

Travailleurs

Gunicorn utilise des travailleurs pour traiter les requêtes. Par défaut, Gunicorn utilise des travailleurs synchrones. Cette classe est compatible avec toutes les applications Web, mais chaque travailleur ne peut gérer qu'une requête à la fois. Par défaut, Gunicorn n'en utilise qu'un. Cette manière de procéder peut souvent entraîner une sous-utilisation des instances et une latence accrue lorsque les applications sont soumises à une charge élevée.

Nous vous recommandons de définir un nombre de travailleurs compris entre 2 et 4 fois le nombre de cœurs de processeur de l'instance, plus un. Vous pouvez le spécifier dans le fichier gunicorn.conf.py comme suit :

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1

De plus, avec certaines applications Web principalement liées aux E/S, vous pouvez constater une amélioration des performances en utilisant une classe de travailleur différente. Si votre classe de nœud de calcul nécessite des dépendances supplémentaires, telles que gevent ou tornado, ces dépendances doivent être déclarées dans le fichier requirements.txt de votre application.

HTTPS et proxy de transfert

App Engine met fin à la connexion HTTPS au niveau de l'équilibreur de charge et transfère la requête à l'application. La plupart des applications n'ont pas besoin de savoir si la requête a été envoyée via HTTPS ou non, mais celles qui ont besoin de ces informations doivent configurer Gunicorn pour approuver le proxy App Engine dans leur fichier gunicorn.conf.py :

forwarded_allow_ips = '*'
secure_scheme_headers = {'X-FORWARDED-PROTO': 'https'}

Gunicorn va maintenant s'assurer que l'élément wsgi.url_scheme est défini sur 'https', ce que la plupart des frameworks Web interpréteront comme indiquant que la requête est sécurisée. Si votre serveur ou framework WSGI ne le permet pas, vérifiez manuellement la valeur de l'en-tête X-Forwarded-Proto.

Certaines applications doivent également vérifier l'adresse IP de l'utilisateur. Cette option est disponible dans l'en-tête X-Forwarded-For.

Le paramètre secure_scheme_headers dans le fichier gunicorn.conf.py doit être en majuscules (par exemple, X-FORWARDED-PROTO), mais les en-têtes que votre code peut lire contiendront à la fois des lettres majuscules et minuscules (par exemple, X-Forwarded-Proto).

Étendre l'environnement d'exécution

L'environnement d'exécution Python standard peut servir de base à la création d'un environnement d'exécution personnalisé. Les environnements d'exécution personnalisés sont configurés à l'aide de fichiers Dockerfile. Vous pouvez générer un fichier Dockerfile basé sur l'environnement d'exécution Python standard à l'aide de gen-config :

gcloud beta app gen-config --custom

Vous pouvez personnaliser Dockerfile et .dockerignore selon vos besoins. Enfin, vous devez spécifier runtime: custom au lieu de runtime: python dans le fichier app.yaml. Pour plus d'informations, consultez Personnaliser l'environnement d'exécution Python.

Variables d'environnement

Les variables d'environnement suivantes sont définies par l'environnement d'exécution :

Variable d'environnement Description
GAE_INSTANCE Le nom de l'instance actuelle.
GAE_MEMORY_MB La quantité de mémoire disponible pour le processus d'application.
GAE_SERVICE Nom du service spécifié dans le fichier app.yaml de votre application. Si aucun nom de service n'est spécifié, il est défini sur default.
GAE_VERSION Libellé de version de l'application en cours.
GOOGLE_CLOUD_PROJECT ID du projet associé à votre application, visible dans Google Cloud Console.
PORT Port qui reçoit les requêtes HTTP.

Vous pouvez définir des variables d'environnement supplémentaires à l'aide du fichier app.yaml.

Serveur de métadonnées

Chaque instance de votre application peut utiliser le serveur de métadonnées Compute Engine pour rechercher des informations sur l'instance, y compris son nom d'hôte, son adresse IP externe, son ID d'instance, ses métadonnées personnalisées et ses informations de compte de service. App Engine ne vous permet pas de définir des métadonnées personnalisées pour chaque instance, mais vous pouvez définir des métadonnées personnalisées à l'échelle du projet et les lire à partir de vos instances App Engine et Compute Engine.

Cet exemple de fonction utilise le serveur de métadonnées pour obtenir l'adresse IP externe de l'instance :

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'