Migracja z App Engine Blobstore do Cloud Storage (moduł 16)

1. Omówienie

Seria ćwiczeń z programowania dla bezserwerowych stacji migracji (samouczek, samouczków) i podobnych filmów ma pomóc deweloperom bezserwerowych Google Cloud w modernizacji aplikacji przez przeprowadzenie co najmniej 1 migracji, w wyniku rezygnacji ze starszych usług. W ten sposób Twoje aplikacje stają się bardziej przenośne, mają więcej opcji i elastyczność, co pozwala na integrację z szerszą gamą usług Cloud i uzyskiwanie do nich dostępu, a także łatwiejsze przejście na nowsze wersje językowe. Choć początkowo koncentrowaliśmy się na pierwszych użytkownikach Cloud, głównie deweloperów korzystających ze środowiska App Engine (środowisko standardowe), ta seria jest na tyle szeroka, aby uwzględnić inne platformy bezserwerowe, takie jak Cloud Functions i Cloud Run, oraz inne, w stosownych przypadkach.

Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak przejść z App Engine Blobstore do Cloud Storage. Możliwe są też niejawne migracje z:

Szczegółowe informacje znajdziesz w powiązanych modułach migracji.

Dowiesz się, jak:

  • Dodaj sposób korzystania z interfejsu API/biblioteki App Engine Blobstore
  • Przechowywanie treści przesłanych przez użytkowników do usługi Blobstore
  • Przygotowanie do następnego kroku migracji do Cloud Storage

Czego potrzebujesz

Ankieta

Jak wykorzystasz ten samouczek?

Tylko do przeczytania Przeczytaj go i wykonaj ćwiczenia

Jak oceniasz swoje doświadczenia z językiem Python?

Początkujący Poziom średnio zaawansowany Biegły

Jak oceniasz korzystanie z usług Google Cloud?

Początkujący Poziom średnio zaawansowany Biegły
.

2. Tło

To ćwiczenie w Codelabs rozpoczyna się od przykładowej aplikacji z modułu 15 i pokazuje, jak przejść z Blobstore (i NDB) do Cloud Storage (i Cloud NDB). Proces migracji obejmuje zastąpienie zależności od starszych pakietów usług App Engine, co pozwoli Ci w razie potrzeby przenieść aplikacje na inną bezserwerową platformę Cloud lub inną platformę hostingową.

Ta migracja wymaga nieco więcej wysiłku niż inne migracje w tej serii. Blobstore jest zależny od pierwotnej platformy aplikacji internetowej, dlatego przykładowa aplikacja korzysta z platformy Webapp2, a nie Flask. W tym samouczku omawiamy migracje do Cloud Storage, Cloud NDB, Flask i Pythona 3.

Aplikacja nadal rejestruje „wizyty” użytkowników i wyświetla 10 najnowszych, ale w poprzednim (Moduł 15) dodano nową funkcję, aby dostosować do zastosowania Blobstore: aplikacja zachęca użytkowników do przesłania artefaktu (pliku) odpowiadającego ich „wizycie”. Użytkownicy mogą to zrobić lub wybrać opcję „pomiń”. rezygnować. Niezależnie od decyzji użytkownika następna strona renderuje te same dane co w poprzednich wersjach tej aplikacji – zawiera informacje o ostatnich wizytach. Dodatkowy problem polega na tym, że wizyty z odpowiadającymi im artefaktami wiążą się z „widokiem”. który służy do wyświetlania artefaktu wizyty. To ćwiczenie w Codelabs wykorzystuje wymienione wcześniej migracje, zachowując opisane funkcje.

3. Konfiguracja/praca

Zanim przejdziemy do głównej części samouczka, skonfigurujmy projekt, pobierz kod, a potem wdróż aplikację bazową. W ten sposób wiemy, że zaczynamy od działającego kodu.

1. Konfigurowanie projektu

Jeśli aplikacja modułu 15 została już wdrożona, zalecamy ponowne wykorzystanie tego samego projektu (i kodu). Możesz też utworzyć nowy projekt lub wykorzystać inny istniejący projekt. Sprawdź, czy projekt ma aktywne konto rozliczeniowe i jest włączona usługa App Engine.

2. Pobierz przykładową aplikację bazową

