1. Übersicht
Die Codelabs der Reihe „Serverless Migration Station“ (selbstgesteuerte, praktische Anleitungen) und die zugehörigen Videos sollen serverlosen Google Cloud-Entwicklern helfen, ihre Anwendungen zu modernisieren. Dazu werden sie durch eine oder mehrere Migrationen geführt, bei denen es in erster Linie darum geht, von Legacy-Diensten wegzukommen. Dadurch werden Ihre Apps portierbarer und Sie erhalten mehr Optionen und Flexibilität. Sie können eine größere Auswahl an Cloud-Produkten einbinden und darauf zugreifen und einfacher auf neuere Sprachversionen upgraden. Die Reihe konzentriert sich zwar anfangs auf die ersten Cloud-Nutzer, vor allem auf App Engine-Entwickler (Standardumgebung), ist aber breit genug, um auch andere serverlose Plattformen wie Cloud Functions und Cloud Run oder andere Plattformen einzubeziehen, sofern zutreffend.
In diesem Codelab erfahren Sie, wie Sie von App Engine Blobstore zu Cloud Storage migrieren. Außerdem gibt es implizite Migrationen von:
webapp2-Webframework zu Flask (wird in Modul 1 behandelt)- App Engine NDB zu Cloud NDB für den Datastore-Zugriff (wird in Modul 2 behandelt)
- Python 2 zu 3 (die migrierte App ist sowohl mit Python 2 als auch mit Python 3 kompatibel)
Weitere Informationen finden Sie in den entsprechenden Migrationsmodulen.
Lerninhalte
- Verwendung der App Engine Blobstore API/Bibliothek hinzufügen
- Nutzer-Uploads im Blobstore-Dienst speichern
- Nächsten Schritt für die Migration zu Cloud Storage vorbereiten
Voraussetzungen
- Ein Google Cloud Platform-Projekt mit einem aktiven GCP-Rechnungskonto
- Grundlegende Python-Kenntnisse
- Grundkenntnisse zu gängigen Linux-Befehlen
- Grundlegende Kenntnisse zur Entwicklung und Bereitstellung von App Engine-Anwendungen
- Eine funktionierende App Engine-App für Modul 15: Führen Sie das Codelab für Modul 15 aus (empfohlen) oder kopieren Sie die App für Modul 15 aus dem Repository.
Umfrage
Wie werden Sie diese Anleitung verwenden?
Wie würden Sie Ihre Erfahrung mit Python bewerten?
Wie würden Sie Ihre Erfahrungen mit Google Cloud-Diensten bewerten?
2. Hintergrund
In diesem Codelab wird mit der Beispiel-App aus Modul 15 begonnen und gezeigt, wie Sie von Blobstore (und NDB) zu Cloud Storage (und Cloud NDB) migrieren. Bei der Migration müssen Sie Abhängigkeiten von den gebündelten Legacy-Diensten von App Engine ersetzen. So können Sie Ihre Anwendungen bei Bedarf auf eine andere serverlose Cloud-Plattform oder eine andere Hostingplattform migrieren.
Diese Migration erfordert etwas mehr Aufwand als die anderen Migrationen in dieser Reihe. Blobstore ist vom ursprünglichen Webapp-Framework abhängig. Deshalb wird in der Beispielanwendung das Webapp2-Framework anstelle von Flask verwendet. In dieser Anleitung werden Migrationen zu Cloud Storage, Cloud NDB, Flask und Python 3 beschrieben.
Die App registriert weiterhin Endnutzerbesuche und zeigt die zehn letzten an. Im vorherigen Codelab (Modul 15) wurde jedoch eine neue Funktion hinzugefügt, um die Verwendung von Blobstore zu ermöglichen: Die App fordert Endnutzer auf, ein Artefakt (eine Datei) hochzuladen, das ihrem Besuch entspricht. Nutzer können dies tun oder „Überspringen“ auswählen, um die Funktion zu deaktivieren. Unabhängig von der Entscheidung des Nutzers wird auf der nächsten Seite die gleiche Ausgabe wie bei früheren Versionen dieser App gerendert und die letzten Besuche werden angezeigt. Eine weitere Besonderheit ist, dass Besuche mit entsprechenden Artefakten einen Link zum Anzeigen des Artefakts enthalten. In diesem Codelab werden die oben genannten Migrationen implementiert, wobei die beschriebene Funktionalität beibehalten wird.
3. Einrichtung/Vorbereitung
Bevor wir zum Hauptteil des Tutorials kommen, richten wir unser Projekt ein, rufen den Code ab und stellen die Baseline-App bereit, damit wir wissen, dass wir mit funktionierendem Code begonnen haben.
1. Projekt einrichten
Wenn Sie die App aus Modul 15 bereits bereitgestellt haben, empfehlen wir, dasselbe Projekt (und denselben Code) wiederzuverwenden. Alternativ können Sie ein neues Projekt erstellen oder ein anderes vorhandenes Projekt wiederverwenden. Prüfen Sie, ob das Projekt ein aktives Rechnungskonto hat und App Engine aktiviert ist.
2. Beispiel-App für die Baseline abrufen
Eine der Voraussetzungen für dieses Codelab ist eine funktionierende Beispiel-App aus Modul 15. Wenn Sie sie nicht haben, können Sie sie aus dem Ordner „START“ für Modul 15 (Link unten) herunterladen. In diesem Codelab werden Sie durch jeden Schritt geführt. Am Ende erhalten Sie Code, der dem im Ordner „FINISH“ von Modul 16 ähnelt.
- START: Ordner für Modul 15 (Python 2)
- ABSCHLUSS: Ordner für Modul 16 (Python 2)
- Gesamtes Repository (zum Klonen oder Herunterladen einer ZIP-Datei)
Das Verzeichnis der START-Dateien für Modul 15 sollte so 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, mit der ein Cloud Storage-Bucket ausgewählt werden kann, der sich vom Standard einer der App zugewiesenen URL basierend auf der ID des Projekts unterscheidet: PROJECT_ID.appspot.com. Diese Datei spielt in diesem Codelab (Modul 16) keine Rolle. Bei Bedarf können jedoch ähnliche Migrationsverfahren auf diese Datei angewendet werden.
3. Referenz-App (erneut) bereitstellen
Das sind die verbleibenden Schritte, die Sie jetzt ausführen müssen:
gcloud-Befehlszeilentool- Beispiel-App mit
gcloud app deploynoch einmal bereitstellen - Prüfen, ob die App problemlos in App Engine ausgeführt wird
Sobald Sie diese Schritte ausgeführt und bestätigt haben, dass Ihre App aus Modul 15 funktioniert. Auf der Startseite wird Nutzern ein Formular angezeigt, in dem sie aufgefordert werden, eine Datei mit Besuchsartefakten hochzuladen. Außerdem wird ihnen eine Option und eine Schaltfläche zum Überspringen angezeigt:

