Module 1: Migrer de webapp2 App Engine vers Flask

Cette suite d'ateliers de programmation (tutoriels pratiques à suivre à votre rythme) est destinée à aider les développeurs Google App Engine (standard) à moderniser leurs applications en les guidant tout au long d'une série de migrations. L'étape la plus importante est de délaisser les services groupés de l'environnement d'exécution d'origine, car les environnements d'exécution nouvelle génération sont plus souples et offrent aux utilisateurs davantage d'options de service. Le passage à l'environnement d'exécution nouvelle génération vous permet d'intégrer plus facilement les produits Google Cloud, d'utiliser une plus large gamme de services compatibles et de prendre en charge les versions de langage actuelles.

Ce tutoriel initial illustre les premières étapes de la migration vers le framework Web dans les applications App Engine: passer de webapp2 à Flask. Dans votre application, vous pouvez utiliser n'importe quel framework Web qui gère le routage, mais pour ce tutoriel, nous utilisons Flask car ce produit est largement utilisé par la communauté.

Vous apprendrez à effectuer les tâches suivantes :

  • Utiliser des bibliothèques tierces (intégrées ou autre)
  • Mettre à jour les fichiers de configuration
  • Migrer une application simple depuis webapp2 vers Flask

Prérequis

Enquête

Comment allez-vous utiliser cet atelier de programmation ?

Je vais le lire uniquement Je vais le lire et effectuer les exercices

Le framework webapp a été regroupé à l'origine lorsque App Engine a été lancé sur Python 2.5 en 2008. Quelques années plus tard, il a été remplacé par son successeur webapp2 lorsque l'environnement d'exécution 2.7 a été abandonné en 2013.

Bien que webapp2 (voir les documents) soit toujours présent et puisse être utilisé en dehors d'App Engine en tant que framework Web compatible WSGI, il n'effectue pas par lui-même le routage des requêtes utilisateur vers le code approprié dans l'application. Il s'appuie à la place sur App Engine, les fichiers de configuration et le développeur pour acheminer le trafic Web vers les "gestionnaires" correspondants. Par ailleurs, les principaux avantages de webapp2 étant étroitement liés aux services groupés d'App Engine, ceci a pour effet de le rendre obsolète, même s'il fonctionne sur Python 3 (voir aussi problème lié).

Ce module offre aux professionnels une expérience pratique de la migration d'une application webapp2 simple vers Flask, un framework compatible avec App Engine, et des nombreux autres services en dehors de Google Cloud, qui améliorent considérablement la portabilité des applications. Si Flask n'est pas le framework souhaité pour déplacer votre application, vous pouvez en sélectionner un autre du moment qu'il effectue son propre routage. Cet atelier de programmation présente aux décideurs informatiques (ITDM) et aux développeurs les différentes étapes du processus de migration. Vous pouvez ainsi vous familiariser avec ce processus, quel que soit le framework vers lequel vous effectuez la migration.

Voici les principales étapes de cette migration:

  1. Configuration/Préparation
  2. Ajouter une bibliothèque tierce Flask
  3. Mettre à jour les fichiers de l'application
  4. Mettre à jour le fichier de modèle HTML

Avant de passer à la partie principale du tutoriel, nous allons configurer notre projet, obtenir le code, puis vous (re)familiariser avec la commande gcloud et déployer l'application de base de façon à commencer avec un code fonctionnel.

1. Configurer le projet

En tant que développeur existant, le tableau de bord App Engine affiche probablement déjà les services que vous avez exécutés. Pour les besoins de ce tutoriel, nous vous recommandons de créer un projet ou de réutiliser un projet existant pour ce tutoriel. Assurez-vous que le projet dispose d'un compte de facturation actif et que App Engine (app) est activé.

2. Téléchargez l'application exemple de référence

Le dépôt de migration de GAE contient tout le code dont vous avez besoin. Clonez-le ou téléchargez son fichier ZIP. Pour ce tutoriel, vous allez commencer par le code situé dans le dossier (START) du Module 0, et lorsque vous aurez terminé le tutoriel, votre code devra correspondre à celui situé dans le dossier (FINISH) du Module 1. Si ce n'est pas le cas, vérifiez les différences de façon à passer à l'atelier suivant.

Le dossier du Module 0 doit contenir des fichiers semblables à ceux illustrés par la commande POSIX ls:

$ ls
app.yaml        index.html      main.py

