Migra de Memcache de App Engine a Cloud Memorystore (módulo 13)

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.

El objetivo de este codelab es mostrar a los desarrolladores de App Engine con Python 2 cómo migrar de Memcache de App Engine a Cloud Memorystore (para Redis). También hay una migración implícita de App Engine ndb a Cloud NDB, pero se trata principalmente en el codelab del módulo 2. Consúltalo para obtener más información paso a paso.

En un próximo lab,

  • Configura una instancia de Cloud Memorystore (desde Cloud Console o la herramienta de gcloud)
  • Configura un conector de Acceso a VPC sin servidores de Cloud (desde la consola de Cloud o la herramienta de gcloud)
  • Migra de Memcache de App Engine a Cloud Memorystore
  • Implementa el almacenamiento en caché con Cloud Memorystore en una app de ejemplo
  • Migra de App Engine ndb a Cloud NDB

Requisitos

Encuesta

¿Cómo usarás este instructivo?

Solo lo leeré Lo leeré y completaré los ejercicios

¿Cómo calificarías tu experiencia en Python?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia en el uso de los servicios de Google Cloud?

Principiante Intermedio Avanzado

2. Fondo

En este codelab, se muestra cómo migrar una app de ejemplo de Memcache de App Engine (y NDB) a Cloud Memorystore (y Cloud NDB). Este proceso implica reemplazar las dependencias de los servicios agrupados de App Engine, lo que hace que tus apps sean más portátiles. Puedes quedarte en App Engine o considerar la posibilidad de migrar a cualquiera de las alternativas descritas anteriormente.

Esta migración requiere más esfuerzo en comparación con las otras de esta serie. El reemplazo recomendado para Memcache de App Engine es Cloud Memorystore, un servicio de almacenamiento en caché basado en la nube completamente administrado. Memorystore admite un par de motores de almacenamiento en caché de código abierto populares, Redis y Memcached. Este módulo de migración usa Cloud Memorystore para Redis. Puedes obtener más información en la Descripción general de Memorystore y Redis.

Dado que Memorystore requiere un servidor en ejecución, también se necesita una VPC de Cloud. Específicamente, se debe crear un conector de acceso a VPC sin servidores para que la app de App Engine pueda conectarse a la instancia de Memorystore a través de su dirección IP privada. Cuando completes este ejercicio, habrás actualizado la app para que, si bien se comporte como antes, Cloud Memorystore sea el servicio de almacenamiento en caché, en reemplazo del servicio de Memcache de App Engine.

Este instructivo comienza con la app de ejemplo del módulo 12 en Python 2, seguida de una actualización secundaria opcional a Python 3. Si ya sabes cómo acceder a los servicios en paquetes de App Engine desde Python 3 a través del SDK de App Engine para Python 3, puedes comenzar con la versión de Python 3 de la app de muestra del módulo 12. Si lo haces, deberás dejar de usar el SDK, ya que Memorystore no es un servicio incluido en App Engine. Aprender a usar el SDK de App Engine para Python 3 está fuera del alcance de este instructivo.

En este instructivo, se incluyen los siguientes pasos clave:

  1. Configuración o trabajo previo
  2. Configura los servicios de almacenamiento en caché
  3. Actualiza archivos de configuración
  4. Actualizar la aplicación principal

3. Configuración o trabajo previo

Prepara el proyecto de Cloud

Te recomendamos que vuelvas a usar el mismo proyecto que usaste para completar el codelab del módulo 12. De manera alternativa, puedes crear un proyecto nuevo o reutilizar otro proyecto existente. Cada codelab de esta serie tiene un "INICIO" (el código de referencia para comenzar) y un "FINAL" (la app migrada). Se proporciona el código FINISH para que puedas comparar tus soluciones con las nuestras en caso de que tengas problemas. Siempre puedes volver a la opción COMENZAR si algo sale mal. Estos puntos de control están diseñados para garantizar que aprendas a realizar las migraciones correctamente.

Cualquiera sea el proyecto de Cloud que uses, asegúrate de que tenga una cuenta de facturación activa. También asegúrate de que App Engine esté habilitado. Revisa y asegúrate de comprender las implicaciones generales de costos de realizar estos instructivos. Sin embargo, a diferencia de otros codelabs de esta serie, este usa recursos de Cloud que no tienen un nivel gratuito, por lo que se generarán algunos costos para completar el ejercicio. Se proporcionará información de costos más específica junto con recomendaciones para reducir el uso, incluidas instrucciones al final sobre cómo liberar recursos para minimizar los cargos de facturación.

