Migrer d'App Engine vers Cloud Storage (module 16)

1. Présentation

La série d'ateliers de programmation Serverless Migration Station (tutoriels pratiques à suivre à votre rythme) et les vidéos associées sont destinées à aider les développeurs Google Cloud sans serveur à moderniser leurs applications en les guidant tout au long d'une ou plusieurs migrations, principalement en les aidant à abandonner les anciens services. Cela rend vos applications plus portables et vous offre plus d'options et de flexibilité, ce qui vous permet de vous intégrer à une plus large gamme de produits Cloud et d'y accéder, et de passer plus facilement aux versions linguistiques plus récentes. Bien qu'elle se concentre initialement sur les premiers utilisateurs de Cloud, principalement les développeurs App Engine (environnement standard), cette série est suffisamment large pour inclure d'autres plates-formes sans serveur comme Cloud Functions et Cloud Run, ou ailleurs si nécessaire.

Cet atelier de programmation vous explique comment migrer d'App Engine Blobstore vers Cloud Storage. Il existe également des migrations implicites depuis :

Pour obtenir des informations plus détaillées, consultez les modules de migration associés.

Vous apprendrez à

  • Ajouter l'utilisation de l'API/bibliothèque Blobstore d'App Engine
  • Stocker les importations des utilisateurs dans le service Blobstore
  • Préparer la prochaine étape de la migration vers Cloud Storage

Prérequis

Enquête

Comment allez-vous utiliser ce tutoriel ?

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

Quel est votre niveau d'expérience avec Python ?

Débutant Intermédiaire Expert

Quel est votre niveau d'expérience avec les services Google Cloud ?

Débutant Intermédiaire Expert

2. Arrière-plan

Dans cet atelier de programmation, vous allez utiliser l'application exemple du module 15 et découvrir comment migrer de Blobstore (et NDB) vers Cloud Storage (et Cloud NDB). Le processus de migration consiste à remplacer les dépendances sur les anciens services groupés d'App Engine, ce qui vous permet de migrer vos applications vers une autre plate-forme Cloud sans serveur ou une autre plate-forme d'hébergement si vous le souhaitez.

Cette migration nécessite un peu plus d'efforts que les autres migrations de cette série. Blobstore dépend du framework webapp d'origine. C'est pourquoi l'exemple d'application utilise le framework webapp2 au lieu de Flask. Ce tutoriel présente des migrations vers Cloud Storage, Cloud NDB, Flask et Python 3.

L'application enregistre toujours les "visites" des utilisateurs finaux et affiche les dix plus récentes, mais l'atelier de programmation précédent (module 15) a ajouté une nouvelle fonctionnalité pour tenir compte de l'utilisation de Blobstore : l'application invite les utilisateurs finaux à importer un artefact (un fichier) correspondant à leur "visite". Les utilisateurs peuvent le faire ou sélectionner "Ignorer" pour refuser. Quelle que soit la décision de l'utilisateur, la page suivante affiche la même sortie que les versions précédentes de cette application, en affichant les visites les plus récentes. Autre particularité : les visites avec des artefacts correspondants comportent un lien "Afficher" permettant d'afficher l'artefact d'une visite. Cet atelier de programmation implémente les migrations mentionnées précédemment tout en préservant la fonctionnalité décrite.

3. Configuration/Préparation

Avant de passer à la partie principale de ce 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 déjà déployé l'application du module 15, 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 activé.

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

L'une des conditions préalables à cet atelier de programmation est de disposer d'un exemple d'application fonctionnel du module 15. Si vous n'en avez pas, vous pouvez l'obtenir dans le dossier "START" du module 15 (lien ci-dessous). Cet atelier de programmation vous guide pour chaque étape jusqu'à obtenir un code similaire à celui du dossier "FINISH" du module 16.

Le répertoire des fichiers de départ du module 15 doit se présenter comme suit :

$ ls
README.md       app.yaml        main-gcs.py     main.py         templates

Le fichier main-gcs.py est une version alternative de main.py du module 15. Il permet de sélectionner un bucket Cloud Storage différent de celui par défaut d'une URL attribuée à une application en fonction de l'ID du projet : PROJECT_ID.appspot.com. Ce fichier ne joue aucun rôle dans cet atelier de programmation (module 16), si ce n'est que des techniques de migration similaires peuvent lui être appliquées si vous le souhaitez.

3. (Re)Déployer l'application de référence

Étapes préliminaires restantes :

  1. Familiarisez-vous avec l'outil de ligne de commande gcloud
  2. Redéployez l'exemple d'application avec gcloud app deploy
  3. Vérifier que l'application s'exécute sans problème sur App Engine

Une fois ces étapes effectuées, vérifiez que votre application du module 15 fonctionne. La page d'accueil présente aux utilisateurs un formulaire les invitant à importer un fichier d'artefact de visite, ainsi qu'une option leur permettant de refuser en cliquant sur un bouton "Ignorer" :

f5b5f9f19d8ae978.png

Une fois que les utilisateurs ont importé un fichier ou ignoré cette étape, l'application affiche la page "Visites récentes" qu'ils connaissent bien :

f5ac6b98ee8a34cb.png

Les visites comportant un artefact sont associées à un lien "Afficher" à droite de l'horodatage de la visite, qui permet d'afficher (ou de télécharger) l'artefact. Une fois que vous avez confirmé la fonctionnalité de l'application, vous êtes prêt à migrer des anciens services App Engine (webapp2, NDB, Blobstore) vers des alternatives contemporaines (Flask, Cloud NDB, Cloud Storage).

4. Mettre à jour les fichiers de configuration

Trois fichiers de configuration entrent en jeu pour la version mise à jour de notre application. Les tâches requises sont les suivantes :

  1. Mettre à jour les bibliothèques tierces intégrées requises dans app.yaml et laisser la porte ouverte à une migration vers Python 3
  2. Ajoutez un requirements.txt qui spécifie toutes les bibliothèques requises qui ne sont pas intégrées.
  3. Ajoutez appengine_config.py pour que l'application soit compatible avec les bibliothèques tierces intégrées et non intégrées.

app.yaml

Modifiez votre fichier app.yaml en mettant à jour la section libraries. Supprimez jinja2 et ajoutez grpcio, setuptools et ssl. Choisissez la dernière version disponible pour les trois bibliothèques. Ajoutez également la directive Python 3 runtime, mais mettez-la en commentaire. Une fois que vous avez terminé, le résultat doit être semblable à ceci (si vous avez sélectionné Python 3.9) :

AVANT :

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

APRÈS :

#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest
- name: ssl
  version: latest

Les modifications concernent principalement les bibliothèques Python 2 intégrées disponibles sur les serveurs App Engine (vous n'avez donc pas besoin de les regrouper vous-même). Nous avons supprimé Jinja2, car il est fourni avec Flask, que nous allons ajouter à reqs.txt. grpcio et setuptools sont nécessaires chaque fois que des bibliothèques clientes Google Cloud, telles que celles pour Cloud NDB et Cloud Storage, sont utilisées. Enfin, Cloud Storage lui-même nécessite la bibliothèque SSL. L'instruction d'exécution commentée en haut de la page est à utiliser lorsque vous serez prêt à transférer cette application vers Python 3. Nous aborderons ce sujet à la fin de ce tutoriel.

requirements.txt

Ajoutez un fichier requirements.txt, qui nécessite le framework Flask, ainsi que les bibliothèques clientes Cloud NDB et Cloud Storage, qui ne sont pas intégrées. Créez le fichier avec le contenu suivant :

flask
google-cloud-ndb
google-cloud-storage

L'environnement d'exécution Python 2 App Engine nécessite l'auto-groupement des bibliothèques tierces non intégrées. Exécutez donc la commande suivante pour installer ces bibliothèques dans le dossier "lib" :

pip install -t lib -r requirements.txt

Si vous avez installé Python 2 et Python 3 sur votre machine de développement, vous devrez peut-être utiliser la commande pip2 pour vous assurer d'obtenir les versions Python 2 de ces bibliothèques. Une fois que vous êtes passé à Python 3, vous n'avez plus besoin de regrouper vous-même les dépendances.

appengine_config.py

Ajoutez un fichier appengine_config.py compatible avec les bibliothèques tierces intégrées et non intégrées. Créez le fichier avec le contenu suivant :

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)

Les étapes que vous venez de suivre devraient être semblables ou identiques à celles listées dans la section Installer des bibliothèques pour les applications Python 2 de la documentation App Engine. Plus précisément, le contenu de appengine_config.py devrait correspondre à celui de l'étape 5.

Le travail sur les fichiers de configuration est terminé. Passons maintenant à l'application.

5. Modifier les fichiers d'application

Importations

Le premier ensemble de modifications pour main.py consiste à remplacer tous les éléments à remplacer. Voici ce qui va changer :

  1. webapp2 est remplacé par Flask
  2. Au lieu d'utiliser Jinja2 à partir de webapp2_extras, utilisez celui fourni avec Flask.
  3. App Engine Blobstore et NDB sont remplacés par Cloud NDB et Cloud Storage
  4. Les gestionnaires Blobstore dans webapp sont remplacés par une combinaison du module de bibliothèque standard io, de Flask et des utilitaires werkzeug.
  5. Par défaut, Blobstore écrit dans un bucket Cloud Storage dont le nom est celui de l'URL de votre application (PROJECT_ID.appspot.com). Étant donné que nous effectuons la migration vers la bibliothèque cliente Cloud Storage, google.auth est utilisé pour obtenir l'ID de projet afin de spécifier exactement le même nom de bucket. (Vous pouvez modifier le nom du bucket, car il n'est plus codé en dur.)

AVANT :

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

Implémentez les modifications de la liste ci-dessus en remplaçant la section d'importation actuelle dans main.py par l'extrait de code ci-dessous.

APRÈS :

import io

from flask import (Flask, abort, redirect, render_template,
        request, send_file, url_for)
from werkzeug.utils import secure_filename

import google.auth
from google.cloud import exceptions, ndb, storage

Initialisation et prise en charge inutile de Jinja2

Le bloc de code suivant à remplacer est le BaseHandler qui spécifie l'utilisation de Jinja2 à partir de webapp2_extras. Cette ligne est inutile, car Jinja2 est fourni avec Flask et constitue son moteur de création de modèles par défaut. Supprimez-la.

Du côté du module 16, instanciez les objets que nous n'avions pas dans l'ancienne application. Cela inclut l'initialisation de l'application Flask et la création de clients API pour Cloud NDB et Cloud Storage. Enfin, nous assemblons le nom du bucket Cloud Storage, comme décrit ci-dessus dans la section des importations. Voici les captures d'écran avant et après l'implémentation de ces modifications :

AVANT :

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

APRÈS :

app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID

Mettre à jour l'accès à Datastore

Cloud NDB est principalement compatible avec App Engine NDB. L'une des différences déjà abordées est la nécessité d'un client API. Une autre différence est que le dernier nécessite que l'accès à Datastore soit contrôlé par le gestionnaire de contexte Python du client API. En d'autres termes, cela signifie que tous les appels d'accès à Datastore à l'aide de la bibliothèque cliente Cloud NDB ne peuvent se produire que dans les blocs Python with.

Il s'agit d'un changement.L'autre changement est que Blobstore et ses objets, par exemple les BlobKey, ne sont pas compatibles avec Cloud Storage. Vous devez donc remplacer file_blob par ndb.StringProperty. Vous trouverez ci-dessous la classe de modèle de données et les fonctions store_visit() et fetch_visits() mises à jour reflétant ces modifications :

AVANT :

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()

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

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

APRÈS :

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.StringProperty()

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

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

Voici une représentation visuelle des modifications apportées jusqu'à présent :

a8f74ca392275822.png

Mettre à jour les gestionnaires

Gestionnaire d'importation

Les gestionnaires dans webapp2 sont des classes, tandis que dans Flask, ce sont des fonctions. Au lieu d'une méthode de verbe HTTP, Flask utilise le verbe pour décorer la fonction. Blobstore et ses gestionnaires webapp sont remplacés par des fonctionnalités de Cloud Storage, ainsi que par Flask et ses utilitaires :

AVANT :

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

APRÈS :

@app.route('/upload', methods=['POST'])
def upload():
    'Upload blob (POST) handler'
    fname = None
    upload = request.files.get('file', None)
    if upload:
        fname = secure_filename(upload.filename)
        blob = gcs_client.bucket(BUCKET).blob(fname)
        blob.upload_from_file(upload, content_type=upload.content_type)
    store_visit(request.remote_addr, request.user_agent, fname)
    return redirect(url_for('root'), code=307)

Voici quelques remarques concernant cette mise à jour :

  • Au lieu d'un blob_id, les artefacts de fichier sont désormais identifiés par le nom de fichier (fname) s'il est présent, et par None dans le cas contraire (l'utilisateur a choisi de ne pas importer de fichier).
  • Les gestionnaires Blobstore ont abstrait le processus d'importation de ses utilisateurs, mais Cloud Storage ne le fait pas. Vous pouvez donc voir le code nouvellement ajouté qui définit l'objet blob et l'emplacement (bucket) du fichier, ainsi que l'appel qui effectue l'importation proprement dite. (upload_from_file()).
  • webapp2 utilise une table de routage en bas du fichier d'application, tandis que les routes Flask se trouvent dans chaque gestionnaire décoré.
  • Les deux gestionnaires terminent leur fonctionnalité en redirigeant vers la page d'accueil ( / ) tout en conservant la requête POST avec un code de retour HTTP 307.

Gestionnaire de téléchargement

La mise à jour du gestionnaire de téléchargement suit un modèle similaire à celui du gestionnaire d'importation, mais avec beaucoup moins de code à examiner. Remplacez les fonctionnalités Blobstore et webapp par les équivalents Cloud Storage et Flask :

AVANT :

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

APRÈS :

@app.route('/view/<path:fname>')
def view(fname):
    'view uploaded blob (GET) handler'
    blob = gcs_client.bucket(BUCKET).blob(fname)
    try:
        media = blob.download_as_bytes()
    except exceptions.NotFound:
        abort(404)
    return send_file(io.BytesIO(media), mimetype=blob.content_type)

Remarques sur cette mise à jour :

  • Encore une fois, Flask décore les fonctions de gestionnaire avec leur route, tandis que webapp le fait dans une table de routage en bas. Vous devez donc reconnaître la syntaxe de correspondance de modèle de ce dernier (('/view/([^/]+)?') par rapport à celle de Flask ('/view/<path:fname>').
  • Comme pour le gestionnaire d'importation, il faut un peu plus de travail côté Cloud Storage pour la fonctionnalité abstraite par les gestionnaires Blobstore, à savoir l'identification du fichier (blob) en question et le téléchargement explicite du binaire par rapport à l'appel de méthode unique send_blob() du gestionnaire Blobstore.
  • Dans les deux cas, une erreur HTTP 404 est renvoyée à l'utilisateur si un artefact est introuvable.

Gestionnaire principal

Les dernières modifications apportées à l'application principale ont lieu dans le gestionnaire principal. Les méthodes de verbe HTTP webapp2 sont remplacées par une seule fonction combinant leurs fonctionnalités. Remplacez la classe MainHandler par la fonction root() et supprimez la table de routage webapp2, comme indiqué ci-dessous :

AVANT :

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

APRÈS :

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

Au lieu de méthodes get() et post() distinctes, il s'agit essentiellement d'une instruction if-else dans root(). De plus, comme root() est une fonction unique, il n'y a qu'un seul appel pour afficher le modèle pour GET et POST, ce qui n'est pas vraiment possible dans webapp2.

Voici une représentation visuelle de ce deuxième et dernier ensemble de modifications apportées à main.py :

5ec38818c32fec2.png

(facultatif) "Amélioration" de la rétrocompatibilité

La solution créée ci-dessus fonctionne parfaitement, mais uniquement si vous partez de zéro et que vous n'avez pas de fichiers créés par Blobstore. Étant donné que nous avons mis à jour l'application pour identifier les fichiers par leur nom au lieu de BlobKey, l'application du module 16 telle quelle ne pourra pas afficher les fichiers Blobstore. En d'autres termes, nous avons apporté une modification non rétrocompatible lors de cette migration. Nous présentons maintenant une autre version de main.py appelée main-migrate.py (disponible dans le dépôt) qui tente de combler cette lacune.

La première "extension" permettant de prendre en charge les fichiers créés par Blobstore est un modèle de données qui comporte un BlobKeyProperty (en plus d'un StringProperty pour les fichiers créés par Cloud Storage) :

class Visit(ndb.Model):
    'Visit entity registers visitor IP address & timestamp'
    visitor   = ndb.StringProperty()
    timestamp = ndb.DateTimeProperty(auto_now_add=True)
    file_blob = ndb.BlobKeyProperty()  # backwards-compatibility
    file_gcs  = ndb.StringProperty()

La propriété file_blob permet d'identifier les fichiers créés par Blobstore, tandis que file_gcs est réservée aux fichiers Cloud Storage. Désormais, lorsque vous créez des visites, stockez explicitement une valeur dans file_gcs au lieu de file_blob. L'événement store_visit se présente donc un peu différemment :

AVANT :

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

APRÈS :

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

Lorsque vous récupérez les visites les plus récentes, normalisez les données avant de les envoyer au modèle :

AVANT :

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = fetch_visits(10)
    return render_template('index.html', **context)

APRÈS :

@app.route('/', methods=['GET', 'POST'])
def root():
    'main application (GET/POST) handler'
    context = {}
    if request.method == 'GET':
        context['upload_url'] = url_for('upload')
    else:
        context['visits'] = etl_visits(fetch_visits(10))
    return render_template('index.html', **context)

Ensuite, vérifiez l'existence de file_blob ou file_gcs (ou d'aucun des deux). S'il existe un fichier, sélectionnez-le et utilisez son identifiant (BlobKey pour les fichiers créés par Blobstore ou le nom de fichier pour les fichiers créés par Cloud Storage). Lorsque nous parlons de "fichiers créés par Cloud Storage", nous faisons référence aux fichiers créés à l'aide de la bibliothèque cliente Cloud Storage. Blobstore écrit également dans Cloud Storage, mais dans ce cas, il s'agit de fichiers créés par Blobstore.

Plus important encore, qu'est-ce que cette fonction etl_visits() utilisée pour normaliser ou ETL (extraire, transformer et charger) les données pour l'utilisateur final ? Elle se présente comme suit :

def etl_visits(visits):
    return [{
            'visitor': v.visitor,
            'timestamp': v.timestamp,
            'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
                    and v.file_gcs else v.file_blob
            } for v in visits]

Il ressemble probablement à ce que vous attendiez : le code parcourt toutes les visites et, pour chaque visite, prend les données de visiteur et d'horodatage telles quelles, puis vérifie si file_gcs ou file_blob existe et, si c'est le cas, en choisit un (ou None si aucun n'existe).

Voici une illustration des différences entre main.py et main-migrate.py :

718b05b2adadb2e1.png

Si vous partez de zéro sans fichiers créés par Blobstore, utilisez main.py. Toutefois, si vous effectuez une transition et que vous souhaitez des fichiers d'assistance créés par Blobstore et Cloud Storage, consultez main-migrate.py pour obtenir un exemple de gestion de ce type de scénario. Cela vous aidera à planifier les migrations pour vos propres applications. Lors de migrations complexes, des cas particuliers sont susceptibles de se produire. Cet exemple est donc destiné à montrer une plus grande affinité pour la modernisation d'applications réelles avec des données réelles.

6. Résumé/Nettoyage

Cette section conclut cet atelier de programmation en déployant l'application et en vérifiant qu'elle fonctionne comme prévu et dans toutes les sorties reflétées. Après la validation de l'application, effectuez les étapes de nettoyage et réfléchissez aux prochaines étapes.

Déployer et vérifier l'application

Avant de redéployer votre application, assurez-vous d'exécuter pip install -t lib -r requirements.txt pour obtenir ces bibliothèques tierces auto-groupées dans le dossier "lib". Si vous souhaitez exécuter la solution rétrocompatible, commencez par renommer main-migrate.py en main.py. Exécutez maintenant gcloud app deploy et vérifiez que l'application fonctionne de la même manière que l'application du module 15. L'écran du formulaire ressemble à ceci :

f5b5f9f19d8ae978.png

La page des visites les plus récentes se présente comme suit :

f5ac6b98ee8a34cb.png

Félicitations ! Vous avez terminé cet atelier de programmation qui consistait à remplacer App Engine Blobstore par Cloud Storage, App Engine NDB par Cloud NDB et webapp2 par Flask. Votre code doit maintenant correspondre à celui du dossier FINISH (Module 16). L'autre fichier main-migrate.py est également présent dans ce dossier.

"Migration" vers Python 3

L'instruction Python 3 runtime commentée en haut de app.yaml est tout ce dont vous avez besoin pour migrer cette application vers Python 3. Le code source lui-même est déjà compatible avec Python 3. Aucune modification n'est donc nécessaire. Pour déployer cette application en tant qu'application Python 3, procédez comme suit :

  1. Décommentez l'instruction Python 3 runtime en haut de app.yaml.
  2. Supprimez toutes les autres lignes de app.yaml.
  3. Supprimez le fichier appengine_config.py. (non utilisé dans l'environnement d'exécution Python 3)
  4. Supprimez le dossier lib s'il existe. (inutile avec l'environnement d'exécution Python 3)

Effectuer un nettoyage

Général

Si vous avez terminé pour le moment, nous vous recommandons de désactiver votre application App Engine pour éviter d'être facturé. Toutefois, si vous souhaitez effectuer d'autres tests ou expériences, la plate-forme App Engine dispose d'un quota sans frais. Tant que vous ne dépassez pas ce niveau d'utilisation, aucun frais ne devrait vous être facturé. Cela concerne le calcul, mais des frais peuvent également s'appliquer aux services App Engine concernés. Pour en savoir plus, consultez la page de tarification. Si cette migration implique d'autres services Cloud, ceux-ci sont facturés séparément. Dans les deux cas, le cas échéant, consultez la section "Spécifique à cet atelier de programmation" ci-dessous.

Pour être tout à fait transparent, le déploiement sur une plate-forme de calcul sans serveur Google Cloud comme App Engine entraîne de légers coûts de compilation et de stockage. Cloud Build et Cloud Storage disposent chacun de leur propre quota sans frais. Le stockage de cette image utilise une partie de ce quota. Toutefois, il est possible que vous résidiez dans une région où ce niveau sans frais n'est pas disponible. Veillez donc à surveiller votre utilisation de l'espace de stockage pour minimiser les coûts potentiels. Voici quelques "dossiers" Cloud Storage spécifiques que vous devez examiner :

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Les liens de stockage ci-dessus dépendent de votre PROJECT_ID et de votre *LOC*ation. Par exemple, "us" si votre application est hébergée aux États-Unis.

En revanche, si vous ne souhaitez pas poursuivre avec cette application ni avec d'autres ateliers de programmation de migration associés et que vous souhaitez tout supprimer complètement, arrêtez votre projet.

Spécifique à cet atelier de programmation

Les services listés ci-dessous sont propres à cet atelier de programmation. Pour en savoir plus, consultez la documentation de chaque produit :

Notez que si vous avez migré du module 15 vers le module 16, vous aurez toujours des données dans Blobstore. C'est pourquoi nous incluons les informations sur ses tarifs ci-dessus.

Étapes suivantes

Au-delà de ce tutoriel, voici d'autres modules de migration qui se concentrent sur l'abandon des anciens services groupés :

  • Module 2 : migrer depuis App Engine ndb vers Cloud NDB
  • Modules 7 à 9 : migrer les tâches push de la file d'attente de tâches App Engine vers Cloud Tasks
  • Modules 12 et 13 : migrer d'App Engine Memcache vers Cloud Memorystore
  • Modules 18 et 19 : migrer depuis la file d'attente de tâches App Engine (tâches de retrait) vers Cloud Pub/Sub

App Engine n'est plus la seule plate-forme sans serveur de Google Cloud. Si vous avez une petite application App Engine ou une application dont les fonctionnalités sont limitées et que vous souhaitez la transformer en microservice autonome, ou si vous souhaitez diviser une application monolithique en plusieurs composants réutilisables, ce sont de bonnes raisons d'envisager de passer à Cloud Functions. Si la conteneurisation fait désormais partie de votre workflow de développement d'applications, en particulier s'il s'agit d'un pipeline CI/CD (intégration continue/livraison ou déploiement continus), envisagez de migrer vers Cloud Run. Ces scénarios sont couverts par les modules suivants :

  • Migrer d'App Engine vers Cloud Functions : consultez le module 11.
  • Migrer d'App Engine vers Cloud Run : consultez le module 4 pour conteneuriser votre application avec Docker, ou le module 5 pour le faire sans conteneurs, sans connaissances sur Docker ni Dockerfile.

Le passage à une autre plate-forme serverless est facultatif. Nous vous recommandons d'examiner les meilleures options pour vos applications et vos cas d'utilisation avant d'apporter des modifications.

Quel que soit le module de migration que vous envisagez ensuite, vous pouvez accéder à l'ensemble du contenu Serverless Migration Station (ateliers de programmation, vidéos, code source [le cas échéant]) dans son dépôt Open Source. Le README du dépôt fournit également des conseils sur les migrations à envisager et sur l'"ordre" pertinent des modules de migration.

7. Ressources supplémentaires

Problèmes/commentaires concernant l'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 15 (code de départ "START") et du module 16 (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 15

code

N/A

Module 16 (cet atelier de programmation)

code

(identique à Python 2)

Ressources en ligne

Vous trouverez ci-dessous des ressources en ligne qui peuvent être utiles pour ce tutoriel :

Blobstore App Engine et Cloud Storage

Plate-forme App Engine

Informations sur les autres clouds

Python

Vidéos

Licence

Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.