Von App Engine Blobstore zu Cloud Storage migrieren (Modul 16)

1. Übersicht

Die Codelabs-Reihe zur Serverless Migration Station (zum Selbststudium, praxisorientierte Anleitungen) und ähnliche Videos sollen Entwickler von Google Cloud Serverless bei der Modernisierung ihrer Anwendungen unterstützen, indem sie eine oder mehrere Migrationen durchgehen, in erster Linie von Legacy-Diensten. Dadurch werden Ihre Anwendungen portabler und bieten mehr Optionen und Flexibilität, sodass Sie eine breitere Palette von Cloud-Produkten einbinden und darauf zugreifen sowie einfacher auf neuere Sprachversionen upgraden können. Der Schwerpunkt dieser Reihe liegt anfangs auf die ersten Cloud-Nutzer, in erster Linie auf Entwicklern von App Engine (Standardumgebung). Sie ist aber umfassend genug, um auch andere serverlose Plattformen wie Cloud Functions und Cloud Run oder gegebenenfalls andere Plattformen einzubeziehen.

In diesem Codelab erfahren Sie, wie Sie von App Engine Blobstore zu Cloud Storage migrieren. Es gibt auch implizite Migrationen aus folgenden Quellen:

In den zugehörigen Migrationsmodulen finden Sie weitere Schritt-für-Schritt-Informationen.

Sie werden lernen,

  • Verwendung der App Engine Blobstore API/-Bibliothek hinzufügen
  • Nutzeruploads in den Blobstore-Dienst speichern
  • Auf den nächsten Schritt der Migration zu Cloud Storage vorbereiten

Voraussetzungen

Umfrage

Wie möchten Sie diese Anleitung nutzen?

<ph type="x-smartling-placeholder"></ph> Nur bis zum Ende lesen Lies sie dir durch und absolviere die Übungen

Wie würden Sie Ihre Erfahrung mit Python bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

Wie würden Sie Ihre Erfahrungen im Umgang mit Google Cloud-Diensten bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

2. Hintergrund

Dieses Codelab beginnt mit der Beispielanwendung aus Modul 15 und zeigt, wie Sie von Blobstore (und NDB) zu Cloud Storage (und Cloud NDB) migrieren. Beim Migrationsprozess werden Abhängigkeiten von den gebündelten Legacy-Diensten von App Engine ersetzt, mit denen Sie Ihre Anwendungen bei Bedarf auf eine andere serverlose Cloud-Plattform oder eine andere Hostingplattform verschieben können.

Diese Migration erfordert etwas mehr Aufwand als die anderen Migrationen in dieser Reihe. Blobstore hat Abhängigkeiten vom ursprünglichen Webanwendungs-Framework. Aus diesem Grund verwendet die Beispielanwendung das Framework webapp2 anstelle von Flask. In dieser Anleitung werden Migrationen zu Cloud Storage, Cloud NDB, Flask und Python 3 beschrieben.

Die App registriert weiterhin „Besuche“ von Endnutzern. und zeigt die zehn neuesten an. Im vorherigen Codelab (Modul 15) wurden jedoch neue Funktionen für die Blobstore-Nutzung hinzugefügt: Die Anwendung fordert die Endnutzer auf, ein Artefakt (eine Datei) für ihren Besuch hochzuladen. Nutzer können das jetzt tun oder „Überspringen“ auswählen deaktivieren können. Unabhängig von der Entscheidung des Nutzers wird auf der nächsten Seite die gleiche Ausgabe wie in früheren Versionen dieser App angezeigt, wobei die letzten Besuche angezeigt werden. Ein weiterer Vorteil ist, dass Besuche mit entsprechenden Artefakten eine „Aussicht“ bieten. Link zum Anzeigen des Besuchsartefakts. In diesem Codelab werden die oben genannten Migrationen implementiert und die beschriebene Funktionalität beibehalten.

3. Einrichtung/Vorarbeit

Bevor wir zum Hauptteil des Tutorials kommen, richten wir unser Projekt ein, rufen den Code ab und stellen dann die Referenzanwendung bereit, damit wir wissen, dass wir mit funktionierendem Code beginnen.

1. Projekt einrichten

Wenn Sie die Modul 15-App bereits bereitgestellt haben, empfehlen wir, dasselbe Projekt (und denselben Code) wiederzuverwenden. Alternativ können Sie ein ganz neues Projekt erstellen oder ein anderes vorhandenes Projekt wiederverwenden. Achten Sie darauf, dass das Projekt ein aktives Rechnungskonto hat und App Engine aktiviert ist.

2. Baseline-Beispiel-App abrufen

Eine der Voraussetzungen für dieses Codelab ist eine funktionierende Beispiel-App für Modul 15. Wenn Sie die E-Mail-Adresse nicht haben, finden Sie sie in Modul 15 „START“. (Link unten). Dieses Codelab führt Sie durch die einzelnen Schritte und endet mit Code, der dem in Modul 16 „FINISH“ ähnelt. Ordner.

Das Verzeichnis der START-Dateien in Modul 15 sollte wie folgt aussehen:

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

Die Datei main-gcs.py ist eine alternative Version von main.py aus Modul 15. Sie ermöglicht die Auswahl eines Cloud Storage-Buckets, der vom Standard der zugewiesenen URL einer Anwendung abweicht, der auf der Projekt-ID basiert: PROJECT_ID.appspot.com. Diese Datei spielt in diesem (Modul 16) Codelab keine andere Rolle, außer dass ähnliche Migrationstechniken auf diese Datei angewendet werden können.

3. Referenz-App noch einmal bereitstellen

Sie müssen die verbleibenden Schritte jetzt ausführen:

  1. Machen Sie sich noch einmal mit dem gcloud-Befehlszeilentool vertraut
  2. Beispielanwendung mit gcloud app deploy noch einmal bereitstellen
  3. Prüfen, ob die Anwendung in App Engine problemlos ausgeführt wird

Nachdem Sie diese Schritte erfolgreich ausgeführt haben, und prüfen, ob Ihre Modul 15-App funktioniert. Auf der ersten Seite werden Nutzer mit einem Formular begrüßt, in dem sie zum Hochladen einer Besuchsartefaktdatei und der Option „Überspringen“ aufgefordert werden. auf, um die Funktion zu deaktivieren:

f5b5f9f19d8ae978.png

Sobald Nutzer eine Datei hochgeladen oder übersprungen haben, rendert die App die bekannten „zuletzt besuchten Orte“. Seite:

f5ac6b98ee8a34cb.png

Besuche mit einem Artefakt haben eine „Ansicht“ Link rechts neben dem Zeitstempel des Besuchs, um das Artefakt anzuzeigen (oder herunterzuladen). Sobald Sie die Funktionalität der Anwendung überprüft haben, können Sie von den Legacy-Diensten von App Engine (Web-App2, NDB, Blobstore) zu modernen Alternativen (Flask, Cloud NDB, Cloud Storage) migrieren.

4. Konfigurationsdateien aktualisieren

Für die aktualisierte Version der App kommen drei Konfigurationsdateien zum Einsatz. Die erforderlichen Aufgaben sind:

  1. Aktualisieren Sie die erforderlichen integrierten Bibliotheken von Drittanbietern in app.yaml und lassen Sie die Tür zu einer Python 3-Migration offen.
  2. Fügen Sie einen requirements.txt hinzu, der alle erforderlichen Bibliotheken angibt, die nicht integriert sind
  3. Füge appengine_config.py hinzu, damit die App sowohl integrierte als auch nicht integrierte Bibliotheken von Drittanbietern unterstützt

app.yaml

Bearbeiten Sie die Datei app.yaml, indem Sie den Abschnitt libraries aktualisieren. Entferne jinja2 und füge grpcio, setuptools und ssl hinzu. Wählen Sie die neueste Version aus, die für alle drei Bibliotheken verfügbar ist. Fügen Sie außerdem die Python 3-Anweisung runtime hinzu, aber auskommentiert. Wenn Sie fertig sind, sollte dies so aussehen (wenn Sie Python 3.9 ausgewählt haben):

VORHER:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

NACHHER:

#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

Die Änderungen betreffen hauptsächlich die integrierten Python 2-Bibliotheken, die auf App Engine-Servern verfügbar sind, sodass Sie sie nicht selbst bündeln müssen. Wir haben Jinja2 entfernt, weil es mit Flask geliefert wird, das wir zu reqs.txt hinzufügen werden. Wenn Google Cloud-Clientbibliotheken verwendet werden, z. B. die für Cloud NDB und Cloud Storage, werden grpcio und setuptools benötigt. Schließlich benötigt Cloud Storage selbst die SSL-Bibliothek. Die oben auskommentierte Laufzeitanweisung ist für den Fall gedacht, dass Sie diese Anwendung auf Python 3 portieren möchten. Am Ende dieses Tutorials wird dieses Thema behandelt.

requirements.txt

Fügen Sie eine requirements.txt-Datei hinzu, für die das Flask-Framework sowie die Cloud NDB- und Cloud Storage-Clientbibliotheken erforderlich sind. Keine dieser Bibliotheken ist integriert. Erstellen Sie die Datei mit folgendem Inhalt:

flask
google-cloud-ndb
google-cloud-storage

Die Python 2 App Engine-Laufzeit erfordert eine Selbstbündelung nicht integrierter Drittanbieterbibliotheken. Führen Sie daher den folgenden Befehl aus, um diese Bibliotheken im lib-Ordner zu installieren:

pip install -t lib -r requirements.txt

Wenn Sie sowohl Python 2 als auch 3 auf Ihrem Entwicklungscomputer haben, müssen Sie möglicherweise den Befehl pip2 verwenden, um sicherzustellen, dass die Python 2-Versionen dieser Bibliotheken abgerufen werden. Nach dem Upgrade auf Python 3 müssen Sie sich nicht mehr selbst bündeln.

appengine_config.py

Füge eine appengine_config.py-Datei hinzu, die integrierte und nicht integrierte Bibliotheken von Drittanbietern unterstützt. Erstellen Sie die Datei mit folgendem Inhalt:

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)

Die gerade ausgeführten Schritte sollten den Schritten im Abschnitt Bibliotheken für Python 2-Anwendungen installieren der App Engine-Dokumentation ähneln oder identisch sein. Genauer gesagt sollte der Inhalt von appengine_config.py mit dem Inhalt in Schritt 5 übereinstimmen.

Die Arbeit an den Konfigurationsdateien ist abgeschlossen, also machen wir mit der Anwendung weiter.

5. Anwendungsdateien ändern

Importe

Zu den ersten Änderungen für main.py gehört das Austauschen aller Komponenten, die ersetzt werden sollen. Folgendes wird sich ändern:

  1. webapp2 wird durch Flask ersetzt
  2. Verwenden Sie nicht Jinja2 aus webapp2_extras, sondern die Jinja2-Version, die in Flask enthalten ist.
  3. App Engine Blobstore und NDB wurden durch Cloud NDB und Cloud Storage ersetzt
  4. Die Blobstore-Handler in webapp werden durch eine Kombination aus dem io-Standardbibliotheksmodul, Flask- und werkzeug-Dienstprogrammen ersetzt
  5. Blobstore schreibt standardmäßig in einen Cloud Storage-Bucket, der nach der URL Ihrer Anwendung benannt ist (PROJECT_ID.appspot.com). Da wir Daten zur Cloud Storage-Clientbibliothek übertragen, wird google.auth verwendet, um die Projekt-ID abzurufen und denselben Bucket-Namen anzugeben. Sie können den Bucket-Namen ändern, da er nicht mehr hartcodiert ist.

VORHER:

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

Implementieren Sie die Änderungen in der Liste oben, indem Sie den aktuellen Importabschnitt in main.py durch das Code-Snippet unten ersetzen.

NACHHER:

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

Initialisierung und unnötige Jinja2-Unterstützung

Der nächste zu ersetzende Codeblock ist der BaseHandler, der die Verwendung von Jinja2 aus webapp2_extras angibt. Dies ist überflüssig, da Jinja2 im Lieferumfang von Flask enthalten ist und die Standard-Engine für Vorlagen ist. Entfernen Sie diese Funktion also.

Instanziieren Sie in Modul 16 Objekte, die in der älteren App nicht vorhanden waren. Dazu gehören die Initialisierung der Flask-Anwendung und das Erstellen von API-Clients für Cloud NDB und Cloud Storage. Schließlich fügen wir den Namen des Cloud Storage-Buckets wie oben im Abschnitt „Importe“ beschrieben zusammen. Hier sind die Vorher und nach der Implementierung dieser Aktualisierungen:

VORHER:

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))

NACHHER:

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

Datastore-Zugriff aktualisieren

Cloud NDB ist größtenteils mit App Engine NDB kompatibel. Ein bereits behandelter Unterschied ist die Notwendigkeit eines API-Clients. Bei letzterem muss der Zugriff auf den Datenspeicher vom Python-Kontextmanager des API-Clients gesteuert werden. Im Wesentlichen bedeutet das, dass alle Datastore-Zugriffsaufrufe mit der Cloud NDB-Clientbibliothek nur innerhalb von Python-with-Blöcken erfolgen können.

Das ist eine Änderung: zum anderen, dass Blobstore und seine Objekte, z.B. BlobKeys werden von Cloud Storage nicht unterstützt. Ändern Sie file_blob daher in ndb.StringProperty. Unten sehen Sie die Datenmodellklasse und die aktualisierten Funktionen store_visit() und fetch_visits(), die diese Änderungen widerspiegeln:

VORHER:

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)

NACHHER:

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)

Hier ist eine bildliche Darstellung der bisher vorgenommenen Änderungen:

a8f74ca392275822.png

Handler aktualisieren

Upload-Handler

Handler in webapp2 sind Klassen, während sie Funktionen in Flask sind. Anstelle einer HTTP-Verbmethode verwendet Flask das Verb zum Dekorieren der Funktion. Blobstore und die zugehörigen webapp-Handler werden durch Funktionen von Cloud Storage sowie von Flask und seinen Dienstprogrammen ersetzt:

VORHER:

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)

NACHHER:

@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)

Einige Hinweise zu dieser Aktualisierung:

  • Statt eines blob_id werden Dateiartefakte jetzt anhand des Dateinamens (fname) identifiziert, sofern vorhanden, und ansonsten anhand von None (der Nutzer hat das Hochladen einer Datei deaktiviert).
  • Die Blobstore-Handler abstrahieren den Uploadprozess von den Nutzern, aber Cloud Storage tut dies nicht. Daher sehen Sie den neu hinzugefügten Code, der das Blob-Objekt und den Speicherort der Datei (Bucket) festlegt, sowie den Aufruf, der den eigentlichen Upload durchführt. (upload_from_file()).
  • webapp2 verwendet eine Routingtabelle am Ende der Anwendungsdatei, während in jedem dekorierten Handler Flask-Routen zu finden sind.
  • Beide Handler schließen ihre Funktionalität ab, indem sie zur Startseite ( /) weitergeleitet werden, während die POST-Anfrage mit einem HTTP 307-Rückgabecode beibehalten wird.

Download-Handler

Die Aktualisierung des Download-Handlers folgt einem ähnlichen Muster wie der Upload-Handler, nur es muss viel weniger Code überprüft werden. Ersetzen Sie die Blobstore- und webapp-Funktionen durch die Cloud Storage- und Flask-Entsprechungen:

VORHER:

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)

NACHHER:

@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)

Hinweise zu diesem Update:

  • Auch hier werden Handler-Funktionen mit ihrer Route dekoriert, während webapp dies in einer Routingtabelle am unteren Rand ausführt. Daher wird die Musterabgleichssyntax von Flask (('/view/([^/]+)?') von der von Flask ('/view/<path:fname>') unterschieden.
  • Wie beim Upload-Handler ist bei Cloud Storage noch etwas mehr Arbeit für Funktionen erforderlich, die von den Blobstore-Handlern abstrahiert werden: die Identifizierung der betreffenden Datei (Blob) und das explizite Herunterladen des Binärprogramms im Vergleich zum einzelnen send_blob()-Methodenaufruf des Blobstore-Handlers.
  • In beiden Fällen wird der HTTP-Fehler 404 an den Nutzer zurückgegeben, wenn kein Artefakt gefunden wird.

Haupt-Handler

Die letzten Änderungen an der Hauptanwendung werden im Haupt-Handler vorgenommen. Die HTTP-Verbmethoden webapp2 werden durch eine einzelne Funktion ersetzt, die ihre Funktionen kombiniert. Ersetzen Sie die Klasse MainHandler durch die Funktion root() und entfernen Sie die Routingtabelle webapp2 wie unten gezeigt:

VORHER:

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)

NACHHER:

@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)

Im Grunde sind es keine separaten get()- und post()-Methoden, sondern eine if-else-Anweisung in root(). Da root() eine einzelne Funktion ist, gibt es nur einen Aufruf zum Rendern der Vorlage sowohl für GET als auch für POST. In webapp2 ist dies nicht wirklich möglich.

Hier ist eine bildliche Darstellung dieser zweiten und letzten Änderungen an main.py:

5ec38818c32fec2.png

(optional) „Optimierung“ der Abwärtskompatibilität

Die oben erstellte Lösung funktioniert also perfekt... aber nur, wenn Sie bei null anfangen und keine Dateien haben, die von Blobstore erstellt wurden. Da wir die Anwendung so aktualisiert haben, dass Dateien anhand des Dateinamens und nicht nach BlobKey identifiziert werden, kann die abgeschlossene Anwendung für Modul 16 in der vorliegenden Form keine Blobstore-Dateien aufrufen. Anders ausgedrückt: Bei dieser Migration haben wir eine nicht abwärtskompatible Änderung vorgenommen. Wir präsentieren jetzt eine alternative Version von main.py mit dem Namen main-migrate.py (im Repository gefunden), die versucht, diese Lücke zu schließen.

Die erste „Erweiterung“ Zur Unterstützung von in Blobstore erstellten Dateien gibt es ein Datenmodell mit einem BlobKeyProperty (zusätzlich zu einem StringProperty für von Cloud Storage erstellte Dateien):

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()

Das Attribut file_blob wird verwendet, um von Blobstore erstellte Dateien zu identifizieren, während file_gcs für Cloud Storage-Dateien vorgesehen ist. Speichern Sie nun beim Erstellen neuer Besuche explizit einen Wert in file_gcs statt in file_blob, sodass „store_visit“ etwas anders aussieht:

VORHER:

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()

NACHHER:

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()

Beim Abrufen der letzten Besuche "normalisieren" bevor Sie sie an die Vorlage senden:

VORHER:

@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)

NACHHER:

@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)

Bestätigen Sie als Nächstes, dass file_blob oder file_gcs (oder keines von beiden) vorhanden ist. Wenn eine Datei verfügbar ist, wählen Sie die vorhandene aus und verwenden Sie diese ID (BlobKey für von Blobstore erstellte Dateien oder Dateiname für von Cloud Storage erstellte Dateien). Wenn wir von „In Cloud Storage erstellte Dateien“ sprechen, sind Dateien, die mit der Cloud Storage-Clientbibliothek erstellt wurden. Blobstore schreibt auch in Cloud Storage, aber in diesem Fall wären das von Blobstore erstellte Dateien.

Und was ist die etl_visits()-Funktion, die zum Normalisieren oder ETL (Extrahieren, Transformieren und Laden) der Daten für den Endnutzer verwendet wird? Sie sieht so aus:

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]

Wahrscheinlich sieht es so aus, wie Sie es erwartet haben: Der Code durchläuft alle Besuche und nimmt bei jedem Besuch die Besucher- und Zeitstempeldaten wörtlich. Anschließend wird geprüft, ob file_gcs oder file_blob vorhanden ist. Wenn ja, wird eine davon ausgewählt (oder None, wenn keine vorhanden ist).

Hier sehen Sie die Unterschiede zwischen main.py und main-migrate.py:

718b05b2adadb2e1.png

Wenn Sie von Grund auf ohne Blobstore-Dateien beginnen möchten, sollten Sie main.py verwenden. Wenn Sie jedoch Dateien übertragen möchten, die sowohl von Blobstore als auch Cloud Storage erstellt wurden, sollten Sie sich main-migrate.py als Beispiel für den Umgang mit Szenarien ansehen, um Migrationen für Ihre eigenen Anwendungen zu planen. Bei komplexen Migrationen treten wahrscheinlich Sonderfälle auf. Deshalb soll dieses Beispiel zeigen, dass die Modernisierung echter Anwendungen mit echten Daten stärker ist.

6. Zusammenfassung/Bereinigung

In diesem Abschnitt wird dieses Codelab abgeschlossen. Dazu wird die App bereitgestellt und geprüft, ob sie wie vorgesehen und in allen ausgegebenen Ausgabedaten funktioniert. Führen Sie nach der App-Überprüfung alle Bereinigungsschritte durch und erwägen Sie die nächsten Schritte.

Anwendung bereitstellen und prüfen

Bevor Sie Ihre App noch einmal bereitstellen, führen Sie pip install -t lib -r requirements.txt aus, um diese selbst gebündelten Drittanbieterbibliotheken aus dem lib-Ordner zu entfernen. Wenn Sie die abwärtskompatible Lösung ausführen möchten, benennen Sie main-migrate.py zuerst in main.py um. Führen Sie nun gcloud app deploy aus und prüfen Sie, ob die App identisch mit Modul 15 funktioniert. Der Formularbildschirm sieht so aus:

f5b5f9f19d8ae978.png

Die Seite mit den letzten Besuchen sieht so aus:

f5ac6b98ee8a34cb.png

Herzlichen Glückwunsch! Sie haben dieses Codelab abgeschlossen, in dem App Engine Blobstore durch Cloud Storage, App Engine NDB durch Cloud NDB und webapp2 durch Flask ersetzt wurde. Ihr Code sollte jetzt mit dem Inhalt im Ordner FINISH (Modul 16) übereinstimmen. Die Alternative main-migrate.py ist auch in diesem Ordner vorhanden.

Python 3 „Migration“

Sie benötigen lediglich die auskommentierte runtime-Anweisung von Python 3 am Anfang von app.yaml, um diese Anwendung zu Python 3 zu portieren. Der Quellcode selbst ist bereits mit Python 3 kompatibel, sodass dort keine Änderungen erforderlich sind. Führen Sie die folgenden Schritte aus, um sie als Python 3-Anwendung bereitzustellen:

  1. Entfernen Sie die Kommentarzeichen von der Python 3-Anweisung runtime oben in app.yaml.
  2. Löschen Sie alle anderen Zeilen in app.yaml.
  3. Löschen Sie die Datei appengine_config.py. (in der Python 3-Laufzeit nicht verwendet)
  4. Löschen Sie den Ordner lib, falls vorhanden. (für Python 3-Laufzeit nicht erforderlich)

Bereinigen

Allgemein

Falls Sie vorerst fertig sind, empfehlen wir Ihnen, Ihre App Engine-Anwendung zu deaktivieren, um Gebühren zu vermeiden. Wenn Sie jedoch weitere Tests oder Experimente durchführen möchten, bietet die App Engine-Plattform ein kostenloses Kontingent. Solange Sie diese Nutzungsstufe nicht überschreiten, sollten Ihnen keine Kosten in Rechnung gestellt werden. Das bezieht sich auf die Rechenleistung. Es können jedoch auch Gebühren für relevante App Engine-Dienste anfallen. Weitere Informationen finden Sie auf der Preisseite. Wenn diese Migration andere Cloud-Dienste betrifft, werden diese separat abgerechnet. Lesen Sie in beiden Fällen gegebenenfalls den Abschnitt „Speziell für dieses Codelab“. weiter unten.

Zur vollständigen Offenlegung fallen bei der Bereitstellung auf einer serverlosen Computing-Plattform von Google Cloud wie App Engine geringfügige Build- und Speicherkosten an. Für Cloud Build und Cloud Storage gibt es ein eigenes kostenloses Kontingent. Die Speicherung dieses Images verbraucht einen Teil dieses Kontingents. Möglicherweise leben Sie in einer Region, in der es keine solche kostenlose Stufe gibt. Achten Sie daher auf Ihre Speichernutzung, um potenzielle Kosten zu minimieren. Bestimmte Cloud Storage-„Ordner“ sollten Sie Folgendes überprüfen:

  • 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
  • Die Speicherlinks oben hängen von Ihrer PROJECT_ID- und *LOC*-Adresse ab, z. B. „us“ wenn Ihre App in den USA gehostet wird.

Wenn Sie jedoch nicht mit dieser Anwendung oder anderen verwandten Migrations-Codelabs fortfahren und alles vollständig löschen möchten, beenden Sie Ihr Projekt.

Nur für dieses Codelab

Die unten aufgeführten Dienste gelten nur für dieses Codelab. Weitere Informationen finden Sie in der Dokumentation des jeweiligen Produkts:

Wenn Sie von Modul 15 zu 16 migriert haben, befinden sich immer noch Daten in Blobstore. Daher werden die Preisinformationen oben aufgeführt.

Nächste Schritte

Abgesehen von dieser Anleitung gibt es weitere Migrationsmodule, die sich auf die Umstellung von den gebündelten Legacy-Diensten konzentrieren:

  • Modul 2: von App Engine ndb zu Cloud NDB migrieren
  • Module 7–9: Migration von Push-Aufgaben der App Engine-Aufgabenwarteschlange zu Cloud Tasks
  • Module 12–13: Migration von App Engine Memcache zu Cloud Memorystore
  • Module 18–19: Migration von App Engine-Aufgabenwarteschlange (Pull-Aufgaben) zu Cloud Pub/Sub

App Engine ist nicht mehr die einzige serverlose Plattform in Google Cloud. Wenn Sie eine kleine App Engine-Anwendung oder eine mit eingeschränkter Funktionalität haben und sie in einen eigenständigen Mikrodienst umwandeln möchten oder eine monolithische Anwendung in mehrere wiederverwendbare Komponenten aufteilen möchten, sind dies gute Gründe für einen Wechsel zu Cloud Functions. Wenn die Containerisierung Teil Ihres Workflows für die Anwendungsentwicklung geworden ist, insbesondere wenn sie aus einer CI/CD-Pipeline (Continuous Integration/Continuous Delivery oder Bereitstellung) besteht, sollten Sie eine Migration zu Cloud Run in Betracht ziehen. Diese Szenarien werden in den folgenden Modulen behandelt:

  • Migration von App Engine zu Cloud Functions: siehe Modul 11
  • Migration von App Engine zu Cloud Run: Siehe Modul 4 zum Containerisieren Ihrer Anwendung mit Docker oder Modul 5 zur Implementierung von Containern, Docker-Kenntnissen oder Dockerfile

Der Wechsel zu einer anderen serverlosen Plattform ist optional. Wir empfehlen Ihnen, die besten Optionen für Ihre Anwendungen und Anwendungsfälle zu erwägen, bevor Sie Änderungen vornehmen.

Unabhängig davon, welches Migrationsmodul Sie als Nächstes in Betracht ziehen, können Sie auf alle Inhalte der Serverless Migration Station (Codelabs, Videos, Quellcode [falls verfügbar]) über das Open-Source-Repository zugreifen. Im README des Repositorys finden Sie außerdem Informationen dazu, welche Migrationen berücksichtigt werden müssen und welche relevante „Reihenfolge“ Sie haben Migrationsmodule.

7. Zusätzliche Ressourcen

Codelab-Probleme/Feedback

Wenn Sie Probleme mit diesem Codelab feststellen, suchen Sie bitte zuerst nach dem Problem, bevor Sie es einreichen. Links zum Suchen und Erstellen neuer Ausgaben:

Migrationsressourcen

In der folgenden Tabelle finden Sie Links zu den Repository-Ordnern für Modul 15 (START) und Modul 16 (FINISH). Sie können auch über das Repository für alle App Engine-Codelab-Migrationen auf sie zugreifen. Sie können eine ZIP-Datei klonen oder herunterladen.

Codelab

Python 2

Python 3

Modul 15

code

Modul 16 (dieses Codelab)

code

(entspricht Python 2)

Online-Ressourcen

Nachfolgend finden Sie Onlineressourcen, die für diese Anleitung relevant sein könnten:

App Engine Blobstore und Cloud Storage

App Engine-Plattform

Weitere Cloud-Informationen

Python

Videos

Lizenz

Dieser Text ist mit einer Creative Commons Attribution 2.0 Generic License lizenziert.