Jednym z warunków wstępnych tego ćwiczenia z programowania jest posiadanie działającej przykładowej aplikacji w module 15. Jeśli go nie masz, możesz go pobrać w module 15 „START” (link poniżej). To ćwiczenie w Codelabs przeprowadzi Cię przez poszczególne kroki, kończąc kodem przypominającym to, co znajduje się w module 16 „FINISH”. folderu Dysku.

Katalog plików START z modułem 15 powinien wyglądać tak:

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

Plik main-gcs.py to alternatywna wersja main.py z modułu 15, która pozwala wybrać zasobnik Cloud Storage różniący się od domyślnego adresu URL przypisanego do aplikacji na podstawie identyfikatora projektu: PROJECT_ID.appspot.com. Ten plik nie odgrywa żadnej roli w ramach tego ćwiczenia z programowania (Moduł 16), w razie potrzeby można do niego zastosować inne techniki migracji.

3. (Ponowne) wdrażanie aplikacji podstawowej

Pozostałe kroki do wykonania:

  1. Ponownie zapoznaj się z narzędziem wiersza poleceń gcloud
  2. Wdróż ponownie przykładową aplikację za pomocą gcloud app deploy
  3. Sprawdź, czy aplikacja działa w App Engine bez problemów

Po wykonaniu tych czynności i potwierdzeniu działania aplikacji z modułu 15. Strona początkowa zawiera formularz z prośbą o przesłanie pliku artefaktu wizyty i opcją „pominięcia” , aby zrezygnować:

f5b5f9f19d8ae978.png

Gdy użytkownik prześle plik lub pominie go, aplikacja renderuje znajome „ostatnie wizyty” strona:

f5ac6b98ee8a34cb.png

Wizyty zawierające artefakt będą miały „wyświetlenie” po prawej stronie sygnatury czasowej wizyty, by wyświetlić (lub pobrać) artefakt. Po potwierdzeniu działania aplikacji możesz przejść ze starszych wersji usług App Engine (webapp2, NDB, Blobstore) na nowoczesne alternatywy (Flask, Cloud NDB, Cloud Storage).

4. Aktualizowanie plików konfiguracji

W zaktualizowanej wersji aplikacji pojawiają się 3 pliki konfiguracji. Wymagane zadania to:

  1. Zaktualizuj wymagane wbudowane biblioteki zewnętrzne w app.yaml i pozostaw otwarte narzędzie do migracji z języka Python 3.
  2. Dodaj atrybut requirements.txt, który określa wszystkie wymagane biblioteki, które nie są wbudowane
  3. Dodaj appengine_config.py, aby aplikacja obsługiwała zarówno wbudowane, jak i niewbudowane biblioteki innych firm

app.yaml

Aby edytować plik app.yaml, zaktualizuj sekcję libraries. Usuń kategorię jinja2 i dodaj użytkowników grpcio, setuptools oraz ssl. Wybierz najnowszą dostępną wersję dla wszystkich 3 bibliotek. Dodaj też dyrektywę runtime w języku Python 3, ale z komentarzem. Gdy skończysz, kod powinien wyglądać podobnie do tego (w przypadku wyboru Pythona 3.9):

PRZED:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

PO:

#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

Wprowadzone zmiany dotyczą głównie wbudowanych bibliotek Pythona 2 dostępnych na serwerach App Engine (nie trzeba więc ich grupować samodzielnie). Usunęliśmy kod Jinja2, ponieważ zawiera on platformę Flask, którą dodamy do pliku reqs.txt. Jeśli używane są biblioteki klienta Google Cloud, takie jak Cloud NDB czy Cloud Storage, potrzebne są narzędzia grpcio i setuptools. Pamiętaj też, że Cloud Storage wymaga biblioteki ssl. Dyrektywa środowiska wykonawczego z komentarzem u góry służy do przenoszenia tej aplikacji do Pythona 3. Omówimy ten temat na końcu samouczka.

requirements.txt

Dodaj plik requirements.txt, wymagając platformy Flask oraz bibliotek klienta Cloud NDB i Cloud Storage – żadne z nich nie są wbudowane. Utwórz plik z taką zawartością:

flask
google-cloud-ndb
google-cloud-storage

