Module 2 : Migrer d'App Engine ndb vers Cloud NDB

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 explique comment migrer de la bibliothèque cliente intégrée ndb (Next Database) d'App Engine vers la bibliothèque cliente Cloud NDB.

Vous apprendrez à effectuer les tâches suivantes :

  • Utiliser la bibliothèque ndb d'App Engine (si vous ne la connaissez pas déjà)
  • Migrer de ndb vers Cloud NDB
  • Migrer votre application vers Python 3

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

Dans le module 1, nous avons migré les frameworks Web du framework webapp2 intégré d'App Engine vers Flask. Dans le présent atelier de programmation, nous continuons à abandonner les services intégrés d'App Engine en passant de la bibliothèque ndb d'App Engine à Google Cloud NDB.

Une fois la migration terminée, vous pourrez :

  1. Migrer vers Python 3 et vers l'environnement d'exécution App Engine nouvelle génération.
  2. Migrer vers Cloud Datastore (bibliothèque cliente pour les applications non-App Engine).
  3. Conteneuriser votre application Python 2 (ou 3) et migrer vers Cloud Run.
  4. Ajouter l'utilisation des files d'attente de tâches d'App Engine (push) puis migrer vers Cloud Tasks.

Mais nous n'en sommes pas encore là. Terminez le présent atelier de programmation avant de réfléchir aux étapes suivantes. Les étapes de migration principales du présent tutoriel sont les suivantes :

  1. Configuration/Préparation
  2. Ajouter la bibliothèque Cloud NDB
  3. Mettre à jour les fichiers de l'application

Avant de passer à la partie principale du tutoriel, nous allons configurer notre projet, obtenir le code et déployer l'application de base pour nous assurer de bien utiliser du code fonctionnel.

1. Configurer le projet

Si vous avez terminé l'atelier de programmation du module 1, nous vous recommandons de réutiliser le même projet (et le même code). Vous pouvez également créer un projet ou réutiliser un autre projet existant. Assurez-vous que le projet dispose d'un compte de facturation actif et qu'App Engine est bien activé.

2. Obtenir un exemple d'application de référence

L'une des conditions préalables est de disposer de l'exemple d'application du module 1. Vous pouvez utiliser votre propre application si vous avez suivi ce tutoriel. Sinon, vous pouvez suivre le tutoriel maintenant (lien ci-dessus) ou simplement puis copier le dépôt du module 1 (lien ci-dessous).

Que vous utilisiez votre application ou la nôtre, le code de départ ("START") est celui du module 1. Le présent atelier de programmation du module 2 vous guide pour chaque étape jusqu'à obtenir le code final ("FINISH"), avec le bonus de la migration de Python 2 vers Python 3 :

Le dossier contenant le code de départ "START" du module 1 doit contenir les éléments suivants :

$ ls
README.md               appengine_config.py     requirements.txt
app.yaml                main.py                 templates

Si vous avez suivi le tutoriel du module 1, vous avez également un dossier lib avec Flask et ses dépendances. Si vous n'avez pas de dossier lib, créez-le à l'aide de la commande pip install -t lib -r requirements.txt afin que nous puissions déployer cette application de référence à l'étape suivante. Si Python 2 et Python 3 sont tous les deux installés, nous vous recommandons d'utiliser pip2 plutôt que pip afin d'éviter toute confusion avec Python 3.

3. (Re)Déployer l'application du Mmodule 1

Étapes préliminaires restantes :

  1. Familiarisez-vous avec l'outil de ligne de commande gcloud (si nécessaire).
  2. (Re)déployez le code du module 1 sur App Engine (si nécessaire).

Une fois que vous avez exécuté ces étapes et vérifié le bon fonctionnement du code, nous pouvons passer à la suite de ce tutoriel en commençant par les fichiers de configuration.

De nombreux services intégrés d'App Engine ont évolué pour devenir des produits autonomes, et Datastore est l'un d'entre eux. Aujourd'hui, les applications autres qu'App Engine peuvent utiliser Cloud Datastore. Pour les utilisateurs de longue date de ndb, l'équipe Google Cloud a créé la bibliothèque cliente Cloud NDB pour communiquer avec Cloud Datastore. Elle est disponible pour Python 2 et Python 3.

Nous allons modifier les fichiers de confirmation pour remplacer App Engine ndb par Cloud NDB, puis modifier notre application.

1. Mettre à jour requirements.txt

Dans le module 1, la seule dépendance externe de notre application était Flask. Ajoutons maintenant Cloud NDB. Voici à quoi ressemblait votre fichier requirements.txt à la fin du module 1 :

  • AVANT :
Flask==1.1.2

Pour effectuer une migration depuis App Engine ndb, vous devez utiliser la bibliothèque Cloud NDB (google-cloud-ndb) en ajoutant son package à requirements.txt.

  • APRÈS :
Flask==1.1.2
google-cloud-ndb==1.7.1

Lorsque cet atelier de programmation a été rédigé, la dernière version recommandée était la 1.7.1. Cependant, il est possible que le requirements.txt dans le dépôt utilise une version plus récente. Nous vous recommandons d'utiliser les dernières versions de chaque bibliothèque. Toutefois, si celles-ci ne fonctionnent pas, vous pouvez rétablir une version antérieure.

Supprimez le dossier lib si vous en avez un et que vous ne l'avez pas vous-même créé plus haut. Maintenant, (ré)installez les bibliothèques mises à jour avec la commande pip install -t lib -r requirements.txt, en utilisant pip2 au lieu de pip si nécessaire.

2. Mettre à jour app.yaml

Certains prérequis s'appliquent à l'ajout de bibliothèques clientes Google Cloud telles que google-cloud-ndb car elles s'appuient sur l'inclusion de bibliothèques intégrées, c'est-à-dire des packages tiers déjà disponibles sur les serveurs Google. Vous ne pouvez pas les répertorier pas dans requirements.txt ni les copier avec pip install. Les seules conditions requises sont les suivantes :

  1. Spécifier les bibliothèques intégrées dans app.yaml.
  2. Les faire pointer vers les bibliothèques tierces copiées avec lesquelles elles pourraient travailler (dans lib).

Voici le fichier app.yaml de départ ("START") du module 1 :

  • AVANT :
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

Ajoutez maintenant les lignes suivantes à app.yaml pour référencer les deux packages tiers grpcio et setuptools dans une nouvelle section libraries :

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

Pourquoi utiliser ces bibliothèques intégrées ? gRPC est un framework RPC ouvert utilisé par toutes les bibliothèques clientes de Google Cloud, y compris google-cloud-ndb. La bibliothèque grpcio correspond à l'adaptateur gRPC Python et est donc obligatoire. Le raisonnement derrière l'inclusion de setuptools vous sera prochainement expliqué.

  • APRÈS :

Une fois les modifications ci-dessus effectuées, votre fichier app.yaml mis à jour devrait maintenant ressembler à ceci :

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

3. Mettre à jour appengine_config.py

L'outil pkg_resources, qui fait partie de la bibliothèque setuptools, permet aux bibliothèques tierces intégrées d'accéder aux bibliothèques fournies sous forme de package. Mettez à jour appengine_config.py pour utiliser pkg_resources afin de les faire pointer vers les bibliothèques regroupées dans lib. Une fois les modifications terminées, le fichier complet doit ressembler à ceci :

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

Maintenant que les formalités de fichier de configuration sont terminées, vous pouvez migrer de ndb vers Cloud NDB. Pour effectuer la migration, mettez à jour les bibliothèques importées et ajoutez la gestion du contexte dans main.py.

1. Importations

Faites l'échange d'importation suivant dans main.py :

  • AVANT
from google.appengine.ext import ndb
  • APRÈS :
from google.cloud import ndb

Le passage d'une bibliothèque App Engine à une bibliothèque Google Cloud est parfois aussi subtil dans le cas présent. Pour les services intégrés qui sont devenus des produits Google Cloud complets, vous importerez les attributs de google.cloud au lieu de google.appengine.

2. Accès à Datastore

Pour pouvoir utiliser la bibliothèque Cloud NDB, votre application doit utiliser des gestionnaires de contexte Python. Leur rôle est de contrôler l'accès aux ressources de telle sorte qu'elles doivent être acquises avant de pouvoir être utilisées. Les gestionnaires de contexte reposent sur la technique de contrôle informatique appelée RAII ("Resource Allocation Is Initialization" ou littéralement, "toute allocation de ressource est une initialisation"). Les gestionnaires de contexte sont utilisés avec des fichiers Python (qui doivent être ouverts avant de pouvoir y accéder) et en appliquant la simultanéité. Vous devez donc obtenir des verrous "spin lock" avant de pouvoir exécuter le code dans une section critique.

De même, Cloud NDB nécessite d'obtenir le contexte client pour communiquer avec Datastore avant de pouvoir exécuter des commandes Datastore. Commencez par créer un client (ndb.Client()) en ajoutant ds_client = ndb.Client() dans main.py juste après l'initialisation de Flask :

app = Flask(__name__)
ds_client = ndb.Client()

La commande Python with permet uniquement d'obtenir le contexte d'un objet. Encapsulez tous les blocs de code accédant à Datastore dans des instructions with.

Vous trouverez ci-dessous les mêmes fonctions que dans le module 1 pour l'écriture d'une nouvelle entité dans Datastore et la lecture afin d'afficher les entités les plus récemment ajoutées :

  • AVANT :

Voici le code d'origine sans gestion contextuelle :

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return (v.to_dict() for v in Visit.query().order(
            -Visit.timestamp).fetch(limit))
  • APRÈS :

Ajoutez maintenant with ds_client.context(): et déplacez votre code d'accès Datastore dans le bloc with :

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return (v.to_dict() for v in Visit.query().order(
                -Visit.timestamp).fetch(limit))

L'application de pilote principal reste identique à celle du module 1 car aucun code ndb (ou Cloud NDB) n'apparaît ici :

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

Une bonne pratique consiste à faire une distinction claire entre le code d'application et l'accès aux données. Ainsi, il n'est pas nécessaire de modifier le code principal de votre application lorsque le mécanisme de stockage de données sous-jacent est modifié comme nous l'avons fait avec cette migration.

Déployer l'application

Redéployez votre application avec gcloud app deploy et confirmez qu'elle fonctionne correctement. Votre code doit maintenant correspondre à celui du dépôt du module 2.

Si vous avez consulté cette série sans suivre les ateliers de programmation précédents, l'application elle-même ne change pas. Elle enregistre toutes les visites sur la page Web principale (/) et ressemble à ceci une fois que vous avez consulté le site suffisamment de fois :

Application Visitme

Bravo ! Vous avez terminé l'atelier de programmation du module 2. Vous venez de franchir la ligne d'arrivée : il s'agit de la dernière des migrations vivement recommandées jusqu'à présent pour ce qui est de Datastore.

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

Plusieurs choix s'offrent maintenant à vous pour la suite. Choisissez l'une des options suivantes :

  • Module 2 : Bonus : passez à la partie bonus de ce tutoriel et découvrez comment porter votre application vers Python 3 et utiliser l'environnement d'exécution App Engine nouvelle génération.
  • Module 7 : files d'attente d'envoi de tâches App Engine (obligatoire si vous utilisez des files d'attente de tâches d'envoi de tâches [push])
    • Ajoutez des tâches push taskqueue App Engine à l'application du module 1.
    • Préparez les utilisateurs à migrer vers Cloud Tasks dans le module 8.
  • Module 4 : Migrer vers Cloud Run avec Docker
    • Conteneurisez votre application pour l'exécuter sur Cloud Run avec Docker.
    • Cela vous permet de continuer d'utiliser Python 2.
  • Module 5 : Migrer vers Cloud Run avec les packs de création Cloud
    • Conteneurisez votre application pour qu'elle s'exécute sur Cloud Run avec les packs de création Cloud.
    • Il n'est pas nécessaire de déjà connaître Docker, les conteneurs ou les Dockerfile.
    • Vous devez avoir déjà effectué la migration de votre application vers Python 3.
  • Module 3 :
    • Modernisez l'accès au Datastore en passant de Cloud NDB à Cloud Datastore.
    • Il s'agit de la bibliothèque utilisée pour les applications Python 3 App Engine ou autres.

Pour bénéficier des nouvelles fonctionnalités et des derniers environnements d'exécution App Engine, nous vous recommandons de migrer vers Python 3. Dans notre exemple d'application, Datastore était le seul service intégré utilisé. La migration de ndb vers Cloud NDB ayant été effectuée, nous pouvons maintenant transitionner vers l'environnement d'exécution Python 3 d'App Engine.

Présentation

Bien que le portage vers Python 3 dépasse le cadre d'un simple tutoriel Google Cloud, la présente partie de notre atelier de programmation donne aux développeurs une idée des spécificités de l'environnement d'exécution App Engine pour Python 3. L'accès à des packages tiers est l'un des principaux avantages de l'environnement d'exécution nouvelle génération. Il n'est plus nécessaire de spécifier des packages intégrés dans app.yaml, ni de copier ou d'importer des bibliothèques non intégrées (elles sont installées de manière implicite car elles figurent dans requirements.txt).

Comme notre exemple est très basique et que Cloud NDB est compatible avec les deux versions de Python, le portage ne nécessite aucune modification et le code fonctionne aussi bien sous Python 2 que sous Python 3. Dans le cas présent, seules les modifications de configuration suivantes sont requises :

  1. Simplifier app.yaml pour référencer Python 3 et supprimer les bibliothèques tierces.
  2. Supprimer appengine_config.py et le dossier lib car ils ne sont plus nécessaires.

En plus de main.py, les fichiers requirements.txt et templates/index.html restent inchangés.

Simplier app.yaml

AVANT :

La seule réelle modification pour cet exemple d'application est le fait de raccourcir app.yaml. Pour rappel, voici ce que nous avions dans app.yaml à la fin du module 2 :

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

APRÈS :

Dans Python 3, les instructions threadsafe, api_version et libraries sont toutes obsolètes. Toutes les applications sont supposées être threadsafe et api_version n'est plus utilisé dans Python 3. Comme aucun package tiers intégré n'est préinstallé sur les services App Engine, le service libraries est également obsolète. Pour plus d'informations sur ces modifications, consultez la documentation sur les modifications apportées à app.yaml. Par conséquent, vous devez supprimer ces trois éléments de app.yaml et passer à une version compatible de Python 3 (voir ci-dessous).

Utilisation de la directive handlers

En outre, la directive handlers, qui dirige le trafic vers des applications App Engine spécifiques, a également été abandonnée. Étant donné que l'environnement d'exécution nouvelle génération suppose que les frameworks Web gèrent le routage des applications, tous les "scripts de gestionnaire" doivent être définis sur "auto". En combinant les modifications ci-dessus, vous obtenez ce fichier app.yaml :

runtime: python38

handlers:
- url: /.*
  script: auto

Pour en savoir plus sur script: auto, consultez sa page de documentation.

Supprimer l'instruction handlers

Étant donné que handlers est obsolète, vous pouvez également supprimer toute la section et ne laisser qu'une seule ligne dans votre fichier app.yaml :

runtime: python38

Par défaut, le serveur Web WSGI Gunicorn est disponible pour toutes les applications. Si vous maîtrisez gunicorn, voici la commande qui s'exécute lors d'un démarrage par défaut avec un fichier app.yaml réduit au strict minimum :

gunicorn main:app --workers 2 -c /config/gunicorn.py

Facultatif : utilisation de la directive entrypoint

Toutefois, vous pouvez utiliser une instruction entrypoint si votre application nécessite une commande de démarrage spécifique, auquel cas votre fichier app.yaml ressemble à ceci :

runtime: python38
entrypoint: python main.py

Cet exemple demande spécifiquement un serveur de développement Flask plutôt que d'utiliser gunicorn. Le code qui démarre le serveur de développement doit également être ajouté à votre application pour démarrer sur l'interface 0.0.0.0 sur le port 8080 en ajoutant cette petite section à la fin de main.py :

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

Pour en savoir plus sur entrypoint, consultez la documentation correspondante. Pour obtenir d'autres exemples et bonnes pratiques, consultez la documentation sur le démarrage standard App Engine ainsi que la documentation sur le démarrage flexible App Engine.

Supprimer appengine_config.py et lib

Supprimez le fichier appengine_config.py et le dossier lib. Lors de la migration vers Python 3, App Engine acquiert et installe les packages répertoriés dans requirements.txt.

Le fichier de configuration appengine_config.py permet de reconnaître les bibliothèques et packages tiers, que vous les ayez copiés vous-même ou que vous utilisiez ceux qui sont déjà disponibles sur des serveurs App Engine (intégrés) Voici un résumé des principaux changements lorsque vous passez à Python 3 :

  1. Pas de regroupement de bibliothèques tierces copiées (répertoriées dans requirements.txt).
  2. Pas de pip install dans un dossier lib et pas de dossier lib.
  3. Pas de liste de bibliothèques tierces dans app.yaml.
  4. Pas besoin de référencer une application auprès des bibliothèques tierces, et donc pas de fichier appengine_config.py.

Il vous suffit de répertorier toutes les bibliothèques tierces requises dans requirements.txt.

Déployer l'application

Redéployez votre application pour vous assurer qu'elle fonctionne. Vous pouvez également vérifier que votre solution est identique à l'exemple de code Python 3 du module 2. Pour visualiser les différences avec Python 2, comparez le code à sa version Python 2.

Nous vous félicitons d'avoir terminé l'étape bonus du module 2 ! Consultez la documentation sur la préparation des fichiers de configuration pour l'environnement d'exécution Python 3. Enfin, revenez à l'étape "Récapitulatif/Nettoyage" pour connaître les étapes suivantes et effectuer un nettoyage.

Préparer votre application

Au moment de procéder à la migration de votre application, vous devez transférer le fichier main.py et les autres fichiers de l'application vers la version 3.x. Il est donc recommandé d'optimiser autant que possible la compatibilité ascendante de votre application 2.x.

Pour ce faire il existe de nombreuses ressources en ligne mais voici quelques conseils essentiels :

  1. Assurez-vous que toutes les dépendances de votre application sont entièrement compatibles avec la version 3.x.
  2. Assurez-vous que votre application s'exécute au moins avec la version 2.6 (de préférence 2.7).
  3. Assurez-vous que l'application réussit en intégralité la suite de tests (avec une couverture minimale de 80 %).
  4. Utilisez des bibliothèques de compatibilité telles que six, Future et/ou Modernize.
  5. Informez-vous sur les principaux problèmes de compatibilité entre les versions 2.x et 3.x.
  6. Toute E/S peut entraîner des incompatibilités entre les chaînes Unicode et les chaînes d'octets.

L'exemple d'application a été conçu pour tenir compte de tous ces aspects, ce qui explique pourquoi l'application s'exécute aussi bien sous 2.x que sous 3.x. Nous pouvons donc nous concentrer sur les modifications à apporter pour utiliser la plate-forme nouvelle génération.

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

Vous trouverez des liens vers les dossiers des dépôts du module 1 (code de départ "START") et du module 2 (code final "FINISH") dans le tableau ci-dessous. Vous pouvez également y accéder depuis le dépôt pour toutes les migrations d'ateliers de programmation App Engine que vous pouvez cloner ou télécharger sous forme de fichier ZIP.

Atelier de programmation

Python 2

Python 3

Module 1

code

(n/a)

Module 2

code

code

Ressources App Engine

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