1. Przegląd
Seria ćwiczeń z programowania Serverless Migration Station (samodzielne, praktyczne samouczki) i powiązane filmy mają na celu pomóc deweloperom bezserwerowych rozwiązań Google Cloud w modernizacji aplikacji przez przeprowadzenie ich przez co najmniej 1 migrację, głównie odchodząc od starszych usług. Dzięki temu aplikacje są bardziej przenośne, a Ty masz więcej opcji i większą elastyczność, co umożliwia integrację z szerszą gamą usług Cloud i dostęp do nich, a także łatwiejsze uaktualnianie do nowszych wersji językowych. Chociaż początkowo skupiamy się na najwcześniejszych użytkownikach Cloud, głównie deweloperach App Engine (środowisko standardowe), ta seria jest na tyle szeroka, że obejmuje inne platformy bezserwerowe, takie jak Cloud Functions i Cloud Run, lub inne, jeśli ma to zastosowanie.
Z tego ćwiczenia z programowania dowiesz się, jak przeprowadzić migrację z App Engine Blobstore do Cloud Storage. Istnieją też niejawne migracje z:
webapp2na Flask (omówione w module 1),- App Engine NDB na Cloud NDB w celu uzyskania dostępu do Datastore (omówione w module 2);
- Python 2 do 3 (zmigrowana aplikacja jest zgodna z Pythonem 2 i 3)
Więcej szczegółowych informacji znajdziesz w powiązanych modułach dotyczących migracji.
Dowiesz się, jak:
- Dodanie interfejsu API lub biblioteki Blobstore w App Engine
- Przechowywanie plików przesłanych przez użytkowników w usłudze Blobstore
- Przygotowanie do kolejnego kroku migracji do Cloud Storage
Czego potrzebujesz
- projekt Google Cloud Platform z aktywnym kontem rozliczeniowym GCP,
- podstawowe umiejętności programowania w Pythonie,
- Praktyczna znajomość typowych poleceń systemu Linux.
- podstawowa wiedza na temat tworzenia i wdrażania aplikacji App Engine;
- Działająca aplikacja App Engine z modułu 15: ukończ ćwiczenie w Codelabs z modułu 15 (zalecane) lub skopiuj aplikację z modułu 15 z repozytorium.
Ankieta
Jak będziesz korzystać z tego samouczka?
Jak oceniasz swoje doświadczenie z Pythonem?
Jak oceniasz swoje wrażenia z korzystania z usług Google Cloud?
2. Tło
To ćwiczenie z programowania zaczyna się od przykładowej aplikacji z modułu 15 i pokazuje, jak przeprowadzić migrację z Blobstore (i NDB) do Cloud Storage (i Cloud NDB). Proces migracji obejmuje zastąpienie zależności od starszych usług powiązanych App Engine, co umożliwia przeniesienie aplikacji na inną platformę bezserwerową Cloud lub inną platformę hostingową.
Ta migracja wymaga nieco więcej wysiłku niż inne migracje z tej serii. Blobstore ma zależności od oryginalnej platformy programistycznej webapp, dlatego przykładowa aplikacja używa platformy webapp2 zamiast Flask. Ten samouczek dotyczy migracji do Cloud Storage, Cloud NDB, Flask i Pythona 3.
Aplikacja nadal rejestruje „wizyty” użytkowników i wyświetla 10 ostatnich, ale poprzednie ćwiczenie (moduł 15) dodało nową funkcję, która umożliwia korzystanie z Blobstore: aplikacja prosi użytkowników o przesłanie artefaktu (pliku) odpowiadającego ich „wizycie”. Użytkownicy mogą to zrobić lub wybrać „Pomiń”, aby zrezygnować. Niezależnie od decyzji użytkownika na następnej stronie wyświetlane są te same dane wyjściowe co w poprzednich wersjach tej aplikacji, czyli ostatnie wizyty. Wizyty z odpowiadającymi im artefaktami mają link „Wyświetl”, który umożliwia wyświetlenie artefaktu wizyty. W tym ćwiczeniu przeprowadzimy wspomniane wcześniej migracje, zachowując opisaną funkcjonalność.
3. Konfiguracja/przygotowanie
Zanim przejdziemy do głównej części samouczka, skonfigurujmy projekt, pobierzmy kod, a następnie wdróżmy aplikację bazową, aby mieć pewność, że zaczynamy od działającego kodu.
1. Konfigurowanie projektu
Jeśli aplikacja z modułu 15 została już wdrożona, zalecamy ponowne użycie tego samego projektu (i kodu). Możesz też utworzyć zupełnie nowy projekt lub użyć innego istniejącego projektu. Sprawdź, czy projekt ma aktywne konto rozliczeniowe i czy usługa App Engine jest włączona.
2. Pobieranie przykładowej aplikacji bazowej
Jednym z wymagań wstępnych tego ćwiczenia jest działająca przykładowa aplikacja z modułu 15. Jeśli jej nie masz, możesz ją pobrać z folderu „START” modułu 15 (link poniżej). W tym ćwiczeniu przeprowadzimy Cię przez każdy krok, a na koniec otrzymasz kod podobny do tego, który znajduje się w folderze „FINISH” modułu 16.
- START: folder modułu 15 (Python 2)
- FINISH: folder modułu 16 (Python 2)
- Całe repozytorium (do sklonowania lub pobrania pliku ZIP)
Katalog plików START modułu 15 powinien wyglądać tak:
$ ls README.md app.yaml main-gcs.py main.py templates
Plik main-gcs.py to alternatywna wersja pliku main.py z modułu 15, która umożliwia wybór zasobnika Cloud Storage innego niż domyślny przypisany do aplikacji adres URL oparty na identyfikatorze projektu: PROJECT_ID.appspot.com. Ten plik nie odgrywa żadnej roli w tym ćwiczeniu (moduł 16), ale w razie potrzeby można zastosować do niego podobne techniki migracji.
3. (Ponowne) wdrażanie aplikacji bazowej
Pozostałe czynności przygotowawcze, które należy wykonać:
- Przypomnij sobie, jak działa narzędzie wiersza poleceń
gcloud. - Ponowne wdrażanie przykładowej aplikacji za pomocą
gcloud app deploy - Sprawdzanie, czy aplikacja działa w App Engine bez problemów
Po wykonaniu tych czynności i potwierdzeniu, że aplikacja z modułu 15 działa, Na pierwszej stronie użytkownicy zobaczą formularz z prośbą o przesłanie pliku artefaktu wizyty oraz opcję pominięcia tego kroku:

Gdy użytkownicy prześlą plik lub pominą ten krok, aplikacja wyświetli znaną stronę „Ostatnie wizyty”:

Wizyty, które zawierają artefakt, będą miały link „Wyświetl” po prawej stronie sygnatury czasowej wizyty, który umożliwia wyświetlenie (lub pobranie) artefaktu. Po potwierdzeniu działania aplikacji możesz przejść ze starszych usług App Engine (webapp2, NDB, Blobstore) na ich współczesne odpowiedniki (Flask, Cloud NDB, Cloud Storage).
4. Aktualizowanie plików konfiguracji
W przypadku zaktualizowanej wersji naszej aplikacji używane są 3 pliki konfiguracji. Wymagane zadania:
- Zaktualizuj wymagane wbudowane biblioteki innych firm w
app.yamli pozostaw możliwość migracji do Pythona 3 - Dodaj plik
requirements.txt, który określa wszystkie wymagane biblioteki, które nie są wbudowane. - Dodaj
appengine_config.py, aby aplikacja obsługiwała zarówno wbudowane, jak i niewbudowane biblioteki innych firm
app.yaml
Zmodyfikuj plik app.yaml, aktualizując sekcję libraries. Usuń jinja2 i dodaj grpcio, setuptools oraz ssl. Wybierz najnowszą wersję dostępną dla wszystkich 3 bibliotek. Dodaj też dyrektywę runtime dla Pythona 3, ale zmień w komentarz. Gdy skończysz, powinno to wyglądać tak (jeśli wybrano Pythona 3.9):
PRZED:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
AFTER:
#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
Zmiany dotyczą głównie wbudowanych bibliotek Pythona 2 dostępnych na serwerach App Engine (dzięki czemu nie musisz ich samodzielnie pakować). Usunęliśmy Jinja2, ponieważ jest on dostarczany z Flask, który dodamy do pliku reqs.txt. Za każdym razem, gdy używane są biblioteki klienta Google Cloud, takie jak Cloud NDB i Cloud Storage, wymagane są grpcio i setuptools. Na koniec: Cloud Storage wymaga biblioteki ssl. Zmieniona w komentarz dyrektywa środowiska wykonawczego u góry jest przeznaczona do użycia, gdy będziesz gotowy(-a) do przeniesienia tej aplikacji do Pythona 3. Tym tematem zajmiemy się na końcu samouczka.
requirements.txt
Dodaj plik requirements.txt, który wymaga platformy Flask oraz bibliotek klienta Cloud NDB i Cloud Storage (żadna z nich nie jest wbudowana). Utwórz plik z tą zawartością:
flask
google-cloud-ndb
google-cloud-storage
Środowisko wykonawcze App Engine Python 2 wymaga samodzielnego pakowania niewbudowanych bibliotek innych firm, więc uruchom to polecenie, aby zainstalować te biblioteki w folderze lib:
pip install -t lib -r requirements.txt
Jeśli na komputerze używanym do programowania masz zainstalowane wersje 2 i 3 Pythona, może być konieczne użycie polecenia pip2, aby uzyskać wersje tych bibliotek dla Pythona 2. Po uaktualnieniu do Pythona 3 nie musisz już samodzielnie tworzyć pakietów.
appengine_config.py
Dodaj plik appengine_config.py obsługujący wbudowane i niewbudowane biblioteki innych firm. Utwórz plik z tą zawartością:
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)
Wykonane właśnie czynności powinny być podobne lub identyczne z czynnościami wymienionymi w sekcji Instalowanie bibliotek dla aplikacji w Pythonie 2 w dokumentacji App Engine, a dokładniej zawartość pliku appengine_config.py powinna być zgodna z zawartością kroku 5.
Praca nad plikami konfiguracji została zakończona, więc przejdźmy do aplikacji.
5. Modyfikowanie plików aplikacji
Importy
Pierwszy zestaw zmian w main.py obejmuje wymianę wszystkich elementów, które mają zostać zastąpione. Co się zmienia:
webapp2zastępuje Flask- Zamiast Jinja2 z
webapp2_extrasużyj Jinja2 dostarczanego z Flask - Blobstore i NDB w App Engine zostały zastąpione przez Cloud NDB i Cloud Storage
- Moduły obsługi Blobstore w
webappzostały zastąpione kombinacją modułu biblioteki standardowejio, Flask i narzędziwerkzeug - Domyślnie Blobstore zapisuje dane w zasobniku Cloud Storage o nazwie odpowiadającej adresowi URL aplikacji (
PROJECT_ID.appspot.com). Ponieważ przenosimy dane do biblioteki klienta Cloud Storage,google.authsłuży do pobierania identyfikatora projektu, aby określić dokładnie tę samą nazwę zasobnika. (Możesz zmienić nazwę zasobnika, ponieważ nie jest już zakodowana na stałe).
PRZED:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
Wprowadź zmiany z listy powyżej, zastępując bieżącą sekcję importu w pliku main.py poniższym fragmentem kodu.
AFTER:
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
Inicjalizacja i niepotrzebna obsługa Jinja2
Następny blok kodu do zastąpienia to BaseHandler, który określa użycie Jinja2 z webapp2_extras. Jest to niepotrzebne, ponieważ Jinja2 jest dostarczany z Flask i jest jego domyślnym mechanizmem szablonów, więc usuń go.
W module 16 utwórz instancje obiektów, których nie było w starszej aplikacji. Obejmuje to inicjowanie aplikacji Flask i tworzenie klientów interfejsu API dla Cloud NDB i Cloud Storage. Na koniec tworzymy nazwę zasobnika Cloud Storage, jak opisano powyżej w sekcji importu. Oto jak wyglądały te elementy przed wprowadzeniem zmian i jak wyglądają po ich wprowadzeniu:
PRZED:
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))
AFTER:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
Aktualizowanie dostępu do Datastore
Cloud NDB jest w większości zgodny z App Engine NDB. Jedną z różnic, o których już wspomnieliśmy, jest konieczność użycia klienta API. Inna różnica polega na tym, że w przypadku drugiego podejścia dostęp do Datastore musi być kontrolowany przez menedżera kontekstu Pythona klienta interfejsu API. Oznacza to, że wszystkie wywołania dostępu do Datastore za pomocą biblioteki klienta Cloud NDB mogą występować tylko w blokach with Pythona.
To jedna zmiana.Druga polega na tym, że Blobstore i jego obiekty, np. BlobKey, nie są obsługiwane przez Cloud Storage, więc zmień file_blob na ndb.StringProperty. Poniżej znajdziesz klasę modelu danych oraz zaktualizowane funkcje store_visit() i fetch_visits(), które odzwierciedlają te zmiany:
PRZED:
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)
AFTER:
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)
Oto graficzne przedstawienie zmian, które zostały wprowadzone do tej pory:

Aktualizowanie modułów obsługi
Moduł obsługi przesyłania
Moduły obsługi w webapp2 to klasy, a we Flasku to funkcje. Zamiast metody czasownika HTTP Flask używa czasownika do dekorowania funkcji. Blobstore i jego moduły obsługi webapp zostały zastąpione funkcjami Cloud Storage oraz Flask i jego narzędziami:
PRZED:
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)
AFTER:
@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)
Kilka uwag dotyczących tej aktualizacji:
- Zamiast
blob_idartefakty plików są teraz identyfikowane według nazwy pliku (fname), jeśli jest dostępna, lubNone(użytkownik zrezygnował z przesyłania pliku). - Moduły obsługi Blobstore ukrywały proces przesyłania przed użytkownikami, ale Cloud Storage tego nie robi, więc możesz zobaczyć nowo dodany kod, który ustawia obiekt blob i lokalizację (zasobnik) pliku, a także wywołanie, które wykonuje rzeczywiste przesyłanie. (
upload_from_file()). webapp2używa tabeli routingu na dole pliku aplikacji, a trasy Flask znajdują się w każdym udekorowanym module obsługi.- Obie funkcje obsługi kończą swoje działanie, przekierowując do strony głównej (
/) i zachowując żądaniePOSTz kodem HTTP 307.
Moduł obsługi pobierania
Aktualizowanie modułu obsługi pobierania przebiega podobnie jak w przypadku modułu obsługi przesyłania, ale kodu jest znacznie mniej. Zastąp funkcje Blobstore i webapp odpowiednikami Cloud Storage i Flask:
PRZED:
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)
AFTER:
@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)
Uwagi dotyczące tej aktualizacji:
- Flask dekoruje funkcje obsługi ich trasą, a
webapprobi to w tabeli routingu na dole, więc rozpoznaj składnię dopasowywania wzorców tej drugiej (('/view/([^/]+)?') w porównaniu z Flask ('/view/<path:fname>'). - Podobnie jak w przypadku modułu obsługi przesyłania, po stronie Cloud Storage wymagane jest nieco więcej pracy w celu uzyskania funkcjonalności, która jest abstrakcyjna w przypadku modułów obsługi Blobstore, czyli identyfikacji danego pliku (bloba) i jawnego pobrania pliku binarnego, w porównaniu z pojedynczym wywołaniem metody
send_blob()modułu obsługi Blobstore. - W obu przypadkach, jeśli artefakt nie zostanie znaleziony, użytkownik otrzyma błąd HTTP 404.
Główny moduł obsługi
Ostateczne zmiany w głównej aplikacji są wprowadzane w głównym module obsługi. Metody czasowników HTTP webapp2 zostały zastąpione jedną funkcją, która łączy ich funkcjonalność. Zastąp klasę MainHandler funkcją root() i usuń tabelę routingu webapp2, jak pokazano poniżej:
PRZED:
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)
AFTER:
@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)
Zamiast oddzielnych metod get() i post() są one zasadniczo instrukcją if-else w root(). Poza tym, ponieważ root() to pojedyncza funkcja, istnieje tylko jedno wywołanie renderowania szablonu zarówno dla GET, jak i POST, co nie jest możliwe w webapp2.
Oto graficzne przedstawienie drugiego i ostatniego zestawu zmian w main.py:

(opcjonalnie) „Ulepszenie” zgodności wstecznej
Utworzone powyżej rozwiązanie działa idealnie, ale tylko wtedy, gdy zaczynasz od zera i nie masz plików utworzonych przez Blobstore. Zaktualizowaliśmy aplikację, aby identyfikowała pliki według nazwy, a nie BlobKey, dlatego gotowa aplikacja z modułu 16 nie będzie mogła wyświetlać plików Blobstore. Innymi słowy, podczas tej migracji wprowadziliśmy zmianę, która nie jest zgodna wstecznie. Teraz przedstawiamy alternatywną wersję main.py o nazwie main-migrate.py (znajdującą się w repozytorium), która próbuje wypełnić tę lukę.
Pierwszym „rozszerzeniem” obsługującym pliki utworzone przez Blobstore jest model danych, który ma BlobKeyProperty (oprócz StringProperty dla plików utworzonych przez 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()
Właściwość file_blob będzie używana do identyfikowania plików utworzonych przez Blobstore, a file_gcs – do plików Cloud Storage. Teraz podczas tworzenia nowych wizyt wyraźnie zapisuj wartość w parametrze file_gcs zamiast file_blob, aby zdarzenie store_visit wyglądało nieco inaczej:
PRZED:
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()
AFTER:
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()
Podczas pobierania najnowszych wizyt „normalizuj” dane przed wysłaniem ich do szablonu:
PRZED:
@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)
AFTER:
@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)
Następnie potwierdź, czy istnieje file_blob lub file_gcs (lub żadne z nich). Jeśli plik jest dostępny, wybierz go i użyj jego identyfikatora (BlobKey w przypadku plików utworzonych przez Blobstore lub nazwy pliku w przypadku plików utworzonych przez Cloud Storage). „Pliki utworzone w Cloud Storage” to pliki utworzone za pomocą biblioteki klienta Cloud Storage. Blobstore również zapisuje dane w Cloud Storage, ale w tym przypadku są to pliki utworzone przez Blobstore.
Teraz ważniejsze pytanie: czym jest funkcja etl_visits(), która służy do normalizacji lub ETL (wyodrębniania, przekształcania i ładowania) danych dla użytkownika? Wygląda on następująco:
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]
Prawdopodobnie wygląda to tak, jak się spodziewasz: kod przechodzi przez wszystkie wizyty i w przypadku każdej z nich pobiera dosłownie dane o użytkowniku i sygnaturę czasową, a następnie sprawdza, czy istnieje file_gcs lub file_blob, i jeśli tak, wybiera jeden z nich (lub None, jeśli żaden z nich nie istnieje).
Oto ilustracja przedstawiająca różnice między main.py a main-migrate.py:

Jeśli zaczynasz od zera bez plików utworzonych przez Blobstore, użyj main.py. Jeśli jednak przechodzisz na inną usługę i chcesz obsługiwać pliki utworzone zarówno przez Blobstore, jak i Cloud Storage, zapoznaj się z main-migrate.py, aby dowiedzieć się, jak poradzić sobie z takim scenariuszem i zaplanować migrację własnych aplikacji. Podczas złożonych migracji mogą wystąpić szczególne przypadki, dlatego ten przykład ma na celu pokazanie, jak modernizować rzeczywiste aplikacje z rzeczywistymi danymi.
6. Podsumowanie i czyszczenie
W tej sekcji podsumujemy ćwiczenia z programowania, wdrażając aplikację i sprawdzając, czy działa zgodnie z oczekiwaniami i czy dane wyjściowe są prawidłowe. Po sprawdzeniu aplikacji wykonaj czynności związane z czyszczeniem i zastanów się nad kolejnymi krokami.
Wdrażanie i weryfikowanie aplikacji
Zanim ponownie wdrożysz aplikację, uruchom pip install -t lib -r requirements.txt, aby umieścić te samodzielnie spakowane biblioteki innych firm w folderze lib. Jeśli chcesz uruchomić rozwiązanie zgodne wstecznie, najpierw zmień nazwę main-migrate.py na main.py. Teraz uruchom gcloud app deploy i sprawdź, czy aplikacja działa tak samo jak aplikacja z modułu 15. Ekran formularza wygląda tak:

Strona „Ostatnie wizyty” wygląda tak:

Gratulujemy ukończenia tego ćwiczenia, w którym zastąpiliśmy Blobstore w App Engine usługą Cloud Storage, NDB w App Engine usługą Cloud NDB, a webapp2 frameworkiem Flask. Twój kod powinien teraz odpowiadać zawartości folderu FINISH (moduł 16). W tym folderze znajduje się też alternatywny plik main-migrate.py.
„Migracja” do Pythona 3
Aby przenieść tę aplikację do Pythona 3, wystarczy zmienić w komentarz dyrektywę Pythona 3 runtime na początku pliku app.yaml. Sam kod źródłowy jest już zgodny z Pythonem 3, więc nie trzeba wprowadzać żadnych zmian. Aby wdrożyć tę aplikację jako aplikację w Pythonie 3, wykonaj te czynności:
- Usuń komentarz z dyrektywy
runtimePythona 3 u góry plikuapp.yaml. - Usuń wszystkie pozostałe wiersze w pliku
app.yaml. - Usuń plik
appengine_config.py. (nieużywane w środowisku wykonawczym Pythona 3) - Usuń folder
lib, jeśli istnieje. (niepotrzebne w przypadku środowiska wykonawczego Pythona 3)
Czyszczenie danych
Ogólne
Jeśli na razie nie chcesz kontynuować, zalecamy wyłączenie aplikacji App Engine, aby uniknąć naliczania opłat. Jeśli jednak chcesz przeprowadzić więcej testów lub eksperymentów, platforma App Engine ma bezpłatny limit, więc dopóki nie przekroczysz tego poziomu wykorzystania, nie powinny być naliczane opłaty. To są koszty obliczeń, ale mogą też zostać naliczone opłaty za odpowiednie usługi App Engine, więc więcej informacji znajdziesz na stronie z cennikiem. Jeśli migracja obejmuje inne usługi Cloud, są one rozliczane osobno. W obu przypadkach zapoznaj się z sekcją „Informacje dotyczące tego ćwiczenia” poniżej.
Warto wiedzieć, że wdrożenie na bezserwerowej platformie obliczeniowej Google Cloud, takiej jak App Engine, wiąże się z niewielkimi kosztami kompilacji i przechowywania danych. Cloud Build ma własny bezpłatny limit, podobnie jak Cloud Storage. Przechowywanie tego obrazu wykorzystuje część tego limitu. Możesz jednak mieszkać w regionie, w którym nie ma takiego poziomu bezpłatnego, więc zwracaj uwagę na wykorzystanie miejsca na dane, aby zminimalizować potencjalne koszty. Konkretne „foldery” Cloud Storage, które należy sprawdzić, to:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- Linki do miejsca przechowywania powyżej zależą od
PROJECT_IDi *LOC*ation, na przykład „us”, jeśli aplikacja jest hostowana w USA.
Jeśli jednak nie zamierzasz kontynuować pracy z tą aplikacją ani innymi powiązanymi z nią programami do migracji i chcesz usunąć wszystko, zamknij projekt.
Dotyczy tego ćwiczenia
Usługi wymienione poniżej są unikalne dla tego ćwiczenia z programowania. Więcej informacji znajdziesz w dokumentacji poszczególnych usług:
- Usługa Blobstore App Engine podlega limitom przechowywanych danych, dlatego zapoznaj się z nimi, a także ze stroną z cenami starszych usług powiązanych.
- Cloud Storage ma poziom bezpłatny w określonych regionach. Więcej informacji znajdziesz na stronie z ogólnym cennikiem.
- Usługa App Engine Datastore jest świadczona przez Cloud Datastore (Cloud Firestore w trybie Datastore), która również ma poziom bezpłatny. Więcej informacji znajdziesz na stronie z cennikiem.
Pamiętaj, że jeśli migracja została przeprowadzona z modułu 15 do 16, nadal będziesz mieć dane w Blobstore, dlatego powyżej podajemy informacje o cenach.
Dalsze kroki
Oprócz tego samouczka warto rozważyć inne moduły migracji, które koncentrują się na odchodzeniu od starszych usług powiązanych:
- Moduł 2: migracja z App Engine
ndbdo Cloud NDB - Moduły 7–9: migracja zadań push z kolejki zadań App Engine do Cloud Tasks.
- Moduły 12–13: migracja z App Engine Memcache do Cloud Memorystore
- Moduły 18–19: migracja z kolejki zadań App Engine (zadania typu pull) do Cloud Pub/Sub.
App Engine nie jest już jedyną platformą bezserwerową w Google Cloud. Jeśli masz małą aplikację App Engine lub aplikację o ograniczonej funkcjonalności i chcesz przekształcić ją w samodzielny mikroserwis albo chcesz podzielić monolityczną aplikację na wiele komponentów wielokrotnego użytku, warto rozważyć przejście na Cloud Functions. Jeśli konteneryzacja stała się częścią przepływu pracy związanego z programowaniem aplikacji, zwłaszcza jeśli składa się on z potoku CI/CD (trybu ciągłej integracji / trybu ciągłego dostarczania lub wdrażania), rozważ migrację do Cloud Run. Te scenariusze są omówione w tych modułach:
- Migracja z App Engine do Cloud Functions: patrz moduł 11.
- Migracja z App Engine do Cloud Run: zapoznaj się z modułem 4, aby skonteneryzować aplikację za pomocą Dockera, lub z modułem 5, aby zrobić to bez kontenerów, znajomości Dockera lub
Dockerfile.
Przejście na inną platformę bezserwerową jest opcjonalne. Przed wprowadzeniem jakichkolwiek zmian zalecamy rozważenie najlepszych opcji dla Twoich aplikacji i przypadków użycia.
Niezależnie od tego, który moduł migracji wybierzesz, wszystkie materiały dotyczące migracji bezserwerowej (ćwiczenia, filmy, kod źródłowy [jeśli jest dostępny]) znajdziesz w repozytorium open source. W pliku README repozytorium znajdziesz też wskazówki dotyczące migracji, które warto rozważyć, oraz odpowiedniej „kolejności” modułów migracji.
7. Dodatkowe materiały
Problemy z ćwiczeniami w Codelabs / opinie na ich temat
Jeśli znajdziesz jakieś problemy z tym ćwiczeniem, najpierw wyszukaj je, zanim je zgłosisz. Linki do wyszukiwania i tworzenia nowych zgłoszeń:
Materiały dotyczące migracji
Linki do folderów repozytorium dla modułu 15 (START) i modułu 16 (FINISH) znajdziesz w tabeli poniżej. Możesz też uzyskać do nich dostęp z repozytorium wszystkich migracji w ramach programu App Engine codelab, które możesz sklonować lub pobrać jako plik ZIP.
Codelab | Python 2 | Python 3 |
Moduł 15 | Nie dotyczy | |
Moduł 16 (to ćwiczenie) | (tak samo jak w Pythonie 2) |
Zasoby internetowe
Poniżej znajdziesz zasoby online, które mogą być przydatne w tym samouczku:
Blobstore w App Engine i Cloud Storage
- Usługa Blobstore w App Engine
- Migracja do biblioteki klienta Cloud Storage
- Strona główna Cloud Storage
- Dokumentacja Cloud Storage
Platforma App Engine
- Dokumentacja App Engine
- Środowisko wykonawcze App Engine (środowisko standardowe) dla Pythona 2
- Korzystanie z wbudowanych bibliotek App Engine w App Engine z Pythonem 2
- Środowisko wykonawcze App Engine (środowisko standardowe) w Pythonie 3
- Różnice między środowiskami wykonawczymi App Engine (środowisko standardowe) w Pythonie 2 i 3
- Przewodnik po migracji App Engine (środowisko standardowe) z Pythona 2 na Pythona 3
- Ceny i limity App Engine
- Wprowadzenie platformy App Engine drugiej generacji (2018)
- Porównanie platform pierwszej i drugiej generacji
- Wsparcie długoterminowe dla starszych środowisk wykonawczych
- Repozytorium przykładowych migracji dokumentacji
- Repozytorium przykładowych migracji przesłanych przez społeczność
Inne informacje o Cloud
- Python na Google Cloud Platform
- Biblioteki klienta Google Cloud dla języka Python
- Poziom „Zawsze bezpłatnie” w Google Cloud
- Google Cloud SDK (narzędzie wiersza poleceń
gcloud) - Cała dokumentacja Google Cloud
Python
- systemy szablonów Django i Jinja2,
- Platforma internetowa
webapp2 - Dokumentacja
webapp2 webapp2_extras– połączeniawebapp2_extrasDokumentacja Jinja2- Flask web framework
Filmy
- Serverless Migration Station
- Serverless Expeditions
- Google Cloud Tech
- Zasubskrybuj Google Developers
Licencja
To zadanie jest licencjonowane na podstawie ogólnej licencji Creative Commons Attribution 2.0.