3. (Re)Familiarisez-vous avec les commandes gcloud

Si la commande gcloud n'existe pas encore sur votre ordinateur, installez le SDK Google Cloud et assurez-vous que gcloud est présent dans le chemin d'exécution, puis familiarisez-vous avec les commandes gcloud suivantes:

  1. gcloud components update : mettre à jour le SDK Google Cloud
  2. gcloud auth login : se connecter à votre compte avec identifiants
  3. gcloud config list : répertorier les paramètres de configuration du projet GCP
  4. gcloud config set project PROJECT_ID : définir l'ID du projet GCP
  5. gcloud app deploy : déployer votre application App Engine

Si vous n'avez pas utilisé App Engine avec gcloud récemment, vous devez exécuter les quatre premières commandes (1 à 4) avant de passer aux étapes suivantes. Découvrons-les rapidement.

Tout d'abord, gcloud components update garantit que vous disposez de la dernière version du SDK Cloud. L'exécution de cette commande devrait produire un résultat semblable à celui-ci:

$ gcloud components update

Your current Cloud SDK version is: 317.0.0
You will be upgraded to version: 318.0.0

┌──────────────────────────────────────────────────┐
│        These components will be updated.         │
├──────────────────────────┬────────────┬──────────┤
│           Name           │  Version   │   Size   │
├──────────────────────────┼────────────┼──────────┤
│ Cloud SDK Core Libraries │ 2020.11.06 │ 15.5 MiB │
│ gcloud cli dependencies  │ 2020.11.06 │ 10.6 MiB │
└──────────────────────────┴────────────┴──────────┘

The following release notes are new in this upgrade.
Please read carefully for information about new features, breaking changes,
and bugs fixed.  The latest full release notes can be viewed at:
  https://cloud.google.com/sdk/release_notes

318.0.0 (2020-11-10)

      . . .
      (release notes)
      . . .

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce.

Do you want to continue (Y/n)?

╔════════════════════════════════════════════════════════════╗
╠═ Creating update staging area                             ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Cloud SDK Core Libraries                   ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: gcloud cli dependencies                    ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Cloud SDK Core Libraries                     ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: gcloud cli dependencies                      ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Creating backup and activating new installation          ═╣
╚════════════════════════════════════════════════════════════╝

Performing post processing steps...done.

Update done!

To revert your SDK to the previously installed version, you may run:
  $ gcloud components update --version 317.0.0

Ensuite, utilisez gcloud auth login pour vous authentifier pour les commandes gcloud que vous déclencherez:

$ gcloud auth login
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id= . . .

You are now logged in as [YOUR_EMAIL].
Your current project is [PROJECT_ID].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID

Utilisez gcloud config list pour afficher les paramètres actuels de votre projet:

$ gcloud config list
[core]
account = YOUR_EMAIL
disable_usage_reporting = False
project = PROJECT_ID

Your active configuration is: [default]

La commande ci-dessus vous indique comment créer un projet ou sélectionner un projet existant. Si la sortie de gcloud config list ne correspond pas au projet sélectionné que vous souhaitez utiliser pour ce tutoriel, exécutez gcloud config set project PROJECT_ID pour définir l'ID du projet. Vérifiez ensuite que l'ID du projet est défini en exécutant à nouveau la commande gcloud config list.

$ gcloud config set project PROJECT_ID
Updated property [core/project].

Si vous préférez utiliser Cloud Console, vous pouvez suivre l'interface utilisateur pour créer un projet si vous le souhaitez ou utiliser un projet préexistant. Dans le tableau de bord de votre projet, vous devez voir la fiche info qui contient son ID (ainsi que le nom et le numéro du projet):

Fiche info concernant le projet

La dernière commande (5), gcloud app deploy, sert à déployer votre application sur App Engine. Comme nous n'en sommes qu'au début, vous pouvez vous abstenir de déployer le code du Module 0 maintenant. Toutefois nous conseillons quand même de le faire pour vérifier qu'il fonctionne. Lors de l'exécution, sélectionnez la région géographique dans laquelle vous souhaitez exécuter l'application (généralement votre emplacement). Cependant, vous ne pourrez pas en changer une fois définie. Consultez ensuite les autres informations de déploiement. Une fois l'opération terminée, l'URL à laquelle votre application sera diffusée s'affiche. Voici une version abrégée de ce que vous pouvez voir:

$ gcloud app deploy
Services to deploy:

descriptor:      [/private/tmp/mod0-baseline/app.yaml]
source:          [/private/tmp/mod0-baseline]
target project:  [PROJECT_ID]
target service:  [default]
target version:  [20201116t220827]
target url:      [https://PROJECT_ID.REG_ABBR.r.appspot.com]

Do you want to continue (Y/n)?

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://PROJECT_ID.REG_ABBR.r.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse

Si vous n'avez pas utilisé App Engine depuis un certain temps, vous remarquerez peut-être que la commande appcfg.py update de déploiement initial a été remplacée par gcloud app deploy. Pour en savoir plus sur gcloud app deploy, consultez sa page de documentation.

Une autre modification récente est l'URL des applications déployées, passée de http://PROJECT_ID.appspot.com à http://PROJECT_ID.REG_ABBR.r.appspot.com. La plupart des applications seront finalement converties au nouveau format. Pour plus d'informations sur le format des URL, consultez la documentation sur les requêtes et le routage.

Une fois l'application déployée, actualisez le navigateur (plusieurs fois) pour voir les dernières visites:

Application Visitme

S'il s'agit d'une nouvelle application, vous ne verrez qu'une ou quelques visites.

Le moteur d'exécution d'App Engine Python 2 fournit un ensemble de bibliothèques tierces intégrées qu'il vous suffit de spécifier dans votre fichier app.yaml pour les utiliser. Bien que leur utilisation ne soit pas nécessaire avec cette migration, elles le seront pour le prochain tutoriel de migration (Module 2).

Les bibliothèques tierces qui ne sont pas intégrées doivent être spécifiées dans un fichier appelé requirements.txt et installé localement dans le dossier lib du même répertoire que le code de l'application où tout est importé dans App Engine. Pour plus d'informations, consultez la documentation sur le regroupement de bibliothèques tierces.

Les bibliothèques copiées telles que Flask nécessitent de demander à App Engine de les rechercher dans le dossier lib à l'aide du fichier de configuration appengine_config.py. Le fichier de configuration appengine_config.py est placé dans le même dossier d'application de premier niveau que requirements.txt et lib. Dans cette partie du tutoriel, vous allez effectuer les opérations suivantes:

  • Créer requirements.txt (précisez s'il s'agit d'une bibliothèque tierce copiée)
  • Créer appengine_config.py (reconnaissance des bibliothèques tierces)
  • Installer des packages et des dépendances tiers

1. Créer requirements.txt

Créez un fichier requirements.txt pour spécifier vos packages. Dans notre cas, Flask est la bibliothèque tierce nécessaire. Au moment de la rédaction de cet article, la dernière version est la 1.1.2. Vous devez donc créer requirements.txt avec cette ligne:

Flask==1.1.2

Pour en savoir plus sur les formats acceptés, consultez la documentation sur requirements.txt.

2. Créer appengine_config.py

L'étape suivante consiste à faire en sorte qu'App Engine reconnaisse les bibliothèques tierces externes. Créez un fichier nommé appengine_config.py avec le contenu suivant :

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

Ce code effectue exactement ce que nous avons spécifié précédemment, c'est-à-dire qu'App Engine pointe vers le dossier lib pour les bibliothèques copiées.

3. Installer les packages et les dépendances

Exécutez maintenant la commande pip install pour créer le dossier lib et y installer Flask, ainsi que ses dépendances:

$ pip install -t lib -r requirements.txt

Que vous utilisiez pip ou pip2, une fois l'installation du package terminée, vous devez créer un dossier lib dont le contenu ressemble à ceci:

$ ls lib
bin/
click/
click-7.1.2.dist-info/
flask/
Flask-1.1.2.dist-info/
itsdangerous/
itsdangerous-1.1.0.dist-info/
jinja2/
Jinja2-2.11.2.dist-info/
markupsafe/
MarkupSafe-1.1.1.dist-info/
werkzeug/
Werkzeug-1.0.1.dist-info/

Nous allons maintenant mettre à jour le fichier d'application, main.py.

1. Importations

Les importations se présentent d'abord comme dans tous les fichiers Python. L'importation du framework webapp2 est suivie de la bibliothèque Datastore ndb, et enfin de l'extension App Engine qui traite les modèles de style Django. La page suivante doit normalement s'afficher :

  • AVANT :
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

Lorsque vous passez à Flask, vous importez en même temps les composants Flask et des éléments du moteur de rendu de modèles. Supprimez la paire d'importations associées à webapp2 et remplacez-la comme suit (laissez l'importation ndb en l'état):

  • APRÈS :
from flask import Flask, render_template, request
from google.appengine.ext import ndb

2. Démarrage

Les applications utilisant webapp2 nécessitent un seul tableau (liste Python) qui répertorie tous les routages et gestionnaires dans un fichier Python (il peut y en avoir d'autres):

  • AVANT :
app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

Gardez à l'esprit que app.yaml effectue un routage de niveau supérieur et peut appeler différents gestionnaires. L'exemple d'application est suffisamment simple pour que toutes les routes parviennent au gestionnaire main.py.

Flask n'utilise pas de tables de routage de ce type. Vous devez donc supprimer ces lignes dans main.py. Flask requiert également une initialisation. Ajoutez donc la ligne suivante en haut de main.py, juste sous les importations:

  • APRÈS :
app = Flask(__name__)

Dans Flask, vous initialisez le framework, puis vous utilisez des décorateurs pour définir les routes. De plus, les routes sont associées à des fonctions, et non à des classes ou à des méthodes.

Nous vous invitons à prendre le temps de consulter le tutoriel Flask ainsi que la documentation Flask pour vous familiariser avec les fonctionnalités, car cela n'est pas inclus dans cet atelier de programmation.

3. Modèle de données

Aucune modification ici. Datastore sera au cœur de l'atelier de programmation suivant.

4. Gestionnaires

L'application, quel que soit le framework que vous utilisez (webapp2 ou Flask), effectue trois opérations:

  1. Gérer les requêtes GET de chemin racine (/)
  2. Enregistrer une page Web "visite" (créer/stocker un objet Visit)
  3. Afficher les 10 visites les plus récentes (avec un modèle prédéfini, index.html)

Le framework webapp2 utilise un modèle d'exécution basé sur la classe dans lequel les gestionnaires sont créés pour chaque méthode HTTP compatible. Dans notre cas simple, nous ne disposons que de GET, donc une méthode get() est définie:

  • AVANT :
class MainHandler(webapp2.RequestHandler):
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10) or ()  # empty sequence if None
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

Comme mentionné ci-dessus, Flask effectue son propre routage. Au lieu d'une classe de gestionnaire, vous écrivez des fonctions et les décorez avec la route pour laquelle elles doivent être appelées. Les utilisateurs peuvent spécifier des méthodes HTTP gérées dans l'appel de décorateur, soit : @app.route('/app/', methods=['GET', 'POST']). Étant donné que la valeur par défaut est seulement GET (et implicitement HEAD), vous pouvez la laisser désactivée.

Lors de la migration vers Flask, remplacez la classe MainHandler et sa méthode get() par la fonction de routage Flask suivante:

  • APRÈS :
@app.route('/')
def root():
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10) or ()  # empty sequence if None
    return render_template('index.html', visits=visits)

Cet exemple n'est évidemment pas représentatif de votre application, qui sera probablement plus complexe. L'un des objectifs principaux de ces tutoriels est de vous aider à vous lancer, de créer une partie de cette "mémoire musculaire" et à déterminer où modifier le code spécifique à App Engine. Pour vérifier que vous avez effectué ces modifications correctement, comparez le vôtre avec main.py du Module 1.

5. Fichiers auxiliaires

Aucune modification n'est à apporter au fichier .gcloudignore. Il sert à spécifier les fichiers à ne pas déployer sur App Engine, qui ne sont pas nécessaires au déploiement et à l'exécution de l'application, y compris, mais sans s'y limiter, le fichier Python auxiliaire, le contrôle de la source, le code récurrent du dépôt, etc. Notre .gcloudignore ressemble à ceci (les commentaires ont été supprimés par souci de concision):

.gcloudignore
.git
.gitignore
.hgignore
.hg/
*.pyc
*.pyo
__pycache__/
/setup.cfg
README.md

1. Déplacer le fichier de modèle

Dans le dossier du dépôt de référence (Module 0), le fichier de modèle index.html se trouve dans le même dossier que les fichiers de l'application. Comme Flask requiert des fichiers HTML placés dans un dossier templates, vous devez créer ce dossier (mkdir templates) et y placer index.html. Dans un système compatible POSIX, tel que Linux ou Mac OS X, les commandes seraient les suivantes:

mkdir templates
mv index.html templates

2. Mettre à jour le fichier de modèle

Une fois que vous avez déplacé index.html dans templates, il est temps de procéder à une modification légère, mais obligatoire. Examinons l'intégralité du fichier de modèle d'origine:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

</body>
</html>

Alors que webapp2 utilise des modèles Django qui exécutent des appelables tels que visit.timestamp.ctime sans parenthèses ( ), Jinja2 les requiert explicitement. Bien que cela ressemble à un léger ajustement, les modèles Jinja sont plus performants prêts à l'emploi, car il est possible de transmettre des arguments lors des appels.

Dans l'environnement Django, vous devez créer un "tag de modèle" ou écrire un filtre. C'est pourquoi vous devez mettre à jour index.html en ajoutant une paire de parenthèses à l'appel visit.timestamp.ctime:

  • AVANT :
<li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
  • APRÈS :
<li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>

Il s'agit de la seule modification requise. Vous n'aurez pas à modifier index.html pour les prochains ateliers de la série.

Déployer l'application

Lorsque vous aurez terminé toutes les modifications décrites dans ce tutoriel, les fichiers du dossier de votre application doivent être identiques (ou presque) à celui situé dans le dossier de dépôt du Module 1. Maintenant, déployez et constatez que votre application Flask Module 1 est identique à la version webapp2 du Module 0.

Utilisez la commande gcloud app deploy comme nous l'avons fait précédemment lors du déploiement du code du Module 0 d'origine. L'accès à l'application à l'adresse PROJECT_ID.appspot.com, depuis un navigateur Web ou via une commande curl ou wget permet de vérifier qu'elle fonctionne comme prévu.

Si vous rencontrez une erreur de serveur, il s'agit généralement d'une erreur de frappe dans votre code Python. Examinez les journaux de l'application pour rechercher le problème. Comparez également vos fichiers avec ceux du dépôt du Module 1 (lien juste au-dessus).

Facultatif: Effectuer un nettoyage

Que diriez-vous d'un bon nettoyage pour éviter que des frais vous soient facturés tant que vous n'êtes pas prêt à passer à l'atelier de programmation suivant sur la migration ? En tant que développeur existant, vous connaissez probablement déjà les informations de tarification d'App Engine.

Facultatif: Désactiver l'application

Si vous n'êtes pas encore prêt à passer au tutoriel suivant, désactivez votre application pour éviter les frais. Lorsque vous êtes prêt à passer au prochain atelier de programmation, vous pouvez la réactiver. Tant que votre application est désactivée, elle ne génère aucun trafic, donc aucuns frais. Toutefois, si vous dépassez le quota gratuit, votre utilisation de Datastore vous sera facturée, alors supprimez suffisamment d'éléments pour rester dans la limite.

En revanche, si vous ne souhaitez pas poursuivre vos migrations et souhaitez supprimer tous les éléments, vous pouvez arrêter le projet.

Étapes suivantes

Il existe deux modules de migration qui DEMARRENT avec le code du Module 1 terminé, le Module 2 et le Module 7:

  • Module 2 (obligatoire si vous utilisez Datastore)
    • Migrer depuis App Engine ndb vers Cloud NDB
    • Après être passé à Cloud NDB, de nombreuses autres options deviennent disponibles
      • Conteneuriser votre application pour qu'elle s'exécute sur Cloud Run
      • Migrer ensuite votre application vers la bibliothèque cliente Cloud Datastore
      • Migrer votre application vers Cloud Firestore pour accéder aux fonctionnalités de Firebase
  • Module 7 (obligatoire si vous utilisez les files d'attente de tâches [push])
    • Ajouter l'utilisation taskqueue d'App Engine (push)
    • Prépare l'application du Module 1 pour la migration vers Cloud Tasks dans le Module 8

Problèmes/commentaires concernant le module de migration App Engine en atelier de programmation

Si vous rencontrez des problèmes avec cet atelier de programmation, commencez par faire une recherche avant de les signaler. Liens vers la recherche et la création d'un signalement:

Ressources de migration

Le tableau ci-dessous contient des liens vers les dossiers du dépôt pour les Modules 0 (START) et 1 (FINISH). Vous pouvez également y accéder depuis le dépôt pour toutes les migrations App Engine que vous pouvez cloner ou télécharger sous forme de fichier ZIP.

Atelier de programmation

Python 2

Python 3

Module 0

code

(n/a)

Module 1

code

(n/a)

Ressources App Engine

Vous trouverez ci-dessous d'autres ressources concernant cette migration en particulier: