1. Descripción general
El objetivo de la serie de codelabs de Serverless Migration Station (instructivos prácticos y de autoaprendizaje) y los videos relacionados es ayudar a los desarrolladores de Google Cloud sin servidores a modernizar sus aplicaciones guiándolos a través de una o más migraciones, principalmente alejándose de los servicios heredados. De esta manera, tus apps serán más portátiles y tendrás más opciones y flexibilidad, lo que te permitirá integrar y acceder a una mayor variedad de productos de Cloud, y actualizarte más fácilmente a versiones de lenguaje más recientes. Si bien, en un principio, se enfoca en los primeros usuarios de Cloud, principalmente los desarrolladores de App Engine (entorno estándar), esta serie es lo suficientemente amplia como para incluir otras plataformas sin servidores, como Cloud Functions y Cloud Run, o en cualquier otro lugar si corresponde.
En este codelab, aprenderás a migrar de Blobstore de App Engine a Cloud Storage. También hay migraciones implícitas desde los siguientes sistemas:
- Framework web de
webapp2a Flask (se aborda en el módulo 1) - App Engine NDB a Cloud NDB para el acceso a Datastore (se aborda en el módulo 2)
- Python 2 a 3 (la app migrada es compatible con Python 2 y 3)
Consulta los módulos de migración relacionados para obtener más información paso a paso.
En un próximo lab,
- Agrega el uso de la API/biblioteca de Blobstore de App Engine
- Almacena las cargas de los usuarios en el servicio de Blobstore
- Preparación para el siguiente paso de la migración a Cloud Storage
Requisitos
- Un proyecto de Google Cloud Platform con una cuenta de facturación activa de GCP
- Habilidades básicas de Python
- Conocimiento práctico de los comandos comunes de Linux
- Conocimientos básicos sobre el desarrollo y la implementación de aplicaciones de App Engine
- Una app de App Engine del módulo 15 en funcionamiento: Completa el codelab del módulo 15 (recomendado) o copia la app del módulo 15 del repo.
Encuesta
¿Cómo usarás este instructivo?
¿Cómo calificarías tu experiencia en Python?
¿Cómo calificarías tu experiencia en el uso de los servicios de Google Cloud?
2. Fondo
Este codelab comienza con la app de ejemplo del módulo 15 y muestra cómo migrar de Blobstore (y NDB) a Cloud Storage (y Cloud NDB). El proceso de migración implica reemplazar las dependencias de los servicios heredados agrupados en paquetes de App Engine, lo que te permite trasladar tus apps a otra plataforma sin servidores de Cloud o a otra plataforma de hosting si lo deseas.
Esta migración requiere un poco más de esfuerzo en comparación con las otras migraciones de esta serie. Blobstore tiene dependencias en el framework webapp original, y es por eso que la app de ejemplo usa el framework webapp2 en lugar de Flask. En este instructivo, se muestran migraciones a Cloud Storage, Cloud NDB, Flask y Python 3.
La app sigue registrando las "visitas" de los usuarios finales y muestra las diez más recientes, pero el codelab anterior (Módulo 15) agregó una nueva función para admitir el uso de Blobstore: la app les solicita a los usuarios finales que suban un artefacto (un archivo) correspondiente a su "visita". Los usuarios pueden hacerlo o seleccionar "Omitir" para rechazar la opción. Independientemente de la decisión del usuario, la página siguiente renderiza el mismo resultado que las versiones anteriores de esta app, y muestra las visitas más recientes. Un giro adicional es que las visitas con artefactos correspondientes incluyen un vínculo de "ver" para mostrar el artefacto de una visita. En este codelab, se implementan las migraciones mencionadas anteriormente y se conserva la funcionalidad descrita.
3. Configurar/trabajo previo
Antes de comenzar con la parte principal del instructivo, configuremos nuestro proyecto, obtengamos el código e implementemos la app de modelo de referencia para que comencemos a trabajar con el código.
1. Configura el proyecto
Si ya implementaste la app del módulo 15, te recomendamos volver a usar ese mismo proyecto (y el código). De manera alternativa, puedes crear un proyecto nuevo o reutilizar otro proyecto existente. Asegúrate de que el proyecto tenga una cuenta de facturación activa y que App Engine esté habilitado.
2. Obtén app de ejemplo del modelo de referencia
Uno de los requisitos previos para este codelab es tener una app de ejemplo del módulo 15 que funcione. Si no la tienes, puedes obtenerla de la carpeta "START" del módulo 15 (vínculo a continuación). Este codelab te guiará en cada paso y concluirá con un código que se parezca al que se encuentra en la carpeta "FINISH" del módulo 16.
- INICIO: Carpeta del módulo 15 (Python 2)
- FINALIZAR: Carpeta del módulo 16 (Python 2)
- Repositorio completo (para clonar o descargar el archivo ZIP)
El directorio de archivos de INICIO del módulo 15 debería verse así:
$ ls README.md app.yaml main-gcs.py main.py templates
El archivo main-gcs.py es una versión alternativa de main.py del módulo 15 que permite seleccionar un bucket de Cloud Storage diferente del valor predeterminado de la URL asignada de una app según el ID del proyecto: PROJECT_ID.appspot.com. Este archivo no participa en este codelab (módulo 16), pero se pueden aplicar técnicas de migración similares a ese archivo si lo deseas.
3. (vuelve a) implementa la aplicación de modelo de referencia
Los pasos del trabajo previo restantes para ejecutar ahora sin estos:
- Familiarízate con la herramienta de línea de comandos de
gcloud - Vuelve a implementar la app de muestra con
gcloud app deploy - Confirma que la app se ejecuta en App Engine sin problemas
Una vez que hayas ejecutado esos pasos de manera correcta y confirmes que funciona tu app del módulo 15 En la página inicial, se saluda a los usuarios con un formulario en el que se les solicita que suban un archivo de artefacto de visita, junto con un botón de "omitir" para rechazar la solicitud:

Una vez que los usuarios suben un archivo o lo omiten, la app renderiza la página familiar de "visitas más recientes":

Las visitas que incluyan un artefacto tendrán un vínculo de "ver" a la derecha de la marca de tiempo de la visita para mostrar (o descargar) el artefacto. Una vez que confirmes la funcionalidad de la app, podrás migrar de los servicios heredados de App Engine (webapp2, NDB, Blobstore) a alternativas contemporáneas (Flask, Cloud NDB, Cloud Storage).
4. Actualiza archivos de configuración
En la versión actualizada de nuestra app, entran en juego tres archivos de configuración. Las tareas requeridas son las siguientes:
- Actualiza las bibliotecas integradas de terceros necesarias en
app.yamly deja la puerta abierta a una migración a Python 3. - Agrega un
requirements.txtque especifique todas las bibliotecas requeridas que no estén integradas. - Agrega
appengine_config.pypara que la app admita bibliotecas de terceros integradas y no integradas
app.yaml
Actualiza la sección libraries para editar el archivo app.yaml. Se quita jinja2 y se agregan grpcio, setuptools y ssl. Elige la versión más reciente disponible para las tres bibliotecas. También agrega la directiva runtime de Python 3, pero como comentario. Cuando termines, debería verse así (si seleccionaste Python 3.9):
ANTES:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
DESPUÉS:
#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
Los cambios se relacionan principalmente con las bibliotecas integradas de Python 2 disponibles en los servidores de App Engine (por lo que no tienes que empaquetarlas por tu cuenta). Quitamos Jinja2 porque viene con Flask, que agregaremos a reqs.txt. Siempre que se usen bibliotecas cliente de Google Cloud, como las de Cloud NDB y Cloud Storage, se necesitarán grpcio y setuptools. Por último, Cloud Storage requiere la biblioteca ssl. La directiva de tiempo de ejecución comentada en la parte superior es para cuando esté todo listo para portar esta app a Python 3. Hablaremos de este tema al final del instructivo.
requirements.txt
Agrega un archivo requirements.txt que requiera el framework de Flask y las bibliotecas cliente de Cloud NDB y Cloud Storage, ninguna de las cuales está integrada. Crea el archivo con este contenido:
flask
google-cloud-ndb
google-cloud-storage
El entorno de ejecución de App Engine para Python 2 requiere que se agrupen en paquetes las bibliotecas de terceros no integradas, por lo que debes ejecutar el siguiente comando para instalar estas bibliotecas en la carpeta lib:
pip install -t lib -r requirements.txt
Si tienes Python 2 y 3 en tu máquina de desarrollo, es posible que debas usar el comando pip2 para asegurarte de obtener las versiones de Python 2 de estas bibliotecas. Una vez que actualices a Python 3, ya no necesitarás realizar la agrupación por tu cuenta.
appengine_config.py
Agrega un archivo appengine_config.py que admita bibliotecas integradas y de terceros no integradas. Crea el archivo con este contenido:
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)
Los pasos que acabas de completar deben ser similares o idénticos a los que se indican en la sección Instalación de bibliotecas para apps de Python 2 de la documentación de App Engine y, más específicamente, el contenido de appengine_config.py debe coincidir con lo que se indica en el paso 5 de esa sección.
El trabajo en los archivos de configuración está completo, así que avancemos a la aplicación.
5. Modifica los archivos de la aplicación
Importaciones
El primer conjunto de cambios para main.py incluye el reemplazo de todo lo que se reemplazará. Estos son los cambios:
webapp2se reemplaza por Flask- En lugar de usar Jinja2 desde
webapp2_extras, usa el Jinja2 que viene con Flask. - Blobstore y NDB de App Engine se reemplazan por Cloud NDB y Cloud Storage
- Los controladores de Blobstore en
webappse reemplazan por una combinación del módulo de biblioteca estándario, Flask y las utilidades dewerkzeug. - De forma predeterminada, Blobstore escribe en un bucket de Cloud Storage con el nombre de la URL de tu app (
PROJECT_ID.appspot.com). Como estamos transfiriendo a la biblioteca cliente de Cloud Storage, se usagoogle.authpara obtener el ID del proyecto y especificar el mismo nombre de bucket. (Puedes cambiar el nombre del bucket, ya que no está codificado de forma rígida).
ANTES:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
Implementa los cambios en la lista anterior reemplazando la sección de importación actual en main.py con el siguiente fragmento de código.
DESPUÉS:
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
Inicialización y compatibilidad innecesaria con Jinja2
El siguiente bloque de código que se debe reemplazar es el BaseHandler que especifica el uso de Jinja2 desde webapp2_extras. Esto no es necesario porque Jinja2 viene con Flask y es su motor de plantillas predeterminado, por lo que debes quitarlo.
En el módulo 16, crea instancias de objetos que no teníamos en la app anterior. Esto incluye inicializar la app de Flask y crear clientes de API para Cloud NDB y Cloud Storage. Por último, armamos el nombre del bucket de Cloud Storage como se describió anteriormente en la sección de importaciones. A continuación, se muestran los resultados antes y después de implementar estas actualizaciones:
ANTES:
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))
DESPUÉS:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
Actualiza el acceso a Datastore
Cloud NDB es, en su mayoría, compatible con App Engine NDB. Una diferencia que ya se abordó es la necesidad de un cliente de API. Otro es que este último requiere que el administrador de contexto de Python del cliente de la API controle el acceso a Datastore. Básicamente, esto significa que todas las llamadas de acceso a Datastore que usan la biblioteca cliente de Cloud NDB solo pueden ocurrir dentro de los bloques with de Python.
Ese es un cambio. El otro es que Cloud Storage no admite Blobstore ni sus objetos, p. ej., BlobKeys, por lo que debes cambiar file_blob por un ndb.StringProperty. A continuación, se muestran la clase del modelo de datos y las funciones store_visit() y fetch_visits() actualizadas que reflejan estos cambios:
ANTES:
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)
DESPUÉS:
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)
A continuación, se muestra una representación gráfica de los cambios que se realizaron hasta el momento:

Actualiza los controladores
Controlador de carga
Los controladores en webapp2 son clases, mientras que en Flask son funciones. En lugar de un método de verbo HTTP, Flask usa el verbo para decorar la función. Blobstore y sus controladores webapp se reemplazan por la funcionalidad de Cloud Storage, así como por Flask y sus utilidades:
ANTES:
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)
DESPUÉS:
@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)
Algunas notas sobre esta actualización:
- En lugar de un
blob_id, los artefactos de archivo ahora se identifican por el nombre de archivo (fname) si está presente y, de lo contrario, porNone(el usuario inhabilitó la opción de subir un archivo). - Los controladores de Blobstore abstrajeron el proceso de carga de sus usuarios, pero Cloud Storage no lo hace, por lo que puedes ver el código agregado recientemente que establece el objeto blob y la ubicación (bucket) del archivo, así como la llamada que realiza la carga real. (
upload_from_file()). webapp2usa una tabla de enrutamiento en la parte inferior del archivo de la aplicación, mientras que las rutas de Flask se encuentran en cada controlador decorado.- Ambos controladores completan su funcionalidad con un redireccionamiento a la página principal (
/) y conservan la solicitudPOSTcon un código de retorno HTTP 307.
Controlador de descarga
La actualización del controlador de descargas sigue un patrón similar al del controlador de cargas, solo que hay mucho menos código para analizar. Reemplaza la funcionalidad de Blobstore y webapp por los equivalentes de Cloud Storage y Flask:
ANTES:
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)
DESPUÉS:
@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)
Notas sobre esta actualización:
- Una vez más, Flask decora las funciones de controlador con su ruta, mientras que
webapplo hace en una tabla de enrutamiento en la parte inferior, por lo que debes reconocer la sintaxis de coincidencia de patrones de este último('/view/([^/]+)?') en comparación con la de Flask ('/view/<path:fname>'). - Al igual que con el controlador de carga, se requiere un poco más de trabajo del lado de Cloud Storage para la funcionalidad que abstraen los controladores de Blobstore, es decir, identificar el archivo (blob) en cuestión y descargar explícitamente el binario en comparación con la única llamada al método
send_blob()del controlador de Blobstore. - En ambos casos, se muestra un error HTTP 404 al usuario si no se encuentra un artefacto.
Controlador principal
Los cambios finales en la aplicación principal se realizan en el controlador principal. Los métodos de verbo HTTP webapp2 se reemplazan por una sola función que combina su funcionalidad. Reemplaza la clase MainHandler por la función root() y quita la tabla de enrutamiento webapp2, como se muestra a continuación:
ANTES:
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)
DESPUÉS:
@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)
En lugar de métodos get() y post() separados, son esencialmente una instrucción if-else en root(). Además, como root() es una sola función, solo hay una llamada para renderizar la plantilla para GET y POST, mientras que en webapp2 no es posible.
A continuación, se muestra una representación gráfica de este segundo y último conjunto de cambios en main.py:

(Opcional) "Mejora" de la retrocompatibilidad
Por lo tanto, la solución creada anteriormente funciona perfectamente… pero solo si comienzas desde cero y no tienes archivos creados por Blobstore. Debido a que actualizamos la app para identificar los archivos por nombre de archivo en lugar de BlobKey, la app del Módulo 16 completa tal como está no podrá ver los archivos de Blobstore. En otras palabras, realizamos un cambio incompatible con versiones anteriores al realizar esta migración. Ahora presentamos una versión alternativa de main.py llamada main-migrate.py (que se encuentra en el repo) que intenta cerrar esta brecha.
La primera "extensión" para admitir archivos creados con Blobstore es un modelo de datos que tiene un BlobKeyProperty (además de un StringProperty para los archivos creados con 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()
La propiedad file_blob se usará para identificar los archivos creados por Blobstore, mientras que file_gcs se usará para los archivos de Cloud Storage. Ahora, cuando crees visitas nuevas, almacena explícitamente un valor en file_gcs en lugar de file_blob, de modo que store_visit se vea un poco diferente:
ANTES:
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()
DESPUÉS:
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()
Cuando recuperes las visitas más recientes, "normaliza" los datos antes de enviarlos a la plantilla:
ANTES:
@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)
DESPUÉS:
@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)
A continuación, confirma la existencia de file_blob o file_gcs (o ninguna). Si hay un archivo disponible, elige el que exista y usa ese identificador (BlobKey para los archivos creados por Blobstore o el nombre de archivo para los archivos creados por Cloud Storage). Cuando decimos "archivos creados por Cloud Storage", nos referimos a los archivos creados con la biblioteca cliente de Cloud Storage. Blobstore también escribe en Cloud Storage, pero, en este caso, serían archivos creados por Blobstore.
Ahora, lo más importante: ¿qué es esta función etl_visits() que se usa para normalizar o ETL (extraer, transformar y cargar) los datos para el usuario final? El aspecto resultante será el siguiente:
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]
Probablemente se vea como esperabas: el código recorre en bucle todas las visitas y, para cada una, toma los datos de visitantes y marcas de tiempo de forma literal, luego verifica si existe file_gcs o file_blob y, si es así, elige uno de ellos (o None si no existe ninguno).
Esta es una ilustración de las diferencias entre main.py y main-migrate.py:

Si comienzas desde cero sin archivos creados por Blobstore, usa main.py, pero si estás realizando una transición y deseas admitir archivos creados por Blobstore y Cloud Storage, consulta main-migrate.py como ejemplo de cómo abordar situaciones como esta para ayudarte a planificar las migraciones de tus propias apps. Cuando se realizan migraciones complejas, es probable que surjan casos especiales, por lo que este ejemplo tiene como objetivo mostrar una mayor afinidad por la modernización de apps reales con datos reales.
6. Resumen/Limpieza
En esta sección, se completa el codelab con la implementación de la app y la verificación de que funcione según lo previsto y en cualquier resultado reflejado. Después de la validación de la app, realiza los pasos de limpieza necesarios y considera los próximos pasos.
Implementa y verifica la aplicación
Antes de volver a implementar tu app, asegúrate de ejecutar pip install -t lib -r requirements.txt para obtener esas bibliotecas de terceros autoagrupadas en paquetes en la carpeta lib. Si quieres ejecutar la solución compatible con versiones anteriores, primero cambia el nombre de main-migrate.py a main.py. Ahora ejecuta gcloud app deploy y confirma que la app funciona de forma idéntica a la app del módulo 15. La pantalla del formulario se ve de la siguiente manera:

La página de visitas más recientes se ve así:

Felicitaciones por completar este codelab en el que reemplazaste Blobstore de App Engine por Cloud Storage, NDB de App Engine por Cloud NDB y webapp2 por Flask. El código ahora debería coincidir con el contenido de la carpeta FINISH (módulo 16). El main-migrate.py alternativo también está presente en esa carpeta.
"Migración" a Python 3
La directiva runtime de Python 3 comentada en la parte superior de app.yaml es todo lo que se necesita para portar esta app a Python 3. El código fuente ya es compatible con Python 3, por lo que no es necesario realizar ningún cambio. Para implementar esto como una app de Python 3, sigue estos pasos:
- Quita la marca de comentario de la directiva
runtimede Python 3 en la parte superior deapp.yaml. - Borra todas las demás líneas en
app.yaml. - Borra el archivo
appengine_config.py. (no se usa en el entorno de ejecución de Python 3) - Borra la carpeta
libsi existe. (innecesario con el entorno de ejecución de Python 3)
Limpia
General
Si terminaste por ahora, te recomendamos que inhabilites tu app de App Engine para evitar incurrir en cargos de facturación. Sin embargo, si deseas realizar más pruebas o experimentos, la plataforma de App Engine tiene una cuota gratuita, por lo que no se te cobrará siempre que no excedas ese nivel de uso. Esto se aplica a la capacidad de procesamiento, pero también puede haber cargos por los servicios relevantes de App Engine, por lo que debes consultar su página de precios para obtener más información. Si esta migración involucra otros servicios de Cloud, estos se facturarán por separado. En cualquier caso, si corresponde, consulta la sección "Específico para este codelab" que se encuentra más abajo.
Para divulgar toda la información, la implementación en una plataforma de computación sin servidores de Google Cloud, como App Engine, genera costos menores de compilación y almacenamiento. Cloud Build tiene su propia cuota gratuita, al igual que Cloud Storage. El almacenamiento de esa imagen usa parte de esa cuota. Sin embargo, es posible que vivas en una región que no tenga ese nivel gratuito, por lo que debes tener en cuenta tu uso de almacenamiento para minimizar los costos potenciales. Las "carpetas" específicas de Cloud Storage que debes revisar incluyen las siguientes:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- Los vínculos de almacenamiento anteriores dependen de tu
PROJECT_IDy *LOC*ación, por ejemplo, "us" si tu app está alojada en EE.UU.
Por otro lado, si no vas a continuar con esta aplicación ni con otros codelabs de migración relacionados y quieres borrar todo por completo, cierra tu proyecto.
Específico para este codelab
Los servicios que se indican a continuación son exclusivos de este codelab. Consulta la documentación de cada producto para obtener más información:
- El servicio de Blobstore de App Engine se incluye en las cuotas y los límites de datos almacenados, por lo que también debes revisar la página de precios de los servicios en paquetes heredados.
- Cloud Storage tiene un nivel gratuito para regiones específicas. Consulta también su página de precios generales para obtener más información.
- El servicio App Engine Datastore lo proporciona Cloud Datastore (Cloud Firestore en modo Datastore), que también tiene un nivel gratuito. Consulta su página de precios para obtener más información".
Ten en cuenta que, si migraste del módulo 15 al 16, seguirás teniendo datos en Blobstore, por lo que incluimos su información de precios más arriba.
Próximos pasos
Además de este instructivo, otros módulos de migración que se enfocan en dejar de usar los servicios agrupados heredados que debes tener en cuenta son los siguientes:
- Módulo 2: Migra de
ndbde App Engine a Cloud NDB - Módulos 7 a 9: Migra de las tareas de envío de la lista de tareas en cola de App Engine a Cloud Tasks
- Módulos 12 y 13: Migra de Memcache de App Engine a Cloud Memorystore
- Módulos 18 y 19: Migra de la lista de tareas en cola de App Engine (tareas de extracción) a Cloud Pub/Sub
App Engine ya no es la única plataforma sin servidores de Google Cloud. Si tienes una app de App Engine pequeña o una que tiene funcionalidad limitada y deseas convertirla en un microservicio independiente, o bien quieres dividir una app monolítica en varios componentes reutilizables, estos son buenos motivos para considerar la posibilidad de migrar a Cloud Functions. Si la contenerización se convirtió en parte de tu flujo de trabajo de desarrollo de aplicaciones, en especial si consta de una canalización de CI/CD (integración continua/entrega o implementación continua), considera migrar a Cloud Run. Estos casos se abordan en los siguientes módulos:
- Migra de App Engine a Cloud Functions: Consulta el módulo 11
- Migra de App Engine a Cloud Run: Consulta el módulo 4 para organizar tu app en contenedores con Docker o el módulo 5 para hacerlo sin contenedores, conocimientos de Docker ni
Dockerfiles.
Cambiar a otra plataforma sin servidores es opcional, y te recomendamos que consideres las mejores opciones para tus apps y casos de uso antes de realizar cualquier cambio.
Independientemente del módulo de migración que consideres a continuación, se puede acceder a todo el contenido de Serverless Migration Station (codelabs, videos, código fuente [cuando esté disponible]) en su repositorio de código abierto. El README del repo también proporciona orientación sobre qué migraciones considerar y cualquier "orden" relevante de los módulos de migración.
7. Recursos adicionales
Problemas o comentarios de los codelabs
Si encuentras algún problema con este Codelab, primero busca el problema antes de enviarlo. Vínculos para buscar y crear problemas nuevos:
Recursos de migración
En la siguiente tabla, puedes encontrar vínculos a las carpetas del repositorio para el módulo 15 (INICIAR) y el módulo 16 (FINALIZAR). También se puede acceder a ellos desde el repositorio de todas las migraciones de codelab de App Engine, que puedes clonar o descargar un archivo ZIP.
Codelab | Python 2 | Python 3 |
Módulo 15 | N/A | |
Módulo 16 (este codelab) | (igual que Python 2) |
Recursos en línea
A continuación, se incluyen recursos en línea que pueden ser pertinentes para este instructivo:
Blobstore de App Engine y Cloud Storage
- Servicio de Blobstore de App Engine
- Migra a la biblioteca cliente de Cloud Storage
- Página principal de Cloud Storage
- Documentación de Cloud Storage
Plataforma de App Engine
- Documentación de App Engine
- Tiempo de ejecución de Python 2 App Engine (entorno estándar)
- Usa las bibliotecas integradas de App Engine en App Engine de Python 2
- Tiempo de ejecución de Python 3 de App Engine (entorno estándar)
- Diferencias entre los entornos de ejecución de Python 2 y 3 de App Engine (entorno estándar)
- Guía de migración de Python 2 a 3 de App Engine (entorno estándar)
- Información sobre los precios y las cuotas de App Engine
- Lanzamiento de la plataforma App Engine de segunda generación (2018)
- Comparación de las plataformas de primera y segunda generación
- Asistencia a largo plazo para entornos de ejecución heredados
- Repositorio de muestras de migración de documentación
- Repositorio de muestras de migración aportadas por la comunidad
Otra información de la nube
- Python en Google Cloud Platform
- Bibliotecas cliente de Python de Google Cloud
- Nivel "Siempre gratis" de Google Cloud
- SDK de Google Cloud (herramienta de línea de comandos
gcloud) - Toda la documentación de Google Cloud
Python
- Sistemas de plantillas Django y Jinja2
webapp2framework web- Documentación de
webapp2 webapp2_extrasvínculoswebapp2_extrasDocumentación de Jinja2- Marco de trabajo web de Flask
Videos
- Serverless Migration Station
- Expediciones sin servidores
- Suscríbete a Google Cloud Tech
- Suscríbete a Google Developers
Licencia
Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.