Миграция из App Engine Blobstore в облачное хранилище (модуль 16)

1. Обзор

Серия обучающих материалов Serverless Migration Station (самостоятельные практические уроки) и сопутствующих видеороликов призвана помочь разработчикам бессерверных приложений Google Cloud модернизировать свои приложения, проведя их через одну или несколько миграций, в первую очередь, через отказ от устаревших сервисов. Это делает ваши приложения более портативными, предоставляет больше возможностей и гибкости, позволяя интегрироваться с более широким спектром облачных продуктов и получать к ним доступ, а также упрощает обновление до более новых версий языков программирования. Хотя изначально серия ориентирована на самых первых пользователей облачных сервисов, в первую очередь разработчиков App Engine (стандартная среда), она достаточно широка, чтобы охватить и другие бессерверные платформы, такие как Cloud Functions и Cloud Run , или другие, если это применимо.

В этом практическом занятии вы узнаете, как выполнить миграцию с App Engine Blobstore на Cloud Storage . Также предусмотрены неявные миграции из:

Для получения более подробной пошаговой информации обратитесь к соответствующим модулям миграции.

Вы узнаете, как

  • Добавить возможность использования API/библиотеки App Engine Blobstore.
  • Хранить загрузки пользователей в сервис Blobstore
  • Подготовьтесь к следующему шагу — миграции в облачное хранилище.

Что вам понадобится

Опрос

Как вы будете использовать этот учебный материал?

Прочитайте только от начала до конца. Прочитайте текст и выполните упражнения.

Как бы вы оценили свой опыт работы с Python?

Новичок Средний Профессионал

Как бы вы оценили свой опыт использования сервисов Google Cloud?

Новичок Средний Профессионал

2. Предыстория

Данный практический пример начинается с демонстрационного приложения из модуля 15 и показывает, как перейти с Blobstore (и NDB) на Cloud Storage (и Cloud NDB). Процесс миграции включает в себя замену зависимостей от устаревших встроенных сервисов App Engine, что позволяет при желании перенести ваши приложения на другую бессерверную облачную платформу или другую платформу хостинга.

Эта миграция требует немного больше усилий по сравнению с другими миграциями в этой серии. Blobstore имеет зависимости от оригинального фреймворка веб-приложений, поэтому в примере приложения используется фреймворк webapp2 вместо Flask. В этом руководстве рассматриваются миграции в Cloud Storage, Cloud NDB, Flask и Python 3.

Приложение по-прежнему регистрирует «посещения» конечных пользователей и отображает десять последних, но в предыдущем практическом занятии (модуль 15) была добавлена ​​новая функциональность для работы с Blobstore: приложение предлагает конечным пользователям загрузить артефакт (файл), соответствующий их «посещению». Пользователи могут сделать это или выбрать «пропустить», чтобы отказаться. Независимо от решения пользователя, на следующей странице отображается тот же результат, что и в предыдущих версиях этого приложения, с отображением последних посещений. Еще одна особенность заключается в том, что для посещений с соответствующими артефактами есть ссылка «просмотреть», позволяющая просмотреть артефакт посещения. В этом практическом занятии реализованы упомянутые ранее миграции с сохранением описанной функциональности.

3. Подготовка/Предварительные работы

Прежде чем перейти к основной части урока, давайте настроим наш проект, получим код, а затем развернем базовое приложение, чтобы убедиться, что мы начали с работающего кода.

1. Настройка проекта

Если вы уже развернули приложение Модуля 15, мы рекомендуем повторно использовать тот же проект (и код). В качестве альтернативы вы можете создать совершенно новый проект или использовать другой существующий проект. Убедитесь, что у проекта есть активный платежный аккаунт и включен App Engine.

2. Получите базовый образец приложения.

Одно из предварительных условий для выполнения этого практического задания — наличие работающего примера приложения из модуля 15. Если у вас его нет, вы можете получить его из папки "START" модуля 15 (ссылка ниже). В этом практическом задании вы шаг за шагом пройдете весь процесс, и в конце получите код, похожий на тот, что находится в папке "FINISH" модуля 16.

Структура каталога файлов, запускающих модуль 15, должна выглядеть следующим образом:

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

Файл main-gcs.py — это альтернативная версия файла main.py из модуля 15 .appspot.com позволяющая выбрать сегмент Cloud Storage, отличающийся от URL-адреса, назначенного приложению по умолчанию на основе идентификатора проекта: PROJECT_ID . Этот файл не используется в данном практическом занятии (модуль 16), за исключением того, что при желании к нему можно применить аналогичные методы миграции.

3. (Повторное) развертывание базового приложения

Осталось выполнить следующие подготовительные шаги:

  1. Вспомните, как работает инструмент командной строки gcloud
  2. Повторно разверните демонстрационное приложение с помощью gcloud app deploy
  3. Убедитесь, что приложение работает в App Engine без проблем.

После успешного выполнения этих шагов и подтверждения работоспособности приложения Модуля 15, на начальной странице пользователей встречает форма с запросом на загрузку файла с данными о посещении, а также кнопка «пропустить», позволяющая отказаться от участия:

f5b5f9f19d8ae978.png

После того как пользователи загрузят файл или пропустят действие, приложение отобразит привычную страницу «последние посещения»:

f5ac6b98ee8a34cb.png

Для посещений, содержащих артефакт, справа от временной метки будет ссылка «просмотреть», позволяющая отобразить (или загрузить) артефакт. После подтверждения работоспособности приложения вы готовы перейти от устаревших сервисов App Engine (webapp2, NDB, Blobstore) к современным альтернативам (Flask, Cloud NDB, Cloud Storage).

4. Обновите конфигурационные файлы.

Для обновленной версии нашего приложения используются три конфигурационных файла. Необходимые действия:

  1. Обновите необходимые встроенные сторонние библиотеки в app.yaml , а также оставьте возможность для миграции на Python 3.
  2. Добавьте файл requirements.txt , в котором будут указаны все необходимые библиотеки, не входящие в состав основной библиотеки.
  3. Добавьте appengine_config.py , чтобы приложение поддерживало как встроенные, так и сторонние библиотеки.

app.yaml

Отредактируйте файл app.yaml , обновив раздел libraries . Удалите jinja2 и добавьте grpcio , setuptools и ssl . Выберите последнюю доступную версию для всех трех библиотек. Также добавьте директиву runtime Python 3, но закомментируйте её. В итоге должно получиться примерно так (если вы выбрали Python 3.9):

ДО:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

ПОСЛЕ:

#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

Изменения в основном касаются встроенных библиотек Python 2, доступных на серверах App Engine (чтобы вам не приходилось самостоятельно их собирать). Мы удалили Jinja2, поскольку он поставляется с Flask, который мы добавим в reqs.txt. При использовании клиентских библиотек Google Cloud, таких как библиотеки Cloud NDB и Cloud Storage, необходимы grpcio и setuptools. Наконец, само Cloud Storage требует библиотеку ssl. Закомментированная директива runtime вверху предназначена для случаев, когда вы будете готовы перенести это приложение на Python 3. Мы рассмотрим эту тему в конце этого руководства.

requirements.txt

Добавьте файл requirements.txt , в котором будут указаны зависимости от фреймворка Flask, а также клиентских библиотек Cloud NDB и Cloud Storage (ни одна из них не является встроенной). Создайте файл со следующим содержимым:

flask
google-cloud-ndb
google-cloud-storage

Для работы среды выполнения Python 2 App Engine требуется самостоятельная интеграция сторонних библиотек, не входящих в состав пакета, поэтому выполните следующую команду, чтобы установить эти библиотеки в папку lib:

pip install -t lib -r requirements.txt

Если на вашей машине для разработки установлены Python 2 и 3, вам может потребоваться использовать команду pip2, чтобы убедиться, что вы получаете версии этих библиотек для Python 2. После обновления до Python 3 вам больше не потребуется самостоятельно собирать пакеты.

appengine_config.py

Добавьте файл appengine_config.py , поддерживающий встроенные и невстроенные сторонние библиотеки. Создайте файл со следующим содержимым:

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)

Выполненные действия должны быть аналогичны или идентичны действиям, описанным в разделе «Установка библиотек для приложений Python 2» документации App Engine, и, в частности, содержимое файла appengine_config.py должно совпадать с тем, что указано в шаге 5.

Работа над конфигурационными файлами завершена, поэтому перейдём к приложению.

5. Измените файлы приложения.

Импорт

Первая группа изменений в файле main.py включает замену всего заменяемого контента. Вот что именно меняется:

  1. webapp2 заменен на Flask.
  2. Вместо использования Jinja2 из webapp2_extras , используйте Jinja2, который поставляется с Flask.
  3. App Engine Blobstore и NDB заменены на Cloud NDB и Cloud Storage.
  4. Обработчики Blobstore в webapp заменены комбинацией модуля стандартной библиотеки io , Flask и утилит werkzeug
  5. По умолчанию Blobstore записывает данные в корзину Cloud Storage, имя которой соответствует URL-адресу вашего приложения ( PROJECT_ID.appspot.com ). Поскольку мы переносим приложение на клиентскую библиотеку Cloud Storage, для получения идентификатора проекта и указания точного имени корзины используется google.auth (Вы можете изменить имя корзины, поскольку оно больше не задано жестко.)

ДО:

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

Внесите изменения, указанные в списке выше, заменив текущий раздел импорта в main.py приведенным ниже фрагментом кода.

ПОСЛЕ:

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

Инициализация и ненужная поддержка Jinja2.

Следующий блок кода, который нужно заменить, — это BaseHandler , указывающий на использование Jinja2 из webapp2_extras . Это излишне, поскольку Jinja2 поставляется с Flask и является его шаблонизатором по умолчанию, поэтому удалите его.

В модуле 16 мы создаём объекты, которых не было в старой версии приложения. Это включает инициализацию приложения Flask и создание API-клиентов для Cloud NDB и Cloud Storage. Наконец, мы формируем имя корзины Cloud Storage, как описано выше в разделе импорта. Вот как это выглядит до и после внедрения этих обновлений:

ДО:

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

ПОСЛЕ:

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

Обновить доступ к хранилищу данных

Cloud NDB в основном совместим с App Engine NDB. Одно из уже рассмотренных отличий — необходимость в API-клиенте. Другое отличие заключается в том, что в последнем случае доступ к хранилищу данных должен контролироваться контекстным менеджером Python API-клиента. По сути, это означает, что все вызовы доступа к хранилищу данных с использованием клиентской библиотеки Cloud NDB могут выполняться только внутри Python with блоков.

Это одно изменение; другое заключается в том, что Blobstore и его объекты, например, BlobKey , не поддерживаются Cloud Storage, поэтому замените file_blob на ndb.StringProperty . Ниже приведен класс модели данных и обновленные функции store_visit() и fetch_visits() отражающие эти изменения:

ДО:

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)

ПОСЛЕ:

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)

Вот наглядное представление изменений, которые уже были внесены:

a8f74ca392275822.png

Обновление обработчиков

Обработчик загрузки

Обработчики в webapp2 — это классы, тогда как во Flask это функции. Вместо метода HTTP-глагола Flask использует глагол для оформления функции. Blobstore и его обработчики webapp заменены функциональностью Cloud Storage, а также Flask и его утилитами:

ДО:

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)

ПОСЛЕ:

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

Несколько замечаний по поводу этого обновления:

  • Вместо blob_id , теперь файловые артефакты идентифицируются по имени файла ( fname ), если оно присутствует, и None в противном случае (пользователь отказался от загрузки файла).
  • Обработчики Blobstore абстрагировали процесс загрузки от пользователей, в отличие от Cloud Storage, поэтому вы можете увидеть недавно добавленный код, который устанавливает объект BLOB-объекта и местоположение файла (корзину), а также вызов, выполняющий фактическую загрузку ( upload_from_file() ).
  • webapp2 таблица маршрутизации находится в самом низу файла приложения, тогда как маршруты Flask находятся в каждом обработчике с декораторами.
  • Оба обработчика завершают свою работу, перенаправляя на главную страницу ( / ), при этом сохраняя POST запрос с кодом возврата HTTP 307.

Обработчик загрузки

Обновление обработчика загрузки выполняется по аналогичной схеме, что и обработчик загрузки, но кода для этого гораздо меньше. Замените функциональность Blobstore и webapp на аналоги из Cloud Storage и Flask:

ДО:

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)

ПОСЛЕ:

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

Примечания к этому обновлению:

  • Опять же, Flask добавляет маршрут к функциям-обработчикам, в то время как webapp делает это в таблице маршрутизации внизу, поэтому обратите внимание на синтаксис сопоставления шаблонов в последнем ('/view/([^/]+)?' ) по сравнению с синтаксисом Flask ( '/view/<path:fname>' ).
  • Как и в случае с обработчиком загрузки, на стороне Cloud Storage требуется немного больше работы для функциональности, абстрагированной обработчиками Blobstore, а именно для идентификации нужного файла (blob) и явной загрузки двоичного файла, в отличие от единственного вызова метода send_blob() обработчика Blobstore.
  • В обоих случаях, если артефакт не найден, пользователю возвращается ошибка HTTP 404.

Главный обработчик

Окончательные изменения в основном приложении происходят в главном обработчике. Методы HTTP-глаголов webapp2 заменяются одной функцией, объединяющей их функциональность. Замените класс MainHandler функцией root() и удалите таблицу маршрутизации webapp2 , как показано ниже:

ДО:

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)

ПОСЛЕ:

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

Вместо отдельных методов get() и post() , в root() используется, по сути, оператор if-else . Кроме того, поскольку root() — это единая функция, для рендеринга шаблона как для GET , так и POST требуется всего один вызов, тогда как в webapp2 это практически невозможно.

Вот графическое представление второго и последнего набора изменений в main.py :

5ec38818c32fec2.png

(необязательно) «Улучшение» обратной совместимости

Таким образом, описанное выше решение работает идеально... но только если вы начинаете с нуля и у вас нет файлов, созданных с помощью Blobstore. Поскольку мы обновили приложение, чтобы идентифицировать файлы по имени файла вместо BlobKey , готовое приложение Модуля 16 в текущем виде не сможет просматривать файлы Blobstore. Другими словами, при выполнении этой миграции мы внесли обратно несовместимое изменение. Теперь мы представляем альтернативную версию main.py под названием main-migrate.py (находится в репозитории), которая пытается устранить эту проблему.

Первое «расширение» для поддержки файлов, созданных в Blobstore, — это модель данных, имеющая свойство BlobKeyProperty (в дополнение к StringProperty для файлов, созданных в 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()

Свойство file_blob будет использоваться для идентификации файлов, созданных в Blobstore, а file_gcs — для файлов Cloud Storage. Теперь при создании новых посещений следует явно сохранять значение в file_gcs вместо file_blob , поэтому store_visit будет выглядеть немного иначе:

ДО:

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

При получении данных о последних посещениях выполните их «нормализацию» перед отправкой в ​​шаблон:

ДО:

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

ПОСЛЕ:

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

Далее подтвердите наличие файла file_blob или file_gcs (или ни одного из них). Если файл существует, выберите существующий и используйте его идентификатор ( BlobKey для файлов, созданных в Blobstore, или filename для файлов, созданных в Cloud Storage). Под «файлами, созданными в Cloud Storage» мы подразумеваем файлы, созданные с помощью клиентской библиотеки Cloud Storage. Blobstore также записывает данные в Cloud Storage, но в этом случае это будут файлы, созданные в Blobstore.

А теперь, что более важно, что представляет собой функция etl_visits() , используемая для нормализации или ETL (извлечения, преобразования и загрузки) данных для конечного пользователя? Она выглядит так:

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]

Вероятно, код выглядит так, как вы и ожидали: он перебирает все посещения, и для каждого посещения берет данные о посетителе и временную метку в неизменном виде, затем проверяет, существует ли file_gcs или file_blob , и если да, то выбирает один из них (или None , если ни один из них не существует).

Вот иллюстрация различий между main.py и main-migrate.py :

718b05b2adadb2e1.png

Если вы начинаете с нуля без файлов, созданных Blobstore, используйте main.py , но если вы находитесь в процессе перехода и вам нужны файлы, созданные как Blobstore , так и Cloud Storage, ознакомьтесь с main-migrate.py в качестве примера того, как обрабатывать подобные сценарии, чтобы помочь вам спланировать миграции для ваших собственных приложений. При выполнении сложных миграций могут возникать особые случаи, поэтому этот пример призван продемонстрировать большую готовность к модернизации реальных приложений с использованием реальных данных.

6. Подведение итогов/Завершение

В этом разделе завершается выполнение данного практического задания путем развертывания приложения, проверки его корректной работы и отображения всех полученных результатов. После проверки приложения выполните необходимые действия по очистке и обдумайте дальнейшие шаги.

Разверните и проверьте приложение.

Перед повторным развертыванием приложения обязательно выполните команду pip install -t lib -r requirements.txt , чтобы получить необходимые сторонние библиотеки из папки `lib`. Если вы хотите использовать обратно совместимое решение, сначала переименуйте main-migrate.py в main.py . Теперь выполните команду gcloud app deploy и убедитесь, что приложение работает идентично приложению из модуля 15. Экран формы выглядит следующим образом:

f5b5f9f19d8ae978.png

Страница с информацией о последних посещениях выглядит следующим образом:

f5ac6b98ee8a34cb.png

Поздравляем с завершением этого практического задания, в котором вы заменили App Engine Blobstore на Cloud Storage, App Engine NDB на Cloud NDB и webapp2 на Flask. Ваш код теперь должен соответствовать содержимому папки FINISH (модуль 16) . Альтернативный main-migrate.py также находится в этой папке.

"миграция" в Python 3

Закомментированная директива runtime Python 3 в верхней части файла app.yaml — это всё, что нужно для переноса этого приложения на Python 3. Сам исходный код уже совместим с Python 3, поэтому никаких изменений в нём не требуется. Чтобы развернуть это как приложение Python 3, выполните следующие шаги:

  1. Раскомментируйте директиву runtime Python 3 в верхней части файла app.yaml .
  2. Удалите все остальные строки в app.yaml .
  3. Удалите файл appengine_config.py (он не используется в среде выполнения Python 3).
  4. Удалите папку lib , если она существует (это не требуется при использовании среды выполнения Python 3).

Уборка

Общий

Если на этом пока всё, мы рекомендуем отключить ваше приложение App Engine, чтобы избежать дополнительных расходов. Однако, если вы хотите продолжить тестирование или эксперименты, платформа App Engine предоставляет бесплатную квоту , поэтому, пока вы не превысите этот лимит, с вас не должны взиматься дополнительные платежи. Это касается вычислительных ресурсов, но за соответствующие услуги App Engine также может взиматься плата, поэтому проверьте страницу с ценами для получения более подробной информации. Если эта миграция включает другие облачные сервисы, они оплачиваются отдельно. В любом случае, если применимо, см. раздел «Информация, относящаяся к этому практическому занятию» ниже.

Для полной ясности, развертывание на бессерверной вычислительной платформе Google Cloud, такой как App Engine, влечет за собой незначительные затраты на сборку и хранение . Cloud Build и Cloud Storage имеют собственную бесплатную квоту. Хранение образа использует часть этой квоты. Однако вы можете проживать в регионе, где нет такого бесплатного уровня, поэтому следите за использованием хранилища, чтобы минимизировать потенциальные затраты. К числу конкретных «папок» Cloud Storage, которые следует проверить, относятся:

  • 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
  • Приведенные выше ссылки на хранилища зависят от вашего PROJECT_ID и * LOC *, например, " us ", если ваше приложение размещено в США.

С другой стороны, если вы не собираетесь продолжать работу над этим приложением или другими связанными с миграцией кодовыми руководствами и хотите полностью удалить все, закройте свой проект .

Это относится именно к данному практическому занятию.

Перечисленные ниже услуги являются уникальными для данной учебной лаборатории. Для получения более подробной информации обратитесь к документации по каждому продукту:

Обратите внимание, что если вы перешли с модуля 15 на модуль 16, у вас по-прежнему будут данные в Blobstore, поэтому мы и указали информацию о ценах на него выше.

Следующие шаги

Помимо этого руководства, следует рассмотреть и другие модули миграции, ориентированные на отказ от устаревших встроенных сервисов:

  • Модуль 2 : миграция с App Engine ndb на Cloud NDB
  • Модули 7-9 : миграция с задач, отправляемых через очередь задач App Engine, на облачные задачи.
  • Модули 12-13 : миграция с App Engine Memcache на Cloud Memorystore
  • Модули 18-19 : миграция с очереди задач App Engine (запросы на получение) на Cloud Pub/Sub.

App Engine больше не является единственной бессерверной платформой в Google Cloud. Если у вас небольшое приложение App Engine или приложение с ограниченной функциональностью, которое вы хотите превратить в автономный микросервис, или вы хотите разбить монолитное приложение на несколько многократно используемых компонентов, это веские причины для перехода на Cloud Functions . Если контейнеризация стала частью вашего рабочего процесса разработки приложений, особенно если он включает в себя конвейер CI/CD (непрерывная интеграция/непрерывная доставка или развертывание), рассмотрите возможность миграции на Cloud Run . Эти сценарии рассматриваются в следующих модулях:

  • Переход с App Engine на Cloud Functions: см. Модуль 11
  • Переход с App Engine на Cloud Run: см. Модуль 4 , чтобы контейнеризировать ваше приложение с помощью Docker, или Модуль 5 , чтобы сделать это без контейнеров, знаний Docker или файлов Dockerfile .

Переход на другую бессерверную платформу необязателен, и мы рекомендуем рассмотреть оптимальные варианты для ваших приложений и сценариев использования, прежде чем вносить какие-либо изменения.

Независимо от того, какой модуль миграции вы выберете следующим, весь контент Serverless Migration Station (практические занятия, видео, исходный код [при наличии]) доступен в его репозитории с открытым исходным кодом . README репозитория также содержится информация о том, какие миграции следует рассмотреть и в каком порядке следует выбирать модули миграции.

7. Дополнительные ресурсы

Вопросы/отзывы по Codelab

Если вы обнаружите какие-либо проблемы в этом практическом задании, пожалуйста, сначала найдите свою проблему, прежде чем сообщать о ней. Ссылки для поиска и создания новых проблем:

Миграционные ресурсы

Ссылки на папки репозитория для Модуля 15 (НАЧАЛО) и Модуля 16 (ЗАВЕРШЕНИЕ) можно найти в таблице ниже. К ним также можно получить доступ из репозитория для всех миграций кода App Engine, которые можно клонировать или загрузить в виде ZIP-файла.

Кодлаб

Python 2

Python 3

Модуль 15

код

Н/Д

Модуль 16 (данная практическая работа)

код

(аналогично Python 2)

Онлайн-ресурсы

Ниже приведены онлайн-ресурсы, которые могут быть полезны для данного урока:

Хранилище больших двоичных объектов и облачное хранилище App Engine

платформа App Engine

Прочая информация об облачных сервисах

Python

Видео

Лицензия

Данная работа распространяется под лицензией Creative Commons Attribution 2.0 Generic.