Środowisko wykonawcze App Engine w języku Python 2 wymaga samodzielnego grupowania niewbudowanych bibliotek zewnętrznych, więc uruchom to polecenie, aby zainstalować te biblioteki w folderze lib:

pip install -t lib -r requirements.txt

Jeśli na komputerze do programowania masz zarówno język Python 2, jak i 3, musisz użyć polecenia pip2, aby mieć pewność, że otrzymasz te biblioteki w języku Python 2. Po przejściu na Pythona 3 nie musisz już grupować samodzielnie.

appengine_config.py

Dodaj plik appengine_config.py obsługujący wbudowane i niewbudowane biblioteki innych firm. Utwórz plik z taką 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 takie same jak te wymienione w sekcji Instalowanie bibliotek do aplikacji w języku Python 2 w dokumentacji App Engine, a konkretniej zawartość pliku appengine_config.py powinna być zgodna z tym, co jest w kroku 5.

Prace nad plikami konfiguracji zostały zakończone, więc przejdźmy do aplikacji.

5. Modyfikowanie plików aplikacji

Importy

Pierwszy zestaw zmian w usłudze main.py obejmuje zastąpienie wszystkich elementów. Co się zmienia:

  1. Tabela webapp2 została zastąpiona przez Flask
  2. Zamiast Jinja2 z webapp2_extras użyj Jinja2, który jest dołączony do Flask.
  3. Zastąpienie App Engine Blobstore i NDB przez Cloud NDB i Cloud Storage
  4. Moduły obsługi Blobstore w webapp zostały zastąpione kombinacją modułu standardowej biblioteki io, narzędzia Flask i narzędzi werkzeug.
  5. Domyślnie Blobstore zapisuje w zasobniku Cloud Storage o nazwie odpowiadającej adresowi URL Twojej aplikacji (PROJECT_ID.appspot.com). Przenosimy ją do biblioteki klienta Cloud Storage, dlatego google.auth jest używany do uzyskania identyfikatora projektu, który pozwala określić dokładnie taką samą nazwę zasobnika. Możesz zmienić nazwę zasobnika, bo nie jest już ona 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 powyższej listy, zastępując bieżącą sekcję importowania w interfejsie main.py poniższym fragmentem kodu.

PO:

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

Inicjowanie i niepotrzebna obsługa Jinja2

Następny blok kodu do zastąpienia to BaseHandler określający użycie Jinja2 z webapp2_extras. Jest to niepotrzebne, bo Jinja2 jest dołączony do platformy Flask, która jest domyślnym silnikiem do tworzenia szablonów. Usuń ją.

Po stronie Moduł 16 utwórz instancje obiektów, których nie było w starszej aplikacji. Obejmuje to inicjowanie aplikacji Flask oraz tworzenie klientów API dla Cloud NDB i Cloud Storage. Na koniec utworzyliśmy nazwę zasobnika Cloud Storage zgodnie z opisem powyżej w sekcji dotyczącej importowania. Oto, co można zrobić przed wdrożeniem tych zmian i po nim:

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

PO:

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

Zaktualizuj dostęp do Datastore

Usługa Cloud NDB jest głównie zgodna z App Engine NDB. Jedną z różnic jest konieczność posiadania klienta interfejsu API. Drugie rozwiązanie wymaga, aby dostęp do Datastore był kontrolowany przez menedżera kontekstu klienta API w języku Python. Oznacza to, że wszystkie wywołania dostępu do Datastore korzystające z biblioteki klienta Cloud NDB mogą występować tylko w blokach Pythona with.

To jedna zmiana. a drugie to Blobstore i jego obiekty, np. Obiekty BlobKey nie są obsługiwane przez Cloud Storage, dlatego 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)

PO:

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 obrazowe przedstawienie wprowadzonych do tej pory zmian:

a8f74ca392275822.png

Aktualizowanie modułów obsługi

Moduł obsługi przesyłania

Moduły obsługi w webapp2 są klasami, gdy działają w narzędziu Flask. Zamiast metody z czasownikami HTTP do dekorowania funkcji Flask używa czasownika. Blobstore i jego moduły obsługi webapp są zastępowane funkcjonalnością z Cloud Storage, a także usługą Flask i jej 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)

PO:

@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 na temat tej aktualizacji:

  • Artefakty pliku zamiast blob_id są teraz identyfikowane na podstawie nazwy pliku (fname), jeśli istnieje. W przeciwnym razie None (użytkownik zrezygnował z przesłania pliku).
  • Moduły obsługi Blobstore odebrały proces przesyłania od użytkowników, ale Cloud Storage go nie obsługuje. W związku z tym możesz zobaczyć nowo dodany kod, który ustawia obiekt blob i lokalizację (zasobnik) pliku, a także wywołanie, które wykonuje faktyczne przesyłanie. (upload_from_file()).
  • webapp2 używa tabeli routingu na dole pliku aplikacji, a trasy Flask znajdują się w każdym udekorowanym module obsługi.
  • Oba moduły obsługi zakończą swoje funkcje, przekierowując je na stronę główną ( /), zachowując jednocześnie żądanie POST z zwróconym kodem HTTP 307.

Moduł obsługi pobierania

Aktualizowanie modułu obsługi pobierania odbywa się zgodnie z wzorcem podobnym do modułu przesyłania, ale ilość kodu jest znacznie mniejsza. Zastąp funkcje Blobstore i webapp ich odpowiednikami w 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)

PO:

@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 na temat tej aktualizacji:

  • Znowu Flask dekoruje funkcje obsługi za pomocą trasy, a webapp robi to w tabeli routingu na dole, więc rozpoznasz składnię dopasowania wzorca ('/view/([^/]+)?') zamiast składni Flask ('/view/<path:fname>').
  • Podobnie jak w przypadku modułu obsługi przesyłania, po stronie Cloud Storage wymagane jest nieco więcej pracy ze względu na funkcje pobrane przez moduły obsługi Blobstore, czyli identyfikowanie pliku (blob) i jednoznaczne pobranie pliku binarnego lub pojedynczego wywołania metody send_blob() modułu obsługi Blobstore.
  • W obu przypadkach, jeśli nie znaleziono artefaktu, użytkownikowi jest zwracany błąd HTTP 404.

Główny moduł obsługi

Ostateczne zmiany w głównej aplikacji są dokonywane w głównym module obsługi. Metody czasowników HTTP webapp2 zostały zastąpione przez jedną funkcję łączącą ich funkcje. Zastąp klasę MainHandler funkcją root() i usuń tabelę routingu webapp2 w następujący sposób:

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)

PO:

@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 osobnych metod get() i post() są to instrukcja if-else w root(). Poza tym root() jest pojedynczą funkcją, więc dla GET i POST wystarczy jedno wywołanie, ale w webapp2 jest to niemożliwe.

Oto obrazowe przedstawienie tego drugiego i ostatniego zestawu zmian w elemencie main.py:

5ec38818c32fec2.png

(opcjonalnie) „Ulepszanie” zgodności wstecznej

Rozwiązanie utworzone powyżej działa idealnie, ale tylko wtedy, gdy zaczynasz od zera i nie masz plików utworzonych przez Blobstore. Zaktualizowaliśmy aplikację tak, aby rozpoznawała pliki według nazwy pliku, a nie BlobKey, dlatego aplikacja w stanie, w której ukończono Moduł 16, nie będzie mogła wyświetlać plików Blobstore. Innymi słowy, podczas tej migracji wprowadziliśmy zmianę niekompatybilną wstecznie. Prezentujemy alternatywną wersję zasobu main.py o nazwie main-migrate.py (znajdującą się w repozytorium), która ma na celu wypełnienie tej luki.

Pierwsze „rozszerzenie” do obsługi plików utworzonych w Blobstore jest model danych, który ma atrybut BlobKeyProperty (oprócz StringProperty dla plików utworzonych w 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 w Blobstore, a file_gcs do plików z Cloud Storage. Teraz podczas tworzenia nowych wizyt zapisz wartość bezpośrednio w file_gcs, a nie w file_blob, więc store_visit wygląda trochę 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()

PO:

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 ostatnich wizyt „znormalizuj” dane przed wysłaniem 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)

PO:

@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ź, że istnieje file_blob lub file_gcs (albo żaden z tych elementów). Jeśli jest dostępny plik, wybierz go i użyj tego identyfikatora (BlobKey w przypadku plików utworzonych w Blobstore lub nazwy pliku w przypadku plików utworzonych w Cloud Storage). Kiedy mówimy „Pliki utworzone w Cloud Storage”, mamy na myśli pliki utworzone za pomocą biblioteki klienta Cloud Storage. Blobstore zapisuje również dane w Cloud Storage, ale w tym przypadku będą to pliki utworzone przez Blobstore.

Jeszcze ważniejsze jest to, jaka jest funkcja etl_visits() wykorzystywana do normalizacji lub ETL (wyodrębniania, przekształcania i wczytywania 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 tego oczekiwano: kod zapętla wszystkie wizyty i w przypadku każdej wizyty dosłownie sprawdza dane o użytkownikach i sygnaturach czasowych, a następnie sprawdza, czy istnieje element file_gcs lub file_blob, a jeśli tak, wybiera jedną z nich (lub None, jeśli nie istnieją).

Różnice między main.py a main-migrate.py:

718b05b2adadb2e1.png

Jeśli zaczynasz od zera bez plików utworzonych w Blobstore, użyj main.py. Jeśli jednak przenosisz pliki i chcesz korzystać z nich zarówno w Blobstore, jak i Cloud Storage, zapoznaj się z przykładem main-migrate.py, który pomoże Ci zaplanować migrację do własnych aplikacji. W przypadku złożonych migracji mogą wystąpić szczególne przypadki. Ten przykład ma pokazać większe zainteresowanie modernizacją prawdziwych aplikacji przy użyciu prawdziwych danych.

6. Podsumowanie/Czyszczenie

W tej sekcji znajdziesz podsumowanie tego ćwiczenia w programie przez wdrożenie aplikacji oraz sprawdzenie, czy działa ona zgodnie z oczekiwaniami i we wszystkich uwzględnionych danych wyjściowych. Po sprawdzeniu aplikacji wykonaj czynności związane z czyszczeniem i zastanów się nad dalszymi czynnościami.

Wdróż i zweryfikuj aplikację

Przed ponownym wdrożeniem aplikacji uruchom pip install -t lib -r requirements.txt, aby umieścić te dołączone do siebie 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 Moduł 15. Ekran formularza wygląda tak:

f5b5f9f19d8ae978.png

Strona ostatnich wizyt wygląda tak:

f5ac6b98ee8a34cb.png

Gratulujemy ukończenia tego ćwiczenia z programowania. Zastępujesz App Engine Blobstore usługą Cloud Storage, App Engine NDB usługą Cloud NDB oraz webapp2 za pomocą Flask. Twój kod powinien być teraz zgodny z plikiem w folderze FINISH (Module 16). W tym folderze znajduje się również alternatywna wersja main-migrate.py.

„Migracja” Pythona 3

Do przeniesienia tej aplikacji do Pythona 3 wystarczy skomentowana dyrektywa runtime w języku Python 3 na górze kodu app.yaml. Kod źródłowy jest już zgodny z językiem Python 3, więc nie musisz w nim wprowadzać żadnych zmian. Aby wdrożyć to jako aplikację w Pythonie 3, wykonaj te czynności:

  1. Usuń znacznik komentarza z dyrektywy runtime w języku Python 3 na górze app.yaml.
  2. Usuń wszystkie pozostałe wiersze w wierszu app.yaml.
  3. Usuń plik appengine_config.py. (nieużywane w środowisku wykonawczym Pythona 3)
  4. Usuń folder lib, jeśli istnieje. (nie jest potrzebne w środowisku wykonawczym Pythona 3)

Czyszczenie danych

Ogólne

Jeśli na razie wszystko jest gotowe, wyłącz aplikację App Engine, aby uniknąć naliczania opłat. Jeśli jednak chcesz jeszcze bardziej przetestować lub poeksperymentować, platforma App Engine ma bezpłatny limit. Dopóki nie przekroczysz tego limitu, nie pobierzemy żadnych opłat. Oznacza to obliczenia, ale mogą być też naliczane opłaty za odpowiednie usługi App Engine. Więcej informacji znajdziesz na stronie z cennikiem. Jeśli ta migracja obejmuje inne usługi Cloud, są one rozliczane osobno. W obu przypadkach zapoznaj się z sekcją „Zapoznaj się z tymi ćwiczeniami”. sekcji poniżej.

Aby w pełni wyjaśnić wszystkie kwestie, 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. Dlatego pamiętaj o wykorzystaniu miejsca na dane, aby zminimalizować potencjalne koszty. Określone „foldery” Cloud Storage należy sprawdzić m.in.:

  • 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
  • Powyższe linki do miejsca na dane zależą od Twoich danych PROJECT_ID oraz *LOC*, np. „us” jeśli aplikacja jest hostowana w Stanach Zjednoczonych.

Jeśli natomiast nie zamierzasz dalej korzystać z tej aplikacji lub innych powiązanych z nią ćwiczeń w Codelabs i chcesz całkowicie usunąć wszystko, zamknij projekt.

Powiązane z tym ćwiczeniam z programowania

Wymienione poniżej usługi są dostępne tylko w ramach tego ćwiczenia z programowania. Więcej informacji znajdziesz w dokumentacji poszczególnych usług:

Pamiętaj, że po przejściu z modułów 15 na 16 nadal będziesz mieć dane w Blobstore, dlatego umieściliśmy powyżej informacje o cenach.

Dalsze kroki

Oprócz tego samouczka dostępne są też inne moduły migracji koncentrujące się na odejściu od starszych pakietów usług, które warto rozważyć:

  • Moduł 2. Migracja z App Engine ndb do Cloud NDB
  • Moduły 7–9. Migracja z kolejki zadań App Engine w trybie push 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 (pobierania zadań) do Cloud Pub/Sub

App Engine nie jest już jedyną bezserwerową platformą w Google Cloud. Jeśli masz małą aplikację App Engine lub taką, która ma ograniczoną funkcjonalność i chcesz przekształcić ją w samodzielny mikroserwis, albo chcesz podzielić aplikację monolityczną na kilka komponentów wielokrotnego użytku, rozważ przejście na Cloud Functions. Jeśli konteneryzacja stała się częścią przepływu pracy przy tworzeniu aplikacji, zwłaszcza jeśli składa się z potoku CI/CD (ciągła integracja/ciągłe dostarczanie lub wdrażanie), rozważ migrację do Cloud Run. Te scenariusze są opisane 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 Moduł 5, aby zrobić to bez kontenerów, Dockera lub Dockerfile.

Przejście na inną bezserwerową platformę jest opcjonalne. Zalecamy, aby przed wprowadzeniem jakichkolwiek zmian wybrać najlepsze opcje dla swoich aplikacji i przypadków użycia.

Niezależnie od tego, który moduł migracji wykorzystasz w następnej kolejności, wszystkie materiały z serwerowej platformy migracji (laboratorium, filmy, kod źródłowy [jeśli jest dostępne]) są dostępne w repozytorium open source. README repozytorium zawiera też wskazówki dotyczące migracji, które warto wziąć pod uwagę, i wszelkich odpowiednich „zamówień” modułów migracji.

7. Dodatkowe materiały

Problemy z ćwiczeniami w Codelabs/opinie

Jeśli podczas korzystania z tych ćwiczeń z programowania zauważysz jakiekolwiek problemy, najpierw je wyszukaj. Linki do wyszukiwania i tworzenia nowych problemów:

Zasoby migracji

Linki do folderów repozytorium w modułach 15 (START) i modułach 16 (FINISH) znajdziesz w tabeli poniżej. Dostęp do nich możesz też uzyskać z repozytorium wszystkich migracji z ćwiczeń z programowania App Engine, które możesz sklonować lub pobrać w postaci pliku ZIP.

Codelab

Python 2

Python 3

Część 15

kod

Nie dotyczy

Moduł 16 (to ćwiczenia z programowania)

kod

(tak samo jak w Pythonie 2)

Zasoby online

Poniżej znajdują się zasoby online, które mogą być pomocne w przypadku tego samouczka:

Blobstore i Cloud Storage App Engine

Platforma App Engine

Inne informacje o Google Cloud

Python

Filmy

Licencja

To zadanie jest licencjonowane na podstawie ogólnej licencji Creative Commons Attribution 2.0.