Obtén app de ejemplo del modelo de referencia

A partir del código de referencia del módulo 12 con el que COMENZAMOS, este codelab te guía paso a paso por la migración. Cuando termines, tendrás una app del módulo 13 que se parecerá mucho al código de una de las carpetas FINISH. Estos son los recursos:

La carpeta START debe contener los siguientes archivos:

$ ls
README.md               app.yaml                main.py                 requirements.txt        templates                

Si comienzas con la versión de Python 2, también habrá un archivo appengine_config.py y, posiblemente, una carpeta lib si completaste el codelab del módulo 12.

(Vuelve a ) implementar la app del Módulo 12

Pasos restantes del trabajo previo:

  1. Vuelve a familiarizarte con la herramienta de línea de comandos de gcloud (si es necesario).
  2. (Vuelve a )implementar el código del módulo 12 en App Engine (si es necesario)

Los usuarios de Python 2 deben borrar y volver a instalar la carpeta lib con estos comandos:

rm -rf ./lib; pip install -t lib -r requirements.txt                

Ahora todos (usuarios de Python 2 y 3) deben subir el código a App Engine con este comando:

gcloud app deploy                

Una vez que se haya implementado correctamente, confirma que la app se vea y funcione igual que la app del módulo 12, una app web que hace un seguimiento de las visitas y las almacena en caché para el mismo usuario durante una hora:

dfe56a02ae59ddd8.png

Debido a que las visitas más recientes se almacenan en caché, las actualizaciones de la página deberían cargarse con bastante rapidez.

4. Configura los servicios de almacenamiento en caché

Cloud Memorystore no es un servicio sin servidores. Se requiere una instancia; en este caso, una instancia de Redis en ejecución. A diferencia de Memcache, Memorystore es un producto de Cloud independiente y no tiene un nivel gratuito, por lo que debes consultar la información sobre los precios de Memorystore para Redis antes de continuar. Para minimizar los costos de este ejercicio, recomendamos la menor cantidad de recursos para operar: un nivel de servicio Básico y una capacidad de 1 GB.

La instancia de Memorystore se encuentra en una red diferente a la de tu app (instancias) de App Engine, por lo que se debe crear un conector de acceso a VPC sin servidores para que App Engine pueda acceder a tus recursos de Memorystore. Para minimizar los costos de la VPC, elige el tipo de instancia (f1-micro) y la menor cantidad de instancias que se pueden solicitar (sugerimos un mínimo de 2 y un máximo de 3). También puedes consultar la página de información sobre precios de VPC.

Repetimos estas recomendaciones para reducir los costos a medida que te guiamos en la creación de cada recurso requerido. Además, cuando crees recursos de Memorystore y de VPC en la consola de Cloud, verás la calculadora de precios de cada producto en la esquina superior derecha, que te proporcionará una estimación del costo mensual (consulta la ilustración a continuación). Esos valores se ajustan automáticamente si cambias tus opciones. Esto es aproximadamente lo que deberías ver:

7eb35ebf7248c010.png

Ambos recursos son obligatorios, y no importa cuál crees primero. Si creas la instancia de Memorystore primero, tu app de App Engine no podrá acceder a ella sin el conector de VPC. Del mismo modo, si primero creas el conector de VPC, no habrá nada en esa red de VPC con lo que tu app de App Engine pueda comunicarse. En este instructivo, primero crearás la instancia de Memorystore y, luego, el conector de VPC.

Una vez que ambos recursos estén en línea, agregarás la información pertinente a app.yaml para que tu app pueda acceder a la caché. También puedes consultar las guías de Python 2 o Python 3 en la documentación oficial. También vale la pena consultar la guía de almacenamiento en caché de datos en la página de migración de Cloud NDB ( Python 2 o Python 3).

Crea una instancia de Cloud Memorystore

Debido a que Cloud Memorystore no tiene un nivel gratuito, te recomendamos que asignes la menor cantidad de recursos posible para completar el codelab. Puedes mantener los costos al mínimo con los siguientes parámetros de configuración:

  • Selecciona el nivel de servicio más bajo: Básico (valor predeterminado de la consola: "Estándar", valor predeterminado de gcloud: "Básico").
  • Elige la menor cantidad de almacenamiento: 1 GB (valor predeterminado de la consola: 16 GB, valor predeterminado de gcloud: 1 GB).
  • Por lo general, las versiones más recientes de cualquier software requieren la mayor cantidad de recursos, pero tampoco se recomienda seleccionar la versión más antigua. Actualmente, la segunda versión más reciente es Redis versión 5.0 (predeterminada en la consola: 6.x)

Con esos parámetros de configuración en mente, la siguiente sección te guiará para crear la instancia desde la consola de Cloud. Si prefieres hacerlo desde la línea de comandos, avanza.

Desde la consola de Cloud

Ve a la página de Cloud Memorystore en Cloud Console (es posible que se te solicite información de facturación). Si aún no habilitaste Memorystore, se te solicitará que lo hagas:

68318997e3105db6.png

Una vez que lo habilites (y, posiblemente, junto con la facturación), llegarás al panel de Memorystore. Aquí puedes ver todas las instancias creadas en tu proyecto. El proyecto que se muestra a continuación no tiene ninguna, por lo que verás el mensaje "No hay filas para mostrar". Para crear una instancia de Memorystore, haz clic en Crear instancia en la parte superior:

63547aa575838a36.png

En esta página, se incluye un formulario que debes completar con la configuración deseada para crear la instancia de Memorystore:

b77d927287fdf4c7.png

Para mantener bajos los costos de este instructivo y su app de ejemplo, sigue las recomendaciones que se mencionaron anteriormente. Después de realizar las selecciones, haz clic en Crear. El proceso de creación tarda varios minutos. Cuando finalice, copia la dirección IP y el número de puerto de la instancia para agregarlos a app.yaml.

Desde la línea de comandos

Si bien es visualmente informativo crear instancias de Memorystore desde Cloud Console, algunas personas prefieren la línea de comandos. Antes de continuar, asegúrate de tener gcloud instalado y en funcionamiento.

Al igual que con Cloud Console, Cloud Memorystore para Redis debe estar habilitado. Ejecuta el comando gcloud services enable redis.googleapis.com y espera a que se complete, como en este ejemplo:

$ gcloud services enable redis.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

Si el servicio ya está habilitado, ejecutar el comando (de nuevo) no tiene efectos secundarios (negativos). Con el servicio habilitado, creemos una instancia de Memorystore. El comando se ve de la siguiente manera:

gcloud redis instances create NAME --redis-version VERSION \
    --region REGION --project PROJECT_ID

Elige un nombre para tu instancia de Memorystore. En este lab, se usa "demo-ms" como nombre junto con el ID del proyecto "my-project". La región de esta app de ejemplo es us-central1 (igual que us-central), pero puedes usar una más cercana si la latencia es un problema. Debes seleccionar la misma región que tu app de App Engine. Puedes seleccionar la versión de Redis que prefieras, pero nosotros usaremos la versión 5, como se recomendó anteriormente. Con esos parámetros de configuración, este es el comando que ejecutarías (junto con el resultado asociado):

$ gcloud redis instances create demo-ms --region us-central1 \
    --redis-version redis_5_0 --project my-project

Create request issued for: [demo-ms]
Waiting for operation [projects/my-project/locations/us-central1/operations/operation-xxxx] to complete...done.
Created instance [demo-ms].

A diferencia de los valores predeterminados de la consola de Cloud, gcloud se establece de forma predeterminada en recursos mínimos. El resultado es que no se requirió el nivel de servicio ni la cantidad de almacenamiento en ese comando. La creación de una instancia de Memorystore tarda varios minutos. Cuando finalice, anota la dirección IP y el número de puerto de la instancia, ya que se agregarán a app.yaml pronto.

Confirma que se creó la instancia

Desde la consola de Cloud o la línea de comandos

Ya sea que hayas creado tu instancia desde Cloud Console o la línea de comandos, puedes confirmar que está disponible y lista para usarse con este comando: gcloud redis instances list --region REGION

Este es el comando para verificar las instancias en la región us-central1, junto con el resultado esperado que muestra la instancia que acabamos de crear:

$ gcloud redis instances list --region us-central1
INSTANCE_NAME  VERSION    REGION       TIER   SIZE_GB  HOST         PORT  NETWORK  RESERVED_IP     STATUS  CREATE_TIME
demo-ms        REDIS_5_0  us-central1  BASIC  1        10.aa.bb.cc  6379  default  10.aa.bb.dd/29  READY   2022-01-28T09:24:45

Cuando se te solicite la información de la instancia o que configures tu app, asegúrate de usar HOST y PORT (no RESERVED_IP). El panel de Cloud Memorystore en Cloud Console ahora debería mostrar esa instancia:

c5a6948ec1c056ed.png

Desde una máquina virtual de Compute Engine

Si tienes una máquina virtual (VM) de Compute Engine, también puedes enviar comandos directos a tu instancia de Memorystore desde una VM para confirmar que funciona. Ten en cuenta que el uso de una VM puede tener costos asociados independientes de los recursos que ya estás usando.

Crea un conector de Acceso a VPC sin servidores

Al igual que con Cloud Memorystore, puedes crear el conector de VPC de Cloud sin servidores en Cloud Console o en la línea de comandos. Del mismo modo, Cloud VPC no tiene un nivel gratuito, por lo que te recomendamos que asignes la menor cantidad de recursos posible para completar el codelab y mantener los costos al mínimo. Esto se puede lograr con los siguientes parámetros de configuración:

  • Selecciona la cantidad máxima de instancias más baja: 3 (valor predeterminado de la consola y de gcloud: 10)
  • Elige el tipo de máquina de menor costo: f1-micro (valor predeterminado de la consola: e2-micro, sin valor predeterminado de gcloud)

En la siguiente sección, se te guiará para crear el conector desde Cloud Console con la configuración de la VPC de Cloud anterior. Si prefieres hacerlo desde la línea de comandos, ve a la siguiente sección.

Desde la consola de Cloud

Ve a la página "Acceso a VPC sin servidores" de Cloud Networking en Cloud Console (es posible que se te solicite información de facturación). Si aún no habilitaste la API, se te solicitará que lo hagas:

e3b9c0651de25e97.png

Una vez que habilites la API (y, posiblemente, la facturación), llegarás al panel que muestra todos los conectores de VPC creados. El proyecto que se usa en la captura de pantalla a continuación no tiene ninguna, por lo que se muestra el mensaje "No hay filas para mostrar". En la consola, haz clic en Create Connector en la parte superior:

b74b49b9d73b7dcf.png

Completa el formulario con la configuración deseada:

6b26b2aafa719f73.png

Elige la configuración adecuada para tus propias aplicaciones. Para este instructivo y su app de ejemplo con necesidades mínimas, tiene sentido minimizar los costos, por lo que debes seguir las recomendaciones que se mencionaron anteriormente. Una vez que hayas realizado las selecciones, haz clic en Crear. La solicitud de un conector de VPC tardará unos minutos en completarse.

Desde la línea de comandos

Antes de crear un conector de VPC, primero habilita la API de Serverless VPC Access. Deberías ver un resultado similar después de ejecutar el siguiente comando:

$ gcloud services enable vpcaccess.googleapis.com
Operation "operations/acf.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

Con la API habilitada, se crea un conector de VPC con un comando similar al siguiente:

gcloud compute networks vpc-access connectors create CONNECTOR_NAME \
    --range 10.8.0.0/28 --region REGION --project PROJECT_ID

Elige un nombre para tu conector y una dirección IP inicial de bloque CIDR /28 sin usar. En este instructivo, se hacen las siguientes suposiciones:

  • Project ID (ID del proyecto): my-project
  • Nombre del conector de VPC: demo-vpc
  • Instancias mínimas: 2 (valor predeterminado) y instancias máximas: 3
  • Tipo de instancia: f1-micro
  • Región: us-central1
  • Bloque CIDR de IPv4: 10.8.0.0/28 (como se recomienda en la consola de Cloud)

Si ejecutas el siguiente comando teniendo en cuenta las suposiciones anteriores, deberías ver un resultado similar al siguiente:

$ gcloud compute networks vpc-access connectors create demo-vpc \
    --max-instances 3 --range 10.8.0.0/28 --machine-type f1-micro \
    --region us-central1  --project my-project

Create request issued for: [demo-vpc]
Waiting for operation [projects/my-project/locations/us-central1/operations/xxx] to complete...done.
Created connector [demo-vpc].

En el comando anterior, se omite la especificación de valores predeterminados, como un mínimo de 2 instancias y una red llamada default. La creación de un conector de VPC tarda varios minutos en completarse.

Confirma que se creó el conector

Una vez que se complete el proceso, ejecuta el siguiente comando gcloud, suponiendo que sea la región us-central1, para confirmar que se creó y está listo para usarse:

$ gcloud compute networks vpc-access connectors list --region us-central1
CONNECTOR_ID  REGION       NETWORK  IP_CIDR_RANGE  SUBNET  SUBNET_PROJECT  MIN_THROUGHPUT  MAX_THROUGHPUT  STATE
demo-vpc      us-central1  default  10.8.0.0/28                            200             300             READY

Del mismo modo, el panel ahora debería mostrar el conector que acabas de crear:

e03db2c8140ed014.png

Anota el ID del proyecto de Cloud, el nombre del conector de VPC y la región.

Ahora que creaste los recursos adicionales de Cloud necesarios, ya sea a través de la línea de comandos o en la consola, es momento de actualizar la configuración de la aplicación para admitir su uso.

5. Actualiza archivos de configuración

El primer paso es realizar todas las actualizaciones necesarias en los archivos de configuración. El objetivo principal de este codelab es ayudar a los usuarios de Python 2 a migrar, pero, por lo general, ese contenido se complementa con información sobre la portabilidad a Python 3 en cada sección a continuación.

requirements.txt

En esta sección, agregaremos paquetes para admitir Cloud Memorystore y Cloud NDB. En el caso de Cloud Memorystore para Redis, basta con usar el cliente estándar de Redis para Python (redis), ya que no existe una biblioteca cliente de Cloud Memorystore como tal. Agrega redis y google-cloud-ndb a requirements.txt, y une flask del módulo 12:

flask
redis
google-cloud-ndb

Este archivo requirements.txt no incluye números de versión, lo que significa que se seleccionan las versiones más recientes. Si surgen incompatibilidades, especifica los números de versión para fijar las versiones que funcionan.

app.yaml

Nuevas secciones para agregar

El entorno de ejecución de App Engine para Python 2 requiere paquetes específicos de terceros cuando se usan APIs de Cloud, como Cloud NDB, es decir, grpcio y setuptools. Los usuarios de Python 2 deben incluir en app.yaml las bibliotecas integradas, como las que se muestran a continuación, junto con una versión disponible. Si aún no tienes una sección libraries, crea una y agrega ambas bibliotecas de la siguiente manera:

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest

Cuando migres tu app, es posible que ya tenga una sección de libraries. Si es así y faltan grpcio y setuptools, agrégalos a tu sección libraries existente.

A continuación, nuestra app de ejemplo necesita la información de la instancia de Cloud Memorystore y del conector de VPC, por lo que debes agregar las siguientes dos secciones nuevas a app.yaml, independientemente del tiempo de ejecución de Python que uses:

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

Eso es todo en cuanto a las actualizaciones requeridas. Tu archivo app.yaml actualizado ahora debería verse de la siguiente manera:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

A continuación, se muestra un ejemplo de "antes y después" que ilustra las actualizaciones que debes aplicar a app.yaml:

ec2bb027a67debb6.png

*Diferencias de Python 3

Esta sección es opcional y solo se aplica si estás portando a Python 3. Para ello, debes realizar varios cambios en la configuración de Python 2. Omite esta sección si no realizarás la actualización en este momento.

No se usan ni threadsafe ni api_version para el entorno de ejecución de Python 3, por lo que debes borrar ambos parámetros de configuración. El entorno de ejecución más reciente de App Engine no admite bibliotecas de terceros integradas ni la copia de bibliotecas no integradas. El único requisito para los paquetes de terceros es enumerarlos en requirements.txt. Como resultado, se puede borrar toda la sección libraries de app.yaml.

A continuación, el entorno de ejecución de Python 3 requiere el uso de frameworks web que realicen su propio enrutamiento, por lo que mostramos a los desarrolladores cómo migrar de webp2 a Flask en el módulo 1. Como resultado, todos los controladores de secuencias de comandos deben cambiarse a auto. Dado que esta app no entrega ningún archivo estático, es "inútil" tener controladores en la lista (ya que todos son auto), por lo que también se puede quitar toda la sección handlers. Como resultado, tu nuevo app.yaml abreviado y ajustado para Python 3 debería acortarse para verse de la siguiente manera:

runtime: python39

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

A continuación, se resumen las diferencias en app.yaml cuando se porta a Python 3:

  • Borra la configuración de threadsafe y api_version
  • Borra la sección libraries.
  • Borra la sección handlers (o solo los controladores script si tu app entrega archivos estáticos).

Reemplaza los valores

Los valores de las nuevas secciones de Memorystore y el conector de VPC son solo marcadores de posición. Reemplaza esos valores en mayúsculas (YOUR_REDIS_HOST, YOUR_REDIS_PORT, PROJECT_ID, REGION, CONNECTOR_NAME) por los valores que guardaste cuando creaste esos recursos anteriormente. En cuanto a tu instancia de Memorystore, asegúrate de usar HOST (no RESERVED_IP) y PORT. A continuación, se incluye una forma rápida de obtener HOST y PORT desde la línea de comandos, suponiendo que el nombre de la instancia es demo-ms y que REGION es us-central1:

$ gcloud redis instances describe demo-ms --region us-central1 \
    --format "value(host,port)"
10.251.161.51   6379

Si la dirección IP de nuestra instancia de Redis de ejemplo fuera 10.10.10.10 con el puerto 6379 en nuestro proyecto my-project ubicado en la región us-central1 con un nombre de conector de VPC de demo-vpc, estas secciones en app.yaml se verán de la siguiente manera:

env_variables:
    REDIS_HOST: '10.10.10.10'
    REDIS_PORT: '6379'

vpc_access_connector:
    name: projects/my-project/locations/us-central1/connectors/demo-vpc

Crea o actualiza appengine_config.py

Cómo agregar compatibilidad con bibliotecas de terceros integradas

Al igual que lo hicimos con app.yaml anteriormente, agrega el uso de las bibliotecas grpcio y setuptools. Modifica appengine_config.py para admitir bibliotecas de terceros integradas. Si esto te resulta familiar, es porque también era necesario en el módulo 2 cuando migramos de App Engine ndb a Cloud NDB. El cambio exacto que se requiere es agregar la carpeta lib al conjunto de trabajo setuptools.pkg_resources:

4140b3800694f77e.png

*Diferencias de Python 3

Esta sección es opcional y solo se aplica si estás portando a Python 3. Uno de los cambios bienvenidos de la segunda generación de App Engine es que ya no es necesario copiar (a veces llamado "vendoring") paquetes de terceros (no integrados) ni hacer referencia a paquetes de terceros integrados en app.yaml, lo que significa que puedes borrar todo el archivo appengine_config.py.

6. Actualizar archivos de la aplicación

Solo hay un archivo de aplicación, main.py, por lo que todos los cambios de esta sección afectan solo a ese archivo. Proporcionamos una representación pictórica de los cambios que realizaremos para migrar esta aplicación a Cloud Memorystore. Es solo con fines ilustrativos y no está destinado a que lo analices en detalle. Todo el trabajo se centra en los cambios que realizamos en el código.

5d043768ba7be742.png

Abordemos cada sección por separado, comenzando por la parte superior.

Actualiza las importaciones

La sección de importación en main.py para el Módulo 12 usa Cloud NDB y Cloud Tasks; aquí están sus importaciones:

ANTES:

from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb

Para cambiar a Memorystore, es necesario leer las variables de entorno, lo que significa que necesitamos el módulo os de Python y redis, el cliente de Redis de Python. Como Redis no puede almacenar en caché objetos de Python, serializa la lista de visitas más recientes con pickle, por lo que también debes importar eso. Un beneficio de Memcache es que la serialización de objetos se realiza automáticamente, mientras que Memorystore es un poco más "hágalo usted mismo". Por último, actualiza de App Engine ndb a Cloud NDB reemplazando google.appengine.ext.ndb por google.cloud.ndb. Después de estos cambios, tus importaciones deberían verse de la siguiente manera:

DESPUÉS:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

Actualización de la inicialización

La inicialización del módulo 12 consiste en crear una instancia del objeto de aplicación de Flask app y establecer una constante para una hora de almacenamiento en caché:

ANTES:

app = Flask(__name__)
HOUR = 3600

El uso de las APIs de Cloud requiere un cliente, por lo que debes crear una instancia de un cliente de Cloud NDB inmediatamente después de Flask. A continuación, obtén la dirección IP y el número de puerto de la instancia de Memorystore a partir de las variables de entorno que configuraste en app.yaml. Con esa información, crea una instancia de un cliente de Redis. Así se ve el código después de esas actualizaciones:

DESPUÉS:

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

*Migración a Python 3

Esta sección es opcional si comienzas con la versión de Python 3 de la app del módulo 12. Si es así, hay varios cambios obligatorios relacionados con las importaciones y la inicialización.

En primer lugar, como Memcache es un servicio en paquetes de App Engine, su uso en una app de Python 3 requiere el SDK de App Engine, específicamente, encapsular la aplicación WSGI (además de otra configuración necesaria):

ANTES:

from flask import Flask, render_template, request
from google.appengine.api import memcache, wrap_wsgi_app
from google.appengine.ext import ndb

app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600

Como migraremos a Cloud Memorystore (que no es un servicio en paquete de App Engine como Memcache), se debe quitar el uso del SDK. Esto es sencillo, ya que solo borrarás toda la línea que importa memcache y wrap_wsgi_app. También borra la línea que llama a wrap_wsgi_app(). Con estas actualizaciones, esta parte de la app (en realidad, toda la app) queda idéntica a la versión de Python 2.

DESPUÉS:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

Por último, quita el uso del SDK de app.yaml (borra la línea: app_engine_apis: true) y requirements.txt (borra la línea: appengine-python-standard).

Migra a Cloud Memorystore (y Cloud NDB)

El modelo de datos de Cloud NDB está diseñado para ser compatible con los ndb de App Engine, lo que significa que la definición de los objetos Visit sigue siendo la misma. Al igual que en la migración del módulo 2 a Cloud NDB, todas las llamadas a Datastore en store_visit() y fetch_visits() se aumentan y se incorporan en un nuevo bloque with (ya que se requiere el uso del administrador de contexto de Cloud NDB). Estas son las llamadas antes de ese cambio:

ANTES:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

Agrega un bloque with ds_client.context() a ambas funciones y coloca las llamadas a Datastore dentro (con sangría). En este caso, no es necesario realizar ningún cambio en las llamadas:

DESPUÉS:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

A continuación, veamos los cambios en el almacenamiento en caché. Esta es la función main() del módulo 12:

ANTES:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    visits = memcache.get('visits')

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0].visitor != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        memcache.set('visits', visits, HOUR)  # set() not add()

    return render_template('index.html', visits=visits)

Redis tiene llamadas "get" y "set", al igual que Memcache. Todo lo que hacemos es intercambiar las bibliotecas cliente respectivas, ¿verdad? Estuviste cerca. Como se mencionó anteriormente, no podemos almacenar en caché una lista de Python con Redis (porque primero debe serializarse, algo de lo que Memcache se encarga automáticamente), por lo que, en la llamada a set(), "serializamos" las visitas en una cadena con pickle.dumps(). Del mismo modo, cuando recuperes visitas de la caché, deberás deserializarlas con pickle.loads() inmediatamente después de get(). Este es el controlador principal después de implementar esos cambios:

DESPUÉS:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    rsp = REDIS.get('visits')
    visits = pickle.loads(rsp) if rsp else None

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0].visitor != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        REDIS.set('visits', pickle.dumps(visits), ex=HOUR)

    return render_template('index.html', visits=visits)

Con esto, se completan los cambios necesarios en main.py para convertir el uso de Memcache de la app de ejemplo a Cloud Memorystore. ¿Qué sucede con la plantilla HTML y la portabilidad a Python 3?

¿Actualizar el archivo de plantilla HTML y portarlo a Python 3?

¡Sorpresa! No es necesario hacer nada aquí, ya que la aplicación se diseñó para ejecutarse en Python 2 y 3 sin cambios de código ni bibliotecas de compatibilidad. Verás main.py. idénticos en las carpetas "FINISH" de mod13a (2.x) y mod13b (3.x) Lo mismo sucede con requirements.txt , más allá de las diferencias en los números de versión (si se usan). Como la interfaz de usuario no cambia, tampoco hay actualizaciones en templates/index.html.

Todo lo necesario para ejecutar esta app en App Engine de Python 3 se completó anteriormente en la configuración: se quitaron las directivas innecesarias de app.yaml y se borraron appengine_config.py y la carpeta lib, ya que no se usan en Python 3.

7. 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 cualquier limpieza y considera los próximos pasos.

Implementa y verifica la aplicación

La última verificación siempre es implementar la app de ejemplo. Desarrolladores de Python 2: Borren y reinstalen lib con los siguientes comandos. (Si tienes instalados Python 2 y 3 en tu sistema, es posible que debas ejecutar pip2 de forma explícita).

rm -rf ./lib
pip install -t lib -r requirements.txt

Ahora, los desarrolladores de Python 2 y 3 deben implementar sus apps con el siguiente comando:

gcloud app deploy

Como solo modificaste el cableado interno para un servicio de almacenamiento en caché completamente diferente, la app debería funcionar de forma idéntica a la app del módulo 12:

App de visitme del módulo 7

Con este paso, se completa el codelab. Te invitamos a comparar tu app de ejemplo actualizada con cualquiera de las carpetas del módulo 13, mod13a (Python 2) o mod13b (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/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • Los vínculos de almacenamiento anteriores dependen de tu PROJECT_ID y *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:

En este instructivo, se usaron cuatro productos de Cloud:

  • App Engine
  • Cloud Datastore
  • Cloud Memorystore
  • Cloud VPC

A continuación, se indican los pasos para liberar estos recursos y evitar o minimizar los cargos de facturación.

Apaga la instancia de Memorystore y el conector de VPC

Estos son los productos sin un nivel gratuito, por lo que se te facturará ahora mismo. Si no apagas tu proyecto de Cloud (consulta la siguiente sección), debes borrar tu instancia de Memorystore y el conector de VPC para detener la facturación. Al igual que cuando creaste estos recursos, también puedes liberarlos desde Cloud Console o la línea de comandos.

Desde la consola de Cloud

Para borrar la instancia de Memorystore, vuelve al panel de Memorystore y haz clic en el ID de la instancia:

2b09baf1aa2e0a25.png

Una vez que estés en la página de detalles de esa instancia, haz clic en "Borrar" y confirma la acción:

f9d9eb1c1d4c6107.png

Para borrar el conector de VPC, ve a su panel de control, selecciona la casilla de verificación junto al conector que deseas borrar, haz clic en "Borrar" y confirma:

ca5fbd9f4c7c9b60.png

Desde la línea de comandos

El siguiente par de comandos de gcloud borra la instancia de Memorystore y el conector de VPC, respectivamente:

  • gcloud redis instances delete INSTANCE --region REGION
  • gcloud compute networks vpc-access connectors delete CONNECTOR --region REGION

Si no configuraste tu ID del proyecto con gcloud config set project, es posible que debas proporcionar --project PROJECT_ID. Si tu instancia de Memorystore se llama demo-ms y el conector de VPC se llama demo-vpc, y ambos están en la región us-central1, ejecuta el siguiente par de comandos y confirma:

$ gcloud redis instances delete demo-ms --region us-central1
You are about to delete instance [demo-ms] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-ms]
Waiting for operation [projects/PROJECT/locations/REGION/operations/operation-aaaaa-bbbbb-ccccc-ddddd] to complete...done.
Deleted instance [demo-ms].
$
$ gcloud compute networks vpc-access connectors delete demo-vpc --region us-central1
You are about to delete connector [demo-vpc] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-vpc]
Waiting for operation [projects/PROJECT/locations/REGION/operations/aaaaa-bbbb-cccc-dddd-eeeee] to complete...done.
Deleted connector [demo-vpc].

Cada solicitud tarda unos minutos en ejecutarse. Estos pasos son opcionales si decides cerrar todo tu proyecto de Cloud, como se describió anteriormente. Sin embargo, seguirás incurriendo en cargos de facturación hasta que se complete el proceso de cierre.

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 ndb de 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 15 y 16: Migra de Blobstore de App Engine a Cloud Storage
  • 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.

8. Recursos adicionales

A continuación, se enumeran recursos adicionales para los desarrolladores que deseen explorar más a fondo este módulo de migración o uno relacionado, así como los productos relacionados. Esto incluye lugares para proporcionar comentarios sobre este contenido, vínculos al código y varios documentos que pueden resultarte útiles.

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 12 (INICIAR) y el módulo 13 (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 12

código

código

Módulo 13 (este codelab)

código

código

Referencias en línea

A continuación, se incluyen recursos en línea que pueden ser pertinentes para este instructivo:

App Engine

App Engine NDB y Cloud NDB

Memcache de App Engine y Cloud Memorystore

Cloud VPC

Otra información de la nube

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.