Nachdem Nutzer eine Datei hochgeladen oder den Vorgang übersprungen haben, wird in der App die bekannte Seite „Letzte Besuche“ gerendert:

Bei Besuchen mit einem Artefakt wird rechts neben dem Zeitstempel des Besuchs ein Link zum Aufrufen (oder Herunterladen) des Artefakts angezeigt. Sobald Sie die Funktionalität der App bestätigt haben, können Sie die Migration von App Engine-Legacy-Diensten (webapp2, NDB, Blobstore) zu modernen Alternativen (Flask, Cloud NDB, Cloud Storage) durchführen.
4. Konfigurationsdateien aktualisieren
Für die aktualisierte Version unserer App sind drei Konfigurationsdateien erforderlich. Die erforderlichen Aufgaben sind:
- Aktualisieren Sie die erforderlichen integrierten Drittanbieterbibliotheken in
app.yamlund lassen Sie die Möglichkeit einer Python 3-Migration offen. - Fügen Sie ein
requirements.txthinzu, in dem alle erforderlichen Bibliotheken angegeben sind, die nicht integriert sind. - Fügen Sie
appengine_config.pyhinzu, damit die App sowohl integrierte als auch nicht integrierte Drittanbieterbibliotheken unterstützt.
app.yaml
Bearbeiten Sie die Datei app.yaml, indem Sie den Abschnitt libraries aktualisieren. Entfernen Sie jinja2 und fügen Sie grpcio, setuptools und ssl hinzu. Wählen Sie die neueste Version aus, die für alle drei Bibliotheken verfügbar ist. Fügen Sie auch die Python 3-Anweisung runtime hinzu, aber kommentieren Sie sie aus. Wenn Sie fertig sind, sollte es 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
DANACH:
#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 (Sie müssen sie also nicht selbst bündeln). Wir haben Jinja2 entfernt, da es mit Flask geliefert wird, das wir „reqs.txt“ hinzufügen werden. Wenn Google Cloud-Clientbibliotheken wie die für Cloud NDB und Cloud Storage verwendet werden, sind grpcio und setuptools erforderlich. Schließlich ist die SSL-Bibliothek für Cloud Storage selbst erforderlich. Die auskommentierte Laufzeitanweisung oben ist für den Fall, dass Sie diese App zu Python 3 portieren möchten. Am Ende dieser Anleitung erfahren Sie, wie Sie dazu vorgehen.
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
Für die Python 2-App Engine-Laufzeit ist das Selbstbündeln von Drittanbieterbibliotheken erforderlich, die nicht integriert sind. Führen Sie daher den folgenden Befehl aus, um diese Bibliotheken im Ordner „lib“ zu installieren:
pip install -t lib -r requirements.txt
Wenn Sie sowohl Python 2 als auch Python 3 auf Ihrem Entwicklungscomputer haben, müssen Sie möglicherweise den Befehl „pip2“ verwenden, um sicherzustellen, dass Sie die Python 2-Versionen dieser Bibliotheken erhalten. Nach dem Upgrade auf Python 3 müssen Sie die erforderlichen Bibliotheken nicht mehr selbst bündeln.
appengine_config.py
Fügen Sie eine appengine_config.py-Datei hinzu, die integrierte und nicht integrierte Drittanbieterbibliotheken 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-Apps installieren in der App Engine-Dokumentation ähneln oder mit ihnen identisch sein. Insbesondere sollte der Inhalt von appengine_config.py mit dem Inhalt von Schritt 5 dort übereinstimmen.
Die Arbeit an den Konfigurationsdateien ist abgeschlossen. Wir können uns also der Anwendung zuwenden.
5. Anwendungsdateien ändern
Importe
Die erste Gruppe von Änderungen für main.py umfasst das Ersetzen aller Elemente, die ersetzt werden sollen. Folgendes wird sich ändern:
webapp2wird durch Flask ersetzt- Verwenden Sie anstelle von Jinja2 aus
webapp2_extrasdas Jinja2, das mit Flask geliefert wird. - App Engine Blobstore und NDB werden durch Cloud NDB und Cloud Storage ersetzt
- Die Blobstore-Handler in
webappwerden durch eine Kombination aus demio-Standardbibliotheksmodul, Flask undwerkzeug-Dienstprogrammen ersetzt. - Standardmäßig schreibt Blobstore in einen Cloud Storage-Bucket, der nach der URL Ihrer App benannt ist (
PROJECT_ID.appspot.com). Da wir zur Cloud Storage-Clientbibliothek migrieren, wirdgoogle.authverwendet, um die Projekt-ID abzurufen und genau denselben Bucket-Namen anzugeben. Sie können den Bucket-Namen ändern, da er nicht mehr fest codiert 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 Importbereich in main.py durch das folgende Code-Snippet ersetzen.
DANACH:
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 Codeblock, der ersetzt werden muss, ist BaseHandler, in dem die Verwendung von Jinja2 aus webapp2_extras angegeben wird. Das ist nicht erforderlich, da Jinja2 mit Flask geliefert wird und die Standardvorlagen-Engine ist. Entfernen Sie es daher.
Auf der Seite von Modul 16 werden Objekte instanziiert, die in der älteren App nicht vorhanden waren. Dazu gehört das Initialisieren der Flask-App und das Erstellen von API-Clients für Cloud NDB und Cloud Storage. Schließlich stellen wir den Namen des Cloud Storage-Buckets wie oben beschrieben im Importbereich zusammen. Hier sehen Sie, wie die Seite vor und nach der Implementierung dieser Änderungen aussieht:
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))
DANACH:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
Datenspeicherzugriff aktualisieren
Cloud NDB ist weitgehend mit App Engine NDB kompatibel. Ein Unterschied, der bereits behandelt wurde, ist die Notwendigkeit eines API-Clients. Außerdem muss der Datastore-Zugriff durch den Python-Kontextmanager des API-Clients gesteuert werden. Das bedeutet, dass alle Datastore-Zugriffsaufrufe mit der Cloud NDB-Clientbibliothek nur innerhalb von Python-Blöcken with erfolgen können.
Das ist eine Änderung. Die andere besteht darin, dass Blobstore und seine Objekte, z. B. BlobKeys, von Cloud Storage nicht unterstützt werden. Ändern Sie daher file_blob 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)
DANACH:
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 eine bildliche Darstellung der bisher vorgenommenen Änderungen:

Handler aktualisieren
Upload-Handler
Handler in webapp2 sind Klassen, in Flask sind sie Funktionen. Anstelle einer HTTP-Verb-Methode verwendet Flask das Verb, um die Funktion zu dekorieren. Blobstore und die zugehörigen webapp-Handler werden durch Funktionen von Cloud Storage sowie Flask und den zugehörigen 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)
DANACH:
@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 diesem Update:
- Anstelle von
blob_idwerden Datei-Artefakte jetzt anhand des Dateinamens (fname) identifiziert, sofern vorhanden, und andernfalls anhand vonNone(Nutzer hat das Hochladen einer Datei deaktiviert). - Die Blobstore-Handler haben den Uploadprozess für die Nutzer abstrahiert. Bei Cloud Storage ist das nicht der Fall. Daher sehen Sie den neu hinzugefügten Code, mit dem das Blob-Objekt und der Speicherort (Bucket) der Datei festgelegt werden, sowie den Aufruf, mit dem der eigentliche Upload erfolgt. (
upload_from_file()). webapp2verwendet eine Routingtabelle am Ende der Anwendungsdatei, während Flask-Routen in jedem dekorierten Handler zu finden sind.- Beide Handler schließen ihre Funktionalität ab, indem sie mit einem HTTP-Rückgabecode 307 zur Startseite (
/) weiterleiten und dabei diePOST-Anfrage beibehalten.
Download-Handler
Die Aktualisierung des Download-Handlers folgt einem ähnlichen Muster wie der Upload-Handler. Allerdings ist hier viel weniger Code zu berücksichtigen. 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)
DANACH:
@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:
- Flask dekoriert Handler-Funktionen mit ihrem Pfad, während
webappdies in einer Routingtabelle unten tut. Achten Sie daher auf die Syntax für den Musterabgleich vonwebapp(('/view/([^/]+)?') im Vergleich zu Flask ('/view/<path:fname>'). - Wie beim Upload-Handler ist auf der Cloud Storage-Seite etwas mehr Arbeit erforderlich, um die von den Blobstore-Handlern abstrahierte Funktionalität zu nutzen. Dazu gehört das Identifizieren der betreffenden Datei (des Blobs) und das explizite Herunterladen des Binärinhalts im Gegensatz zum einzelnen
send_blob()-Methodenaufruf des Blobstore-Handlers. - In beiden Fällen wird dem Nutzer ein HTTP 404-Fehler zurückgegeben, wenn ein Artefakt nicht gefunden wird.
Haupt-Handler
Die endgültigen Änderungen an der Hauptanwendung erfolgen im Haupthandler. Die webapp2-HTTP-Verb-Methoden werden durch eine einzelne Funktion ersetzt, die ihre Funktionalität 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)
DANACH:
@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)
Anstelle von separaten get()- und post()-Methoden handelt es sich im Wesentlichen um eine if-else-Anweisung in root(). Da root() eine einzelne Funktion ist, gibt es nur einen Aufruf zum Rendern der Vorlage für GET und POST. In webapp2 ist das nicht möglich.
Hier ist eine bildliche Darstellung dieser zweiten und letzten Änderungen an main.py:

(optional) „Verbesserung“ der Abwärtskompatibilität
Die oben erstellte Lösung funktioniert also perfekt – aber nur, wenn Sie von Grund auf neu beginnen und keine Dateien haben, die von Blobstore erstellt wurden. Da wir die App so aktualisiert haben, dass Dateien anhand des Dateinamens anstelle von BlobKey identifiziert werden, können Blobstore-Dateien in der fertigen App aus Modul 16 nicht angezeigt werden. Mit anderen Worten: Wir haben bei dieser Migration eine nicht abwärtskompatible Änderung vorgenommen. Wir präsentieren nun eine alternative Version von main.py namens main-migrate.py (im Repository), die versucht, diese Lücke zu schließen.
Die erste „Erweiterung“ zur Unterstützung von Blobstore-Dateien ist ein Datenmodell mit einem BlobKeyProperty (zusätzlich zu einem StringProperty für Cloud Storage-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 verwendet wird. Wenn Sie jetzt neue Besuche erstellen, wird explizit ein Wert in file_gcs anstelle von file_blob gespeichert. „store_visit“ sieht also etwas anders aus:
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()
DANACH:
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()
Wenn Sie die letzten Besuche abrufen, normalisieren Sie die Daten, 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)
DANACH:
@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)
Prüfen Sie als Nächstes, ob file_blob oder file_gcs vorhanden ist (oder keines von beiden). Wenn eine Datei verfügbar ist, wählen Sie die vorhandene Datei aus und verwenden Sie die entsprechende Kennung (BlobKey für von Blobstore erstellte Dateien oder den Dateinamen für von Cloud Storage erstellte Dateien). Mit „von Cloud Storage erstellte Dateien“ sind Dateien gemeint, 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.
Was ist die etl_visits()-Funktion, mit der die Daten für den Endnutzer normalisiert oder ETL-Prozesse (Extrahieren, Transformieren und Laden) durchgeführt werden? 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]
Der Code durchläuft alle Besuche und verwendet für jeden Besuch die Besucher- und Zeitstempeldaten unverändert. Anschließend wird geprüft, ob file_gcs oder file_blob vorhanden ist. Wenn ja, wird einer der beiden Werte ausgewählt (oder None, wenn keiner der beiden vorhanden ist).
Hier sehen Sie eine Abbildung der Unterschiede zwischen main.py und main-migrate.py:

Wenn Sie von Grund auf neu beginnen und keine von Blobstore erstellten Dateien haben, verwenden Sie main.py. Wenn Sie jedoch umstellen und unterstützende Dateien benötigen, die sowohl von Blobstore als auch von Cloud Storage erstellt wurden, sehen Sie sich main-migrate.py als Beispiel dafür an, wie Sie mit einem solchen Szenario umgehen können, um Migrationen für Ihre eigenen Apps zu planen. Bei komplexen Migrationen treten wahrscheinlich Sonderfälle auf. Dieses Beispiel soll daher zeigen, wie moderne Apps mit echten Daten modernisiert werden können.
6. Zusammenfassung/Bereinigung
In diesem Abschnitt wird das Codelab abgeschlossen, indem die App bereitgestellt und geprüft wird, ob sie wie vorgesehen funktioniert und ob die Ausgabe korrekt ist. Führen Sie nach der App-Validierung alle erforderlichen Bereinigungsschritte aus und überlegen Sie sich, wie Sie weiter vorgehen möchten.
Anwendung bereitstellen und überprüfen
Bevor Sie Ihre App neu bereitstellen, müssen Sie pip install -t lib -r requirements.txt ausführen, damit die selbst gebündelten Drittanbieterbibliotheken im Ordner „lib“ verfügbar sind. 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 genauso funktioniert wie die App aus Modul 15. Der Formularbildschirm sieht so aus:

Die Seite „Letzte Besuche“ sieht so aus:

Herzlichen Glückwunsch zum Abschluss dieses Codelabs, in dem Sie App Engine Blobstore durch Cloud Storage, App Engine NDB durch Cloud NDB und webapp2 durch Flask ersetzt haben. Ihr Code sollte jetzt mit dem Code im FINISH (Module 16) folder übereinstimmen. Die alternative Datei main-migrate.py ist ebenfalls in diesem Ordner vorhanden.
„Migration“ zu Python 3
Die auskommentierte Python 3-Anweisung runtime oben in app.yaml ist alles, was für die Portierung dieser App zu Python 3 erforderlich ist. Der Quellcode selbst ist bereits mit Python 3 kompatibel, sodass hier keine Änderungen erforderlich sind. Führen Sie die folgenden Schritte aus, um die Anwendung als Python 3-App bereitzustellen:
- Entfernen Sie die Kommentarzeichen für die Python 3-
runtime-Anweisung oben inapp.yaml. - Löschen Sie alle anderen Zeilen in
app.yaml. - Löschen Sie die Datei
appengine_config.py. (in der Python 3-Laufzeit nicht verwendet) - Löschen Sie den Ordner
lib, falls er vorhanden ist. (bei der Python 3-Laufzeit nicht erforderlich)
Bereinigen
Allgemein
Wenn Sie die App vorerst nicht mehr benötigen, empfehlen wir Ihnen, sie zu deaktivieren, um Abrechnungen zu vermeiden. Wenn Sie jedoch weitere Tests durchführen möchten, bietet die App Engine-Plattform ein kostenloses Kontingent. Solange Sie diese Nutzungsebene nicht überschreiten, werden Ihnen keine Gebühren berechnet. Das gilt für die Rechenleistung. Es können aber auch Gebühren für relevante App Engine-Dienste anfallen. Weitere Informationen finden Sie auf der Preisseite. Wenn bei dieser Migration andere Cloud-Dienste beteiligt sind, werden diese separat abgerechnet. Sehen Sie sich in beiden Fällen gegebenenfalls den Abschnitt „Spezifisch für dieses Codelab“ unten an.
Die Bereitstellung auf einer serverlosen Google Cloud-Compute-Plattform wie App Engine verursacht geringe Build- und Speicherkosten. Cloud Build und Cloud Storage haben jeweils ein eigenes kostenloses Kontingent. Das Speichern dieses Bildes verbraucht einen Teil dieses Kontingents. Möglicherweise leben Sie jedoch in einer Region, in der es kein solches kostenloses Kontingent gibt. Achten Sie daher auf Ihre Speichernutzung, um potenzielle Kosten zu minimieren. Folgende Cloud Storage-„Ordner“ sollten Sie sich ansehen:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- Die oben genannten Speicherlinks hängen von Ihrem
PROJECT_IDund *LOC*ab, z. B. „us“, wenn Ihre App in den USA gehostet wird.
Wenn Sie diese Anwendung oder andere zugehörige Migrations-Codelabs nicht weiter verwenden und alles vollständig löschen möchten, beenden Sie Ihr Projekt.
Spezifisch für dieses Codelab
Die unten aufgeführten Dienste sind nur für dieses Codelab verfügbar. Weitere Informationen finden Sie in der Dokumentation der einzelnen Produkte:
- Der App Engine Blobstore-Dienst fällt unter die Kontingente und Limits für gespeicherte Daten. Sehen Sie sich daher diese sowie die Preisseite für gebündelte Legacy-Dienste an.
- Cloud Storage bietet für bestimmte Regionen eine kostenlose Stufe. Weitere Informationen finden Sie auch auf der allgemeinen Preisseite.
- Der Dienst App Engine Datastore wird von Cloud Datastore (Cloud Firestore im Datastore-Modus) bereitgestellt, das auch eine kostenlose Stufe bietet. Weitere Informationen finden Sie auf der Preisseite.“
Wenn Sie von Modul 15 zu Modul 16 migriert sind, haben Sie weiterhin Daten in Blobstore. Deshalb haben wir die Preisinformationen oben aufgeführt.
Nächste Schritte
Neben dieser Anleitung gibt es weitere Migrationsmodule, die sich mit der Umstellung von den gebündelten Legacy-Diensten befassen:
- Modul 2: Von App Engine
ndbzu Cloud NDB migrieren - Module 7–9: Push-Aufgaben von App Engine Task Queue zu Cloud Tasks migrieren
- Module 12–13: Von App Engine Memcache zu Cloud Memorystore migrieren
- Module 18–19: Von App Engine-Aufgabenwarteschlange (Pull-Aufgaben) zu Cloud Pub/Sub migrieren
App Engine ist nicht mehr die einzige serverlose Plattform in Google Cloud. Wenn Sie eine kleine App Engine-Anwendung oder eine Anwendung 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 Anwendungsentwicklungs-Workflows geworden ist, insbesondere wenn er aus einer CI/CD-Pipeline (Continuous Integration/Continuous Delivery oder Deployment) besteht, sollten Sie eine Migration zu Cloud Run in Betracht ziehen. Diese Szenarien werden in den folgenden Modulen behandelt:
- Von App Engine zu Cloud Functions migrieren: Modul 11
- Von App Engine zu Cloud Run migrieren: Modul 4 enthält Informationen zum Containerisieren Ihrer App mit Docker und Modul 5 zum Containerisieren ohne Container, Docker-Kenntnisse oder
Dockerfiles.
Der Wechsel zu einer anderen serverlosen Plattform ist optional. Wir empfehlen, die besten Optionen für Ihre Apps und Anwendungsfälle zu prüfen, bevor Sie Änderungen vornehmen.
Unabhängig davon, welches Migrationsmodul Sie als Nächstes in Betracht ziehen, können Sie auf alle Serverless Migration Station-Inhalte (Codelabs, Videos, Quellcode [sofern verfügbar]) über das zugehörige Open-Source-Repository zugreifen. Das README des Repositorys enthält auch Informationen dazu, welche Migrationen infrage kommen und welche Reihenfolge der Migrationsmodule relevant ist.
7. Zusätzliche Ressourcen
Probleme mit Codelabs/Feedback
Wenn Sie Probleme mit diesem Codelab feststellen, suchen Sie bitte zuerst nach Ihrem Problem, bevor Sie es melden. Links zum Suchen und Erstellen neuer Probleme:
Migrationsressourcen
Links zu den Repository-Ordnern für Modul 15 (START) und Modul 16 (FINISH) finden Sie in der Tabelle unten. Sie können auch über das Repository für alle App Engine-Codelab-Migrationen auf sie zugreifen. Sie können es klonen oder eine ZIP-Datei herunterladen.
Codelab | Python 2 | Python 3 |
Modul 15 | – | |
Modul 16 (dieses Codelab) | (wie bei Python 2) |
Onlineressourcen
Unten finden Sie Online-Ressourcen, die für diese Anleitung relevant sein könnten:
App Engine Blobstore und Cloud Storage
- App Engine Blobstore-Dienst
- Zur Cloud Storage-Clientbibliothek migrieren
- Cloud Storage-Startseite
- Cloud Storage-Dokumentation
App Engine-Plattform
- App Engine-Dokumentation
- Python 2-Laufzeit für die App Engine-Standardumgebung
- Integrierte App Engine-Bibliotheken in Python 2 App Engine verwenden
- Python 3-Laufzeit für die App Engine-Standardumgebung
- Unterschiede zwischen den Python 2- und Python 3-Laufzeiten in App Engine (Standardumgebung)
- Migrationsanleitung für App Engine (Standardumgebung) von Python 2 zu Python 3
- Informationen zu Preisen und Kontingenten für App Engine
- Einführung der App Engine-Plattform der zweiten Generation (2018)
- Plattformen der ersten und zweiten Generation vergleichen
- Langfristiger Support für ältere Laufzeiten
- Repository mit Migrationsbeispielen für die Dokumentation
- Repository der Migrationsbeispiele der Community
Andere Cloud-Informationen
- Python auf der Google Cloud Platform
- Google Cloud Python-Clientbibliotheken
- Kostenlose Stufe von Google Cloud
- Google Cloud SDK (
gcloud-Befehlszeilentool) - Gesamte Google Cloud-Dokumentation
Python
- Django- und Jinja2-Vorlagensysteme
webapp2Web-Frameworkwebapp2Dokumentationwebapp2_extras-Linkswebapp2_extrasJinja2-Dokumentation- Flask-Webframework
Videos
- Serverless Migration Station
- Serverless Expeditions
- Google Cloud Tech abonnieren
- Google Developers abonnieren
Lizenz
Dieser Text ist mit einer Creative Commons Attribution 2.0 Generic License lizenziert.