1. Introducción
Última actualización: 1/11/2024
¿Cómo modernizamos una aplicación de PHP antigua a Google Cloud?
(📽️ mira un video introductorio de 7 minutos a este codelab).
Es común tener aplicaciones heredadas que se ejecutan de forma local y que deben modernizarse. Esto significa hacerlos escalables, seguros y, además, que se puedan implementar en diferentes entornos.
En este taller, harás lo siguiente:
- Organiza la aplicación de PHP en contenedores.
- Migra a un servicio de base de datos administrado (Cloud SQL).
- Implementa en Cloud Run (es una alternativa sin operaciones de GKE o Kubernetes).
- Protege la aplicación con Identity and Access Management (IAM) y Secret Manager.
- Define una canalización de CI/CD a través de Cloud Build. Cloud Build se puede conectar con tu repositorio de Git alojado en proveedores populares de Git, como GitHub o GitLab, y activarse en cualquier push a la rama principal, por ejemplo.
- Alojar las imágenes de la aplicación en Cloud Storage Esto se logra a través del montaje, y no se necesita código para cambiar la app.
- Presenta la funcionalidad de IA generativa a través de Gemini, orquestada a través de Cloud Functions (sin servidores).
- Familiarízate con los SLO y opera tu app recién actualizada.
Si sigues estos pasos, puedes modernizar gradualmente tu aplicación de PHP y mejorar su escalabilidad, seguridad y flexibilidad de implementación. Además, migrar a Google Cloud te permite aprovechar su potente infraestructura y servicios para garantizar que tu aplicación se ejecute sin problemas en un entorno nativo de la nube.
Creemos que lo que aprenderás siguiendo estos sencillos pasos se puede aplicar a tu propia aplicación y organización con diferentes lenguajes o pilas, y diferentes casos de uso.
Acerca de la app
La aplicación ( código, bajo licencia MIT) que bifurarás es una aplicación básica de PHP 5.7 con autenticación de MySQL. La idea principal de la aplicación es proporcionar una plataforma en la que los usuarios puedan subir fotos y los administradores tengan la capacidad de etiquetar imágenes inapropiadas. La aplicación tiene dos tablas:
- Usuarios. Viene precompilada con administradores. Se pueden registrar personas nuevas.
- Images Incluye algunas imágenes de muestra. Los usuarios que accedieron pueden subir fotos nuevas. Agregaremos un poco de magia aquí.
Tu objetivo
Queremos modernizar la aplicación anterior para tenerla en Google Cloud. Aprovecharemos sus herramientas y servicios para mejorar la escalabilidad, mejorar la seguridad y automatizar la administración de la infraestructura, además de integrar funciones avanzadas, como el procesamiento de imágenes, la supervisión y el almacenamiento de datos, con servicios como Cloud SQL, Cloud Run, Cloud Build y Secret Manager, entre otros.
Lo más importante es que queremos hacerlo paso a paso para que puedas aprender cuál es el proceso de pensamiento detrás de cada paso. Por lo general, cada paso abre nuevas posibilidades para los siguientes (por ejemplo, módulos 2 -> 3 y 6 -> 7).
¿Aún no te convences? Consulta este video de 7 minutos en YouTube.
Requisitos
- Una computadora con un navegador conectado a Internet
- Algunos créditos de GCP Pídele a tu fan local de Google que te envíe algunas ;)
- El comando
gcloud
funciona. - ¿Trabajas de forma local? Descárgalo aquí. También necesitarás un editor decente (p.ej., vscode o intellij).
- ¿Quieres hacer todo "en la nube"? Luego, puedes usar cloud Shell.
- Usuario de GitHub. Necesitas esto para bifurcar el código original 🧑🏻💻 gdgpescara/app-mod-workshop con tu propio repositorio de git. Esto es necesario para tener tu propia canalización de CI/CD (confirmación automática -> compilación -> implementación).
Aquí puedes encontrar soluciones de ejemplo:
- Repositorio del autor: https://github.com/Friends-of-Ricc/app-mod-workshop
- El repositorio original del taller, en las carpetas
.solutions/
, por capítulo.
Puedes realizar este taller desde tu computadora local o completamente en un navegador.
2. Configuración y bifurcación del crédito
Canjea el crédito de GCP y configura tu entorno de GCP [opcional]
Para ejecutar este taller, necesitas una cuenta de facturación con algo de crédito. Si ya tienes tu propia facturación, puedes omitir este paso.
Crea una nueva Cuenta de Gmail de Google (*) para vincularla a tu crédito de GCP. Pídele a tu instructor el vínculo para canjear el crédito de GCP o usa los créditos aquí: bit.ly/PHP-Amarcord-credits.
Accede con la cuenta que acabas de crear y sigue las instrucciones.
(
) ¿Por qué necesito una cuenta de Gmail nueva?*
Notamos que algunas personas no pudieron completar el codelab porque su cuenta (en particular, los correos electrónicos de trabajo o de estudiantes) ya había estado expuesta a GCP y tenía políticas de la organización que restringían su capacidad para hacerlo. Te recomendamos que crees una cuenta de Gmail nueva o que uses una existente (gmail.com) sin exposición previa a GCP.
Haz clic en el botón para canjear el crédito.
Completa el siguiente formulario con tu nombre y apellido, y acepta los Términos y Condiciones.
Es posible que debas esperar unos segundos para que la cuenta de facturación aparezca aquí: https://console.cloud.google.com/billing
Cuando termines, abre la consola de Google Cloud y crea un proyecto nuevo haciendo clic en el selector de proyectos en el menú desplegable de la parte superior izquierda, donde se muestra "Sin organización". Ver a continuación
Crea un proyecto nuevo si no tienes uno, como se muestra en la siguiente captura de pantalla. En la esquina superior derecha, hay una opción "NUEVO PROYECTO".
Asegúrate de vincular el proyecto nuevo con la cuenta de facturación de prueba de GCP de la siguiente manera.
Ya está todo listo para que comiences a usar Google Cloud Platform. Si eres principiante o solo quieres hacer todo en un entorno de Cloud, puedes acceder a Cloud Shell y su editor a través del siguiente botón en la esquina superior izquierda, como se muestra a continuación.
Asegúrate de que tu proyecto nuevo esté seleccionado en la parte superior izquierda:
No seleccionado (incorrecto):
Seleccionado (bueno):
Bifurca la app desde GitHub
- Ve a la app de demostración: https://github.com/gdgpescara/app-mod-workshop
- Haz clic en 🍴 bifurcar.
- Si no tienes una cuenta de GitHub, debes crear una nueva.
- Edita los elementos como desees.
- Clona el código de la app con git clone https://github.com/<TU-USUARIO-DE-GITHUB>/<TU-NOMBRE-DE-REPOSITORIO>
- Abre la carpeta del proyecto clonado con tu editor favorito. Si eliges Cloud Shell, puedes hacerlo haciendo clic en "Abrir editor", como se muestra a continuación.
Tienes todo lo que necesitas con el editor de Google Cloud Shell, como se muestra en la siguiente imagen.
3. Módulo 1: Crea una instancia de SQL
Crea la instancia de Google Cloud SQL
Nuestra app de PHP se conectará a una base de datos de MySQL, por lo que debemos replicarla en Google Cloud para que la migración sea sencilla. Cloud SQL es la opción perfecta, ya que te permite ejecutar una base de datos MySQL completamente administrada en la nube. Sigue estos pasos:
- Ve a la página de Cloud SQL: https://console.cloud.google.com/sql/instances
- Haz clic en “Crear instancia”
- Habilita la API (si es necesario). Este proceso podría tardar unos segundos.
- Elige MySQL.
- (intentamos ofrecerte la versión más económica para que dure más tiempo):
- Edición: Enterprise
- Configuración predeterminada: development (probamos la zona de pruebas y no funcionó)
- Mysql Ver: 5.7 (¡vaya, un viaje al pasado!)
- ID de instancia: Elige
appmod-phpapp
(si cambias esto, recuerda cambiar también las secuencias de comandos y las soluciones futuras según corresponda). - Contraseña: Elige la que quieras, pero anota CLOUDSQL_INSTANCE_PASSWORD
- Región: Mantén el mismo valor que elegiste para el resto de la app (p. ej., Milán =
europe-west8
). - Disponibilidad zonal: Zona única (ahorramos dinero para la demostración)
Haz clic en el botón Crear instancia para implementar la base de datos de Cloud SQL. ⌛ El proceso tarda alrededor de 10 minutos en completarse⌛. Mientras tanto, continúa leyendo la documentación. También puedes comenzar a resolver el siguiente módulo ("Cómo crear un contenedor para tu app de PHP"), ya que no tiene dependencias en este módulo en la primera parte (hasta que corrijas la conexión de la base de datos).
Nota. Esta instancia debería costar alrededor de $7 por día. Asegúrate de desconectarlo después del taller.
Crea la base de datos y el usuario image_catalog en Cloud SQL
El proyecto de app incluye una carpeta db/
que contiene dos archivos SQL:
- 01_schema.sql : Contiene código SQL para crear dos tablas que contienen datos de Usuarios y de Imágenes.
- 02_seed.sql: Contiene código SQL para propagar datos en las tablas creadas anteriormente.
Estos archivos se usarán más adelante, una vez que se cree la base de datos image_catalog
. Para ello, sigue estos pasos:
- Abre tu instancia y haz clic en la pestaña Bases de datos:
- Haz clic en "Crear base de datos".
- Llámala
image_catalog
(como en la configuración de la app de PHP).
Luego, creamos el usuario de la base de datos. Con esto, podemos autenticarnos en la base de datos de image_catalog.
- Ahora haz clic en la pestaña Usuarios.
- Haz clic en "Agregar cuenta de usuario".
- Usuario: Creemos uno:
- Nombre de usuario:
appmod-phpapp-user
- Contraseña: Elige algo que puedas recordar o haz clic en “generar”.
- Mantén "Permitir cualquier host (%)".
- haz clic en AGREGAR.
Abre la base de datos en IP conocidas.
Ten en cuenta que todas las bases de datos en Cloud SQL nacen “aisladas”. Debes configurar explícitamente una red a la que se pueda acceder.
- Haz clic en tu instancia.
- Abre el menú “Conexiones”.
- Haz clic en la pestaña “Herramientas de redes”.
- Haz clic en Redes autorizadas. Ahora, agrega una subred.
- Por ahora, vamos a usar INSECURE para permitir que la app funcione:
- Nombre: “Todos en el mundo: INSEGURO” (recordemos que esta solución económica también es insegura).
- Red: “0.0.0.0/0” (Nota: Es INSEGUA)
Haz clic en Guardar.
Debería ver algo como esto:
Nota. Esta solución es un buen compromiso para terminar el taller en O(horas). Sin embargo, consulta el documento SECURITY para proteger tu solución para producción.
Es hora de probar la conexión a la base de datos.
Veamos si funciona el usuario image_catalog
que creamos antes. Accede a Cloud SQL Studio dentro de la instancia y, luego, ingresa la base de datos, el usuario y la contraseña que se autenticarán, como se muestra a continuación:
Ahora que te encuentras, puedes abrir el editor de SQL y continuar con la siguiente sección.
Importa la base de datos desde la base de código
Usa el editor de SQL para importar las tablas de image_catalog con sus datos. Toma el código SQL de los archivos SQL en el repositorio y ejecútalos uno tras otro en un orden secuencial. 01_schema.sql y, luego, 02_seed.sql.
Después de esto, deberías obtener dos tablas en image_catalog, que son users y images, como se muestra a continuación:
Para probarlo, ejecuta lo siguiente en el editor: select * from images;
Además, asegúrate de anotar la dirección IP pública, ya que la necesitarás más adelante.
4. Módulo 2: Organiza tu app de PHP en contenedores
Queremos compilar esta app para la nube.
Esto significa empaquetar el código en algún tipo de archivo ZIP que contenga toda la información para ejecutarlo en la nube.
Existen varias formas de empaquetar el contenido:
- Docker Es muy popular, pero es bastante complejo configurarlo correctamente.
- Paquetes de compilación. Menos popular, pero tiende a "adivinar automáticamente" qué compilar y qué ejecutar. A menudo, simplemente funciona.
En el contexto de este taller, suponemos que usas Docker.
Docker
Si quieres tener control, esta es la solución adecuada para ti. Esto tiene sentido cuando necesitas configurar bibliotecas específicas y, luego, inyectar ciertos comportamientos no evidentes (un chmod en las cargas, un ejecutable no estándar en tu app, etcétera).
Como queremos implementar nuestra aplicación alojada en contenedores en Cloud Run, consulta la siguiente documentación y trata de completar los espacios en blanco. Proporcionamos solo lo esencial para que todo sea más fácil por el momento. El Dockerfile final se verá similar al siguiente:
# Use an official PHP image with Apache
# Pull a suitable php image
FROM __________# Define the env variable for the Apache listening port 8080
ENV __________
# Set working directory inside the container
WORKDIR __________
# Install required PHP extensions: PDO, MySQL, and other dependencies
RUN __________
# Copy all application files into the container
COPY __________
# Configure Apache to listen on port 8080. Use ‘sed' command to change the default listening port.
RUN __________
# When in doubt, always expose to port 8080
EXPOSE __________
# Start Apache in the foreground
CMD __________
Además, para probar nuestra aplicación de forma local, debemos cambiar el archivo config.php de modo que nuestra app de PHP se conecte con la base de datos de MYSQL disponible en Google CloudSQL. Según lo que configuraste antes, completa los espacios en blanco.
- Db_host es la dirección IP pública de Cloud SQL. Puedes encontrarla en la consola:
- DBM_name no debe cambiarse:
image_catalog
- Db_user debe ser
appmod-phpapp-user
. - Db_pass es algo que elegiste. Establece la cadena entre comillas simples y escapa según sea necesario.
<?php
// Database configuration
$db_host = '____________';
$db_name = '____________';
$db_user = '____________';
$db_pass = '____________';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
Además, no dudes en traducir los pocos artículos en italiano al inglés con la ayuda de Gemini.
Bien, ahora que tienes el Dockerfile y configuraste tu app de PHP para que se conecte a tu base de datos, probemos esto.
Instala Docker si aún no lo tienes ( vínculo). No necesitas esto si usas Cloud Shell (¿no es genial?).
Ahora, intenta compilar y ejecutar tu app de PHP alojada en contenedores con los comandos de compilación y ejecución de Docker adecuados.
- docker build -t <IMAGE_TAG_NAME> .
- docker run -it -p <CONTAINER PORT>:<LOCAL MACHINE PORT> <IMAGE_TAG_NAME>
Si todo funciona, deberías poder ver la siguiente página web cuando te conectes al host local.
Si usas Cloud Shell, también puedes exportar el puerto local (por ejemplo, 8080) a tu navegador de la siguiente manera:
docker build -t my-php-app-docker app-mod-workshop/ -f Dockerfile
docker run -it -p 8080:8080 my-php-app-docker
Ahora que sabes que tu app se ejecuta en el puerto 8080, haz clic en el ícono "Vista previa en la Web" (un navegador con un ojo) y, luego, en Vista previa en el puerto 8080 (o "Cambiar puerto" para cualquier otro puerto).
Cómo probar el resultado en tu navegador
Ahora, tu aplicación debería verse de la siguiente manera:
Si accedes con Administrador/admin123, deberías ver algo como esto.
¡Excelente! Funciona 🎉🎉🎉
Si tu dockerización es buena, pero las credenciales de la DB son incorrectas, es posible que obtengas algo como lo siguiente:
Vuelve a intentarlo, estás cerca.
Buildpacks [opcional]
Con Buildpacks, la app se compila automáticamente. Lamentablemente, no tienes control total, por lo que podrías terminar con una configuración inesperada.
- Consulta Buildpacks en GCP: https://cloud.google.com/docs/buildpacks/build-application y aquí.
- Instala
pack
: https://buildpacks.io/docs/for-platform-operators/how-to/integrate-ci/pack/ - Buildpacks en PHP: https://cloud.google.com/docs/buildpacks/php (aquí se explica cómo configurar la versión de PHP)
- Prueba algo como lo siguiente para compilar automáticamente tu imagen de contenedor.
pack build --builder=gcr.io/buildpacks/builder my-app-with-buildpacks
Deberías tener una nueva imagen de Docker en tu entorno local. Puedes intentar ejecutar un contenedor para él, pero como no tenemos el control total de cómo se compiló la imagen, es posible que la app no funcione. En cualquier caso, te invitamos a experimentar y, si tienes éxito, comparte tu opinión. Gracias.
Guardado en Artifact Registry [opcional]
A estas alturas, deberías tener una aplicación de PHP alojada en contenedores que funcione y esté lista para implementarse en la nube. A continuación, necesitamos un lugar en la nube para almacenar nuestra imagen de Docker y hacerla accesible para la implementación en servicios de Google Cloud como Cloud Run. Esta solución de almacenamiento se llama Artifact Registry, un servicio de Google Cloud completamente administrado que se diseñó para almacenar artefactos de aplicaciones, como imágenes de contenedor de Docker, paquetes de Maven, módulos de npm y mucho más.
Creemos un repositorio en Artifact Registry de Google Cloud con el botón correspondiente.
Elige un nombre válido, el formato y la región adecuados para almacenar los artefactos.
Regresa a la etiqueta de tu entorno de desarrollo local y envía la imagen del contenedor de la app al repositorio de Artifact Registry que acabas de crear. Para hacerlo, completa los siguientes comandos.
- docker tag IMAGEN_FUENTE[:ETIQUETA] IMAGEN_DESTINO[:ETIQUETA]
- docker push TARGET_IMAGE[:TAG]
El resultado debería verse como la siguiente captura de pantalla.
¡Felicidades! 🎉🎉🎉 Puedes pasar al siguiente nivel.
Nota. También prueba el extremo /upload.php
y sube una foto. Es posible que recibas un mensaje de "Permiso denegado". Si es así, debes corregir chmod/chown
en Dockerfile
.
5. Módulo 3: Implementa la app en Cloud Run
¿Por qué usar Cloud Run?
Buena pregunta. Hace años, seguramente habrías elegido Google App Engine.
En pocas palabras, hoy en día, Cloud Run tiene una pila de tecnología más reciente, es más fácil de implementar, es más económica y se reduce a 0 cuando no la usas. Con su flexibilidad para ejecutar cualquier contenedor sin estado y su integración con varios servicios de Google Cloud, es ideal para implementar microservicios y aplicaciones modernas con una sobrecarga mínima y la máxima eficiencia.
Específicamente, Cloud Run es una plataforma completamente administrada por Google Cloud que te permite ejecutar aplicaciones alojadas en contenedores sin estado en un entorno sin servidores. Controla automáticamente toda la infraestructura, escalando desde cero para satisfacer el tráfico entrante y disminuyendo cuando está inactivo, lo que lo hace rentable y eficiente. Cloud Run admite cualquier lenguaje o biblioteca, siempre que esté empaquetado en un contenedor, lo que permite una gran flexibilidad en el desarrollo. Se integra bien con otros servicios de Google Cloud y es adecuada para compilar microservicios, APIs, sitios web y aplicaciones basadas en eventos sin necesidad de administrar la infraestructura del servidor.
Requisitos previos
Para realizar esta tarea, debes tener gcloud
instalado en tu máquina local. De lo contrario, consulta las instrucciones aquí. En cambio, si estás en Google Cloud Shell, no es necesario que realices ninguna acción.
Antes de realizar la implementación…
Si trabajas en tu entorno local, autentícate en Google Cloud con el siguiente comando:
$ gcloud auth login –update-adc # not needed in Cloud Shell
Esto debería autenticarte a través de un acceso de OAuth en tu navegador. Asegúrate de acceder a través de Chrome con el mismo usuario (p. ej., vattelapesca@gmail.com) que haya accedido a Google Cloud con la facturación habilitada.
Habilita la API de Cloud Run con el siguiente comando:
$ gcloud services enable run.googleapis.com
En este punto, todo está listo para implementarse en Cloud Run.
Implementa tu app en Cloud Run con gcloud
El comando que te permite implementar la app en Cloud Run es gcloud run deploy
. Existen varias opciones que puedes configurar para lograr tu objetivo. El conjunto mínimo es el siguiente:
- Nombre del servicio de Cloud Run que deseas implementar para tu app. Un servicio de Cloud Run te mostrará una URL que proporciona un extremo a tu app.
- La región de Google Cloud en la que se ejecutará tu app.
- Imagen de contenedor que une tu app.
- Variables de entorno que tu app necesitará usar durante su ejecución.
- La marca allow-Unauthenticated que permite que todos accedan a tu app sin necesidad de autenticación adicional
Consulta la documentación para ver cómo aplicar esta opción a tu comando. La implementación tardará unos minutos. Si todo está correcto, deberías ver algo como esto en la consola de Google Cloud.
Haz clic en la URL que proporciona Cloud Run y prueba tu aplicación. Una vez que se realice la autenticación, deberías ver algo como lo siguiente.
“gcloud run deploy” con “sin preguntas”
Tal vez hayas notado que gcloud run deploy
te hace las preguntas correctas y completa los espacios en blanco que dejaste. ¡Maravilloso!
Sin embargo, en algunos módulos, agregaremos este comando a un activador de Cloud Build, por lo que no podemos permitirnos hacer preguntas. Debemos completar cada opción del comando. Por lo tanto, quieres crear el gcloud run deploy --option1 blah --foo bar --region your-fav-region
dorado. ¿Cómo lo lograrías?
- repite los pasos 2, 3 y 4 hasta que gcloud deje de hacer preguntas:
- [LOOP]
gcloud run deploy
con las opciones encontradas hasta el momento - [LOOP] sistemas piden la opción X
- [LOOP] Busca en la documentación pública cómo configurar X desde la CLI agregando la opción
--my-option [my-value]
. - Regresa al paso 2 ahora, a menos que gcloud se complete sin más preguntas.
- ¡Este comando gcloud run deploy BLAH BLAH BLAH es genial! Guarda el comando en algún lugar, ya que lo necesitarás más adelante para el paso de Cloud Build.
Una posible solución se encuentra aquí.
¡Felicidades! 🎉🎉🎉 Implementaste correctamente tu app en Google Cloud y lograste el primer paso de la modernización.
6. Módulo 4: Limpia la contraseña con Secret Manager
En el paso anterior, pudimos implementar y ejecutar correctamente nuestra app en Cloud Run. Sin embargo, lo hicimos con una práctica poco segura: proporcionar algunos secretos en texto simple.
Primera iteración: Actualiza config.php para usar ENV
Es posible que hayas notado que colocamos la contraseña de la BD directamente en el código del archivo config.php. Esto es adecuado para realizar pruebas y ver si la app funciona. Sin embargo, no puedes confirmar ni usar código de esa manera en un entorno de producción. La contraseña (y otros parámetros de conexión de la base de datos) se deben leer de forma dinámica y proporcionar a la app durante el tiempo de ejecución. Cambia el archivo config.php para que lea los parámetros de la base de datos de las variables de entorno. Si falla, considera establecer valores predeterminados. Esto es útil en caso de que no puedas cargar ENV, de modo que el resultado de la página te indicará si está usando los valores predeterminados. Completa los espacios en blanco y reemplaza el código en config.php.
<?php
// Database configuration with ENV variables. Set default values as well
$db_host = getenv('DB_HOST') ?: _______;
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: _______;
// Note getenv() is PHP 5.3 compatible
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Errore di connessione: " . $e->getMessage());
}
session_start();
?>
Como tu app está alojada en contenedores, debes proporcionar una forma de suministrarle las variables de entorno. Esto se puede hacer de varias maneras:
- En el momento de la compilación, en el Dockerfile. Agrega a tu Dockerfile anterior los 4 parámetros con la sintaxis ENV DB_VAR=ENV_VAR_VALUE. Esto establecerá valores predeterminados que se pueden anular durante el tiempo de ejecución. Por ejemplo, "DB_NAME" y "DB_USER" se pueden establecer aquí y en ningún otro lugar.
- En el tiempo de ejecución. Puedes configurar estas variables para Cloud Run, tanto desde la CLI como desde la IU. Este es el lugar correcto para colocar las 4 variables (a menos que quieras mantener los valores predeterminados establecidos en Dockerfile).
En localhost, te recomendamos que coloques tus variables de entorno en un archivo .env
(consulta la carpeta solutions).
Además, asegúrate de que se agregue .env a tu .gitignore
: no quieres enviar tus secretos a GitHub.
echo .env >> .gitignore
Luego, puedes probar la instancia de forma local:
docker run -it -p 8080:8080 --env-file .env my-php-app-docker
Ahora lograste lo siguiente:
- Tu app leerá la variable de forma dinámica desde tu entorno
- Mejoraste la seguridad porque quitaste la contraseña de la BD de tu código).
Ahora puedes implementar una revisión nueva en Cloud Run. Pasemos a la IU y configuremos las variables de entorno de forma manual:
- Ve a https://console.cloud.google.com/run.
- Haz clic en tu app.
- Haz clic en "Editar e implementar una nueva revisión".
- En la primera pestaña “Contenedores”, haz clic en la pestaña inferior “Variables y secretos”.
- Haz clic en "+ Agregar variable" y agrega todas las variables necesarias. Deberías terminar con algo como lo siguiente:
¿Es perfecta? No. La mayoría de los operadores aún pueden ver tu PASE. Esto se puede mitigar con Google Cloud Secret Manager.
Segunda iteración: Secret Manager
Las contraseñas desaparecieron de tu propio código: ¡victoria! Pero espera, ¿ya estamos a salvo?
Cualquier persona que tenga acceso a la consola de Google Cloud podrá ver tus contraseñas. De hecho, si accedes al archivo de implementación YAML de Cloud Run, podrás recuperarlo. O bien, si intentas editar o implementar una nueva revisión de Cloud Run, la contraseña se mostrará en la sección Variables y secretos, como se muestra en las siguientes capturas de pantalla.
Secret Manager de Google Cloud es un servicio seguro y centralizado para administrar información sensible, como claves de API, contraseñas, certificados y otros secretos.
Te permite almacenar, administrar y acceder a secretos con permisos detallados y encriptación sólida. Secret Manager, integrado en Identity and Access Management (IAM) de Google Cloud, te permite controlar quién puede acceder a secretos específicos, lo que garantiza la seguridad de los datos y el cumplimiento normativo.
También admite la rotación automática de secretos y el control de versiones, lo que simplifica la administración del ciclo de vida de los secretos y mejora la seguridad en las aplicaciones de los servicios de Google Cloud.
Para acceder a Secret Manager, navega desde el menú de opciones a los servicios de Seguridad y búscalo en la sección Protección de datos, como se muestra en la siguiente captura de pantalla.
Habilita la API de Secret Manager una vez que estés allí, como se muestra en la siguiente imagen.
- Ahora, haz clic en "Crear un secreto": Llamémoslo racionalmente:
- Nombre:
php-amarcord-db-pass
- Valor secreto: "your DB password" (ignora la parte "upload file").
- anotar este vínculo secreto, debería verse como
projects/123456789012/secrets/php-amarcord-db-pass
. Este es el puntero único a tu secreto (para Terraform, Cloud Run y otros). El número es el número de proyecto único.
Sugerencia: Intenta usar convenciones de nombres coherentes para tus secretos, especifícalas de izquierda a derecha, por ejemplo: cloud-devrel-phpamarcord-dbpass
.
- Organización (con la empresa)
- Equipo (dentro de la organización)
- Aplicación (dentro del equipo)
- Nombre de la variable (dentro de la app)
Esto te permitirá tener regex fáciles para encontrar todos tus secretos para una sola app.
Cómo crear una nueva revisión de Cloud Run
Ahora que tenemos un secreto nuevo, debemos deshacernos de la variable de entorno DB_PASS y reemplazarla por el secreto nuevo. Entonces:
- Accede a Cloud Run con la consola de Google Cloud
- Elige la app.
- Haz clic en "Editar e implementar una revisión nueva".
- Busca la pestaña "Variables y Secrets".
- Usa el botón "+ Hacer referencia a un Secret" para restablecer la variable de entorno DB_PASS.
- Usa el mismo "DB_PASS" para los secretos a los que se hace referencia y usa la versión más reciente.
Cuando termines, deberías recibir el siguiente error:
Intenta averiguar cómo solucionarlo. Para resolver este problema, debes acceder a la sección IAM y administración y cambiar los permisos de otorgamiento. ¡Buena depuración!
Una vez que lo averigües, vuelve a Cloud Run y vuelve a implementar una revisión nueva. El resultado debería verse como la siguiente imagen:
Sugerencia: La consola para desarrolladores (IU) es excelente para señalar problemas de permisos. Tómate el tiempo para navegar por todos los vínculos de tus entidades de Cloud.
7. Módulo 5: Configura tu CI/CD con Cloud Build
¿Por qué usar una canalización de CI/CD?
A esta altura, deberías haber escrito gcloud run deploy
varias veces, quizás respondiendo la misma pregunta una y otra vez.
¿Cansado de implementar tu app de forma manual con gcloud run deploy? ¿No sería genial que tu app pudiera implementarse automáticamente cada vez que envíes un cambio nuevo a tu repositorio de Git?
Para usar una canalización de CI/CD, necesitarás dos elementos:
- Un repositorio de Git personal: Por suerte, ya deberías haber bifurcado el repositorio del taller en tu cuenta de GitHub en el paso 2. De lo contrario, vuelve y completa ese paso. Tu repositorio bifurcado debería verse de la siguiente manera:
https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop
- Cloud Build. Este servicio increíble y económico te permite configurar automatizaciones de compilación para casi todo: Terraform, apps dockerizadas, etc.
Esta sección se enfocará en la configuración de Cloud Build.
Comienza a usar Cloud Build.
Para ello, usaremos Cloud Build:
- compilar tu fuente (con Dockerfile) Considéralo un “archivo .zip grande” que contiene todo lo que necesitas para compilarlo y ejecutarlo (tu “artefacto de compilación”).
- envía este artefacto a Artifact Registry (AR).
- Luego, emite una implementación de AR a Cloud Run para la app "php-amarcord".
- Esto creará una nueva versión ("revisión") de la app existente (piensa en una capa con el código nuevo) y la configuraremos para desviar el tráfico a la versión nueva si el envío se realiza correctamente.
Este es un ejemplo de algunas compilaciones de mi app de php-amarcord
:
¿Cómo hacemos todo esto?
- Crea un archivo YAML perfecto:
cloudbuild.yaml
- Mediante la creación de un activador de Cloud Build
- Conectándonos a nuestro repositorio de GitHub a través de la IU de Cloud Build.
Crear activador (y conectar repositorio)
- Ve a https://console.cloud.google.com/cloud-build/triggers.
- Haz clic en "Crear activador".
- Compilar:
- Nombre: Algo significativo, como
on-git-commit-build-php-app
- Evento: Envío a una rama
- Fuente: "Conectar repositorio nuevo"
- Se abrirá una ventana a la derecha: “Connect repository”
- Proveedor de la fuente: "GitHub" (primero)
- "Continuar"
- Se abrirá una ventana en GitHub para realizar la autenticación cruzada. Sigue el flujo y ten paciencia. Si tienes muchos repositorios, es posible que tarde un poco.
- "Select repo" Selecciona tu cuenta o repo y marca la parte "I understand…".
- Si recibiste el error: La app de GitHub no está instalada en ninguno de tus repositorios, haz clic en "Instalar Google Cloud Build" y sigue las instrucciones.
- Haz clic en Conectar.
- ¡Bingo! Tu repositorio ya está conectado.
- Volvamos a la parte del activador...
- Configuración: Detectada automáticamente (*)
- Avanzado: Selecciona la cuenta de servicio “[PROJECT_NUMBER]- compute@developer.gserviceaccount.com”
- xxxxx es el ID de tu proyecto.
- La cuenta de servicio de procesamiento predeterminada es adecuada para un enfoque de lab, pero no la uses en producción. ( Más información).
- deja todo lo demás como está.
- Haz clic en el botón “Crear”.
(*) Esta es la forma más sencilla, ya que busca Dockerfile o cloudbuild.yaml. Sin embargo, cloudbuild.yaml
te brinda la capacidad real de decidir qué hacer en cada paso.
¡Yo tengo el poder!
Ahora, el activador no funcionará, a menos que otorgues a la cuenta de servicio de Cloud Build (¿qué es una cuenta de servicio? Es el correo electrónico de un “robot” que actúa en tu nombre para realizar una tarea, en este caso, compilar elementos en la nube.
Tu SA no podrá compilar ni implementarse, a menos que lo habilites para hacerlo. Por suerte, es fácil.
- Ve a "Cloud Build" > " Configuración".
- Cuenta de servicio "[PROJECT_NUMBER]- compute@developer.gserviceaccount.com"
- Marca estas casillas:
- Cloud Run
- Secret Manager
- Cuentas de servicio
- Cloud Build
- También marca la casilla "Establecer como cuenta de servicio preferida"
¿Dónde está el archivo YAML de Cloud Build?
Te recomendamos que dediques un tiempo a crear tu propio YAML de Cloud Build.
Sin embargo, si no tienes tiempo o no quieres tomarte el tiempo, puedes inspirarte en esta carpeta de soluciones: .solutions
Ahora puedes enviar un cambio a GitHub y observar cómo Cloud Build realiza su parte.
La configuración de Cloud Build puede ser complicada. Es posible que haya algunos intercambios de información por los siguientes motivos:
- Revisar los registros en https://console.cloud.google.com/cloud-build/builds;region=global
- Buscando el error.
- Corregir el código y volver a emitir la confirmación de git / git push
- A veces, el error no está en el código, sino en alguna configuración. En ese caso, puedes emitir una compilación nueva desde la IU (Cloud Build > "Triggers" > Run).
Ten en cuenta que, si usas esta solución, aún queda trabajo por hacer. Por ejemplo, debes configurar las variables de ENV para los extremos de dev/prod recién creados:
Puedes hacerlo de dos maneras:
- A través de la IU: Vuelve a configurar las variables de entorno.
- A través de la CLI, creando la secuencia de comandos “perfecta” para ti. Puedes encontrar un ejemplo aquí: gcloud-run-deploy.sh. Debes modificar algunos parámetros, por ejemplo, el extremo y el número de proyecto. Puedes encontrar el número de proyecto en la Descripción general de Cloud.
¿Cómo confirmo el código en GitHub?
No está dentro del alcance de este taller enseñarte la mejor manera de git push
a GitHub. Sin embargo, en caso de que estés atascado y estés en Cloud Shell, hay dos maneras de hacerlo:
- CLI: Agrega una clave SSH de forma local y agrega un remoto con git@github.com:TU_USUARIO/app-mod-workshop.git (en lugar de http).
- VSCode. Si usas el editor de Cloud Shell, puedes usar la pestaña Control de código fuente (Ctrl + Mayúsculas + G), hacer clic en "Sincronizar cambios" y seguir las instrucciones. Deberías poder autenticar tu cuenta de GitHub en vscode y las operaciones de extracción y envío desde allí serán muy sencillas.
Recuerda git add clodubuild.yaml
entre otros archivos; de lo contrario, no funcionará.
"Paridad de dev/prod" profunda o superficial [opcional]
Si copiaste la versión del modelo desde aquí, tendrás dos versiones de DEV y PROD idénticas. Esto es genial y está en línea con la regla 10 de la app de doce factores.
Sin embargo, usamos dos extremos web diferentes para tener una app que apunte a la misma base de datos. Esto es suficiente para un taller. Sin embargo, en la vida real, debes dedicar tiempo a crear un entorno de producción adecuado. Esto significa tener dos bases de datos (una para dev y otra para prod) y también elegir dónde tenerlas para la recuperación ante desastres o la alta disponibilidad. Esto va más allá del alcance de este taller, pero es algo para reflexionar.
Si tienes tiempo para hacer una versión "profunda" de la producción, ten en cuenta todos los recursos que debes duplicar, como los siguientes:
- Base de datos de Cloud SQL (y, probablemente, instancia de SQL)
- Bucket de GCS
- Cloud Function.
- Puedes usar Gemini 1.5 Flash como modelo en desarrollo (más económico y rápido) y Gemini 1.5 Pro (más potente).
En general, cada vez que hagas algo sobre la app, piensa de manera crítica: ¿la producción debería tener este mismo valor o no? Y si no es así, duplica tu esfuerzo. Por supuesto, esto es mucho más fácil con Terraform, donde puedes insertar tu entorno (-dev, -prod) como sufijo a tus recursos.
8. Módulo 6: Traslado a Google Cloud Storage
Almacenamiento
Actualmente, la app almacena el estado en un contenedor de Docker. Si la máquina se rompe, la app explota o simplemente envías una revisión nueva, se programará una nueva, con un almacenamiento restablecido (=>vacío). 🙈
¿Cómo lo arreglamos? Hay varios enfoques.
- Almacena las imágenes en la BD. Eso es lo que hice con mi app de PHP anterior. Es la solución más simple, ya que no agrega complejidad. Sin embargo, agrega latencia y carga a tu base de datos.
- ¿Quieres migrar tu app de Cloud Run a una solución de almacenamiento fácil de usar: GCE + Persistent Disk? ¿Quizás GKE + Storage?
- Ve a GCS. Google Cloud Storage ofrece el mejor almacenamiento de su clase para toda Google Cloud y es la solución más idiomática de Cloud. Sin embargo, requiere que hagamos suciedad con bibliotecas PHP. ¿Tenemos bibliotecas de PHP 5.7 para GCS? ¿
PHP 5.7
admiteComposer
? (Parece que PHP 5.3.2 es la versión más antigua que admite Composer). - ¿Quizás usar un sidecar de Docker?
- O bien, usa las activaciones de volumen de Cloud Run de GCS. Suena increíble.
🤔 Migrar almacenamiento (sin definir)
[Respuesta abierta] En este ejercicio, queremos que encuentres una solución para mover tus imágenes de una manera que se mantenga de alguna manera.
Prueba de aceptación
No quiero decirte la solución, pero quiero que suceda lo siguiente:
- Subes
newpic.jpg
. Puedes verlo en la app. - Actualizas la app a una versión nueva.
newpic.jpg
sigue allí, visible.
💡 Posible solución (activación de volúmenes de Cloud Run de GCS)
Esta es una solución muy elegante que nos permite lograr cargas de archivos con estado sin tocar el código en ABSOLUTO (aparte de mostrar una descripción de la imagen, pero eso es trivial y solo para la satisfacción visual).
Esto debería permitirte activar una carpeta de Cloud Run a GCS, de modo que:
- Todas las cargas a GCS se podrán ver en tu app.
- Todas las cargas a tu app se subirán a GCS
- La magia se realizará con objetos tyo subidos a GCS (capítulo 7).
Nota. Lee la letra pequeña de FUSE. Esto NO está bien si el rendimiento es un problema.
Crea un bucket de GCS
GCS es el servicio de almacenamiento omnipresente de Google Cloud. Está probado y es utilizado por todos los servicios de GCP que necesitan almacenamiento.
Ten en cuenta que Cloud Shell exporta PROJECT_ID como GOOGLE_CLOUD_PROJECT:
$ export PROJECT_ID=$GOOGLE_CLOUD_PROJECT
#!/bin/bash
set -euo pipefail
# Your Cloud Run Service Name, eg php-amarcord-dev
SERVICE_NAME='php-amarcord-dev'
BUCKET="${PROJECT_ID}-public-images"
GS_BUCKET="gs://${BUCKET}"
# Create bucket
gsutil mb -l "$GCP_REGION" -p "$PROJECT_ID" "$GS_BUCKET/"
# Copy original pictures there - better if you add an image of YOURS before.
gsutil cp ./uploads/*.png "$GS_BUCKET/"
Configura Cloud Run para activar el bucket en la carpeta /uploads/
Ahora, veamos la parte elegante. Creamos un volumen php_uploads
y le indicamos a Cloud Run que active un activador de FUSE en MOUNT_PATH
(algo como /var/www/html/uploads/
):
#!/bin/bash
set -euo pipefail
# .. keep variables from previous script..
# Uploads folder within your docker container.
# Tweak it for your app code.
MOUNT_PATH='/var/www/html/uploads/'
# Inject a volume mount to your GCS bucket in the right folder.
gcloud --project "$PROJECT_ID" beta run services update "$SERVICE_NAME" \
--region $GCP_REGION \
--execution-environment gen2 \
--add-volume=name=php_uploads,type=cloud-storage,bucket="$BUCKET" \
--add-volume-mount=volume=php_uploads,mount-path="$MOUNT_PATH"
Ahora, repite este paso para todos los extremos que quieras dirigir a Cloud Storage.
También puedes lograr lo mismo desde la IU
- En la pestaña “Volumes”, crea un punto de activación de volumen que apunte a tu bucket, de tipo “Bucket de Cloud Storage”, por ejemplo, con el nombre “php_uploads”.
- En Contenedores > Activaciones de volumen, activa el volumen que acabas de crear en el punto de volumen solicitado por tu app. Depende del Dockerfile, pero podría verse como
var/www/html/uploads/
.
De cualquier manera, si funciona, editar la nueva revisión de Cloud Run debería mostrarte algo como lo siguiente:
Ahora, prueba la aplicación nueva subiendo una imagen nueva al extremo /upload.php
.
Las imágenes deberían fluir sin problemas en GCS sin escribir una sola línea de PHP:
¿Qué acaba de suceder?
Sucedió algo muy mágico.
Una aplicación antigua con código antiguo sigue haciendo su trabajo. Una nueva pila modernizada nos permite tener todas las imágenes de nuestra app cómodamente en un bucket de Cloud con estado. Ahora el cielo es el límite:
- ¿Quieres enviar un correo electrónico cada vez que aparezca una imagen con el texto "peligroso" o "desnudo"? Puedes hacerlo sin tocar el código PHP.
- ¿Quieres usar un modelo multimodal de Gemini cada vez que llega una imagen para describirla y subir la base de datos con su descripción? Puedes hacerlo sin tocar el código PHP. ¿No me crees? Continúa leyendo en el capítulo 7.
Acabamos de desbloquear un gran espacio de oportunidades.
9. Módulo 7: Mejora tu app con Gemini de Google
Ahora tienes una nueva app de PHP moderna y reluciente (como una Fiat 126
de 2024) con almacenamiento en la nube.
¿Para qué sirve?
Requisitos previos
En el capítulo anterior, una solución de modelo nos permitió activar imágenes /uploads/
en GCS, de facto, separando la lógica de la app del almacenamiento de imágenes.
Para realizar este ejercicio, debes hacer lo siguiente:
- Haber completado correctamente el ejercicio del capítulo 6 (almacenamiento)
- Tener un bucket de GCS con las cargas de imágenes, en el que las personas suban fotos a tu app y las imágenes fluyan a tu bucket
Configura una Cloud Function (en Python)
¿Alguna vez te preguntaste cómo implementar una aplicación orientada a eventos? Algo como lo siguiente:
- cuando ocurre <event> => enviar un correo electrónico
- cuando ocurre <evento> => si <condición> es verdadera, actualiza la base de datos.
El evento puede ser cualquier cosa, desde un registro nuevo disponible en BigQuery, un objeto nuevo modificado en una carpeta de GCS o un mensaje nuevo en espera en una fila de Pub/Sub.
Google Cloud admite varios paradigmas para lograrlo. En particular:
- EventArc. Obtén información para recibir eventos de GCS. Es excelente para crear DAG y organizar acciones basadas en si-entonces-sino en Cloud.
- Cloud Scheduler. Es ideal para un trabajo cron de medianoche en Cloud, por ejemplo.
- Cloud Workflows. Al igual que el arco de eventos, te permite hacer lo siguiente:
- Cloud Run Functions (conocida como
lambdas
). - Cloud Composer. Básicamente, es la versión de Google de Apache Airflow, que también es excelente para DAG.
En este ejercicio, analizaremos Cloud Function para lograr un resultado bastante espectacular. Además, te proporcionaremos ejercicios opcionales.
Ten en cuenta que el código de muestra se proporciona en .solutions/
.
Configura una Cloud Function (🐍 Python)
Intentamos crear un GCF muy ambicioso.
- Cuando se crea una imagen nueva en GCS (probablemente porque alguien lo subió a la app, pero no solo por eso)
- .. llama a Gemini para que la describa y obtengas una descripción textual de la imagen .. (Sería bueno verificar el MIME y asegurarse de que sea una imagen y no un PDF, MP3 o texto).
- y actualiza la base de datos con esta descripción. (esto puede requerir aplicar parches en la base de datos para agregar una columna
description
a la tablaimages
).
Aplica un parche a la base de datos para agregar description
a las imágenes.
- Abre Cloud SQL Studio:
- Ingresa tu usuario y contraseña para la base de datos de imágenes
- Inserta esta sentencia SQL que agrega una columna para una descripción de imagen:
ALTER TABLE images ADD COLUMN description TEXT;
¡Bingo! Prueba ahora para comprobar si funcionó:
SELECT * FROM images;
Deberías ver la nueva columna de descripción:
Escribe el f(x) de Gemini
Nota. En realidad, esta función se creó con la ayuda de Gemini Code Assist.
Nota. Si creas esta función, es posible que se generen errores de permisos de IAM. Algunos se documentan a continuación en el párrafo "Posibles errores".
- Habilitación de las API
- Ve a https://console.cloud.google.com/functions/list.
- Haz clic en "Crear función".
- Habilita las APIs desde el asistente de API:
Puedes crear el GCF desde la IU o desde la línea de comandos. Aquí usaremos la línea de comandos.
Puedes encontrar un código posible en .solutions/
.
- Crea una carpeta para alojar tu código, p. ej., "gcf/". Ingresa a la carpeta.
- Crea un archivo
requirements.txt
:
google-cloud-storage
google-cloud-aiplatform
pymysql
- Crear una función de Python Código de muestra aquí: gcf/main.py.
#!/usr/bin/env python
"""Complete this"""
from google.cloud import storage
from google.cloud import aiplatform
import vertexai
from vertexai.generative_models import GenerativeModel, Part
import os
import pymysql
import pymysql.cursors
# Replace with your project ID
PROJECT_ID = "your-project-id"
GEMINI_MODEL = "gemini-1.5-pro-002"
DEFAULT_PROMPT = "Generate a caption for this image: "
def gemini_describe_image_from_gcs(gcs_url, image_prompt=DEFAULT_PROMPT):
pass
def update_db_with_description(image_filename, caption, db_user, db_pass, db_host, db_name):
pass
def generate_caption(event, context):
"""
Cloud Function triggered by a GCS event.
Args:
event (dict): The dictionary with data specific to this type of event.
context (google.cloud.functions.Context): The context parameter contains
event metadata such as event ID
and timestamp.
"""
pass
- Envía la función. Puedes usar una secuencia de comandos similar a esta: gcf/push-to-gcf.sh.
Nota 1. Asegúrate de obtener los entornos con los valores correctos o simplemente agrégalos en la parte superior (GS_BUCKET=blah
, ..):
Nota 2: Esto enviará todo el código local (.
), así que asegúrate de rodear tu código en una carpeta específica y de usar .gcloudignore
como un profesional para evitar enviar bibliotecas enormes. ( ejemplo).
#!/bin/bash
set -euo pipefail
# add your logic here, for instance:
source .env || exit 2
echo "Pushing ☁️ f(x)☁ to 🪣 $GS_BUCKET, along with DB config.. (DB_PASS=$DB_PASS)"
gcloud --project "$PROJECT_ID" functions deploy php_amarcord_generate_caption \
--runtime python310 \
--region "$GCP_REGION" \
--trigger-event google.cloud.storage.object.v1.finalized \
--trigger-resource "$BUCKET" \
--set-env-vars "DB_HOST=$DB_HOST,DB_NAME=$DB_NAME,DB_PASS=$DB_PASS,DB_USER=$DB_USER" \
--source . \
--entry-point generate_caption \
--gen2
Nota: En este ejemplo, generate_caption
será el método invocado y Cloud Function pasará al evento de GCS con toda la información relevante (nombre del bucket, nombre del objeto, etc.). Tómate un tiempo para depurar ese evento python dict.
Prueba la función
Pruebas de unidades
La función tiene muchos elementos dinámicos. Te recomendamos que pruebes todas las opciones individuales.
Un ejemplo se encuentra en gcf/test.py.
IU de Cloud Functions
Además, tómate un tiempo para explorar tu función en la IU. Vale la pena explorar cada pestaña, especialmente la Source
(la que más me gusta), Variables
, Trigger
y Logs
. Pasarás mucho tiempo en Logs
para solucionar errores (también verás posibles errores al final de esta página). Además, asegúrate de revisar Permissions
.
Prueba de E2E
Es hora de probar la función de forma manual.
- Ve a la app y accede
- Subir una imagen (no es demasiado grande, ya que hemos experimentado problemas con las imágenes grandes)
- verificar la IU en la que se subió la foto.
- Verifica en Cloud SQL Studio que se haya actualizado la descripción. Accede y ejecuta esta consulta:
SELECT * FROM images
.
¡Y funciona! También es posible que debamos actualizar el frontend para mostrar esa descripción.
Actualiza PHP para mostrar [opcional]
Comprobamos que la app funciona. Sin embargo, sería bueno que los usuarios también pudieran ver esa descripción.
No es necesario que seamos expertos en PHP para agregar la descripción a index.php
. Este código debería funcionar (sí, Gemini también lo escribió por mí):
<?php if (!empty($image['description'])): ?>
<p class="font-bold">Gemini Caption:</p>
<p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>
Coloca este código dentro de foreach
a tu gusto.
En los próximos pasos, también veremos una versión más atractiva de la IU, gracias a Gemini Code Assist. Una versión atractiva podría verse así:
Conclusiones
Tienes una Cloud Function activada en objetos nuevos que llegan a GCS, que puede anotar el contenido de la imagen como lo haría una persona y actualizar automáticamente la BD. ¡Vaya!
Próximos pasos Podrías seguir el mismo razonamiento para lograr dos funcionalidades excelentes.
[opcional] Agrega más funciones de Cloud Functions [sin definir]
Se me ocurren algunas funciones adicionales.
📩 Activador de correo electrónico
Un activador de correo electrónico que te envía un correo electrónico cada vez que alguien envía una foto.
- ¿Con demasiada frecuencia? Agrega una restricción adicional: Una imagen GRANDE o una imagen cuyo contenido de Gemini contenga las palabras “desnudo/desnudo/violento”.
- Considera consultar
EventArc
para ello.
🚫 Cómo moderar automáticamente las fotos inapropiadas
Actualmente, un administrador humano marca las imágenes como "inapropiadas". ¿Qué tal si Gemini hace el trabajo pesado y modera el espacio? Agrega una prueba para marcar el contenido del activador inapropiado y actualizar la BD como aprendimos en la función anterior. Esto significa, básicamente, tomar la función anterior, cambiar la instrucción y actualizar la BD según la respuesta.
Advertencia: La IA generativa tiene resultados impredecibles. Asegúrate de que el “resultado creativo” de Gemini esté “sobre rieles”. Puedes solicitar una respuesta determinista, como una puntuación de confianza de 0 a 1, un JSON, etc. Puedes lograr esto de muchas maneras, por ejemplo: * Usando las bibliotecas de Python pydantic
, langchain
, etc. * Usar el resultado estructurado de Gemini.
Nota: Puedes tener MÚLTIPLES funciones o una sola instrucción que aplique una respuesta JSON (funciona muy bien con el "Resultado estructurado de Gemini", como se destacó anteriormente), como las siguientes:
¿Cuál sería la instrucción para generar esto?
{
"description": "This is the picture of an arrosticino",
"suitable": TRUE
}
Podrías agregar campos adicionales a la instrucción para obtener estadísticas como: ¿hay algo bueno en ello? ¿Te molesta? ¿Reconoces el lugar? ¿Hay algo de texto (el OCR nunca fue tan fácil):
goods
: “Parece comida deliciosa”.bads
: “Parece comida poco saludable”.OCR
: "Da consumare preferibilmente prima del 10 Novembre 2024"location
: "Pescara, Lungomare"
Si bien, por lo general, es mejor tener una función N para N resultados, es muy gratificante hacer una que haga 10 cosas. Consulta este artículo de Riccardo para saber cómo.
Posibles errores (en su mayoría, de IAM o permisos)
La primera vez que desarrollé esta solución, me di cuenta de algunos problemas de permisos de IAM. Los agregaré aquí por empatía y para darte algunas ideas sobre cómo solucionarlos.
Error: No hay permisos suficientes para la cuenta de servicio
- Ten en cuenta que, para implementar una función de GCF que escuche un bucket de GCS, debes configurar los permisos adecuados en la cuenta de servicio que usas para la tarea, como se muestra en la siguiente imagen:
Es posible que también debas habilitar las APIs de EventArc, es decir, unos minutos antes de que estén disponibles por completo.
Error: Falta el invocador de Cloud Run
- Otro comentario de la IU sobre los permisos de GCF es el siguiente ( rol de invocador de Cloud Run):
Para corregir este error, ejecuta el comando de la imagen, que es similar a fix-permissions.sh.
Este problema se describe aquí: https://cloud.google.com/functions/docs/securing/authenticating
Error: Se superó el límite de memoria
La primera vez que lo ejecuté, mis registros decían lo siguiente: "Se superó el límite de memoria de 244 MiB con 270 MiB utilizados. Considera aumentar el límite de memoria. Consulta https://cloud.google.com/functions/docs/configuring/memory. Nuevamente, agrega RAM a tu GCF. Esto es muy fácil de hacer en la IU. Este es un posible cambio:
Como alternativa, también puedes corregir la secuencia de comandos de implementación de Cloud Run para aumentar la MEM o la CPU. Este proceso tarda un poco más.
Error: PubSub Published
Cuando se creaba un activador con GCF v1, se generaba este error:
Una vez más, esto es fácil de solucionar. Ve a IAM y asigna a tu cuenta de servicio el rol de “Publicador de Pub/Sub”.
Error: No se usó Vertex AI
Si recibes este error, haz lo siguiente:
Permiso denegado: 403 La API de Vertex AI no se usó en el proyecto YOUR_PROJECT antes o está inhabilitada. Habilítala en https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT
Solo debes habilitar las APIs de Vertex AI. La forma más sencilla de habilitar TODAS las APIs necesarias es la siguiente:
- https://console.cloud.google.com/vertex-ai
- Haz clic en “Habilitar todas las APIs recomendadas”.
Error: No se encontró el activador de Eventarc.
Si recibes este mensaje, vuelve a implementar la función.
Error: Se están aprovisionando 400 agentes de servicio
Se están aprovisionando 400 agentes de servicio ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents). Los agentes de servicio son necesarios para leer el archivo de Cloud Storage proporcionado. Vuelve a intentarlo en unos minutos.
Si esto sucede, espera un tiempo o consulta a un Googler.
10. Módulo 8: Crea SLO de disponibilidad
En el capítulo intentamos lograr esto:
- Crea SLI
- Crea SLO basados en los SLI
- Crea alertas basadas en SLO
Este es un tema muy querido para el autor, ya que Riccardo trabaja en el área de SRE/DevOps de Google Cloud.
(Pregunta abierta) Crear SLI y SLO para esta app
¿Qué tan buena es una app si no puedes saber si está inactiva?
¿Qué es un SLO?
¡Vaya! Google inventó los SLO. Para obtener más información, te recomiendo lo siguiente:
- Libro de SRE, capítulo 2: Implementa SLOs. ( 👉 más libros de SRE)
- Art of SLOs ( video increíble). Es una capacitación fantástica para aprender a crear un SLO perfecto para tu servicio.
- Curso de SRE en Coursera. Yo contribuí a ello.
Paso 1: Crea un SLI o ANS de disponibilidad
Comencemos con el SLO de disponibilidad, ya que es el más fácil y posiblemente el más importante que se debe medir.
Por suerte, Cloud Run incluye compatibilidad con SLO precompilados gracias a Istio.
Una vez que tu app esté en Cloud Run, esto es muy sencillo de lograr, me lleva 30 segundos.
- Ve a tu página de Cloud Run.
- Haz clic en tu app o selecciónala.
- Selecciona la pestaña
SLOs
. - Haz clic en “+ Crear SLO”.
- Disponibilidad, basada en solicitudes
- Continuar
- Mes del calendario/99%
- Haz clic en "Crear SLO".
Paso 2: Configura alertas en este SLO
Te sugerimos que crees 2 alertas:
- Una con un ritmo de consumo bajo ("Slowburn") para alertarte por correo electrónico (simula un ticket de bajo costo).
- Uno con una tasa de quema alta ("Fastburn") para enviarte una alerta por SMS (simula un ticket o localizador de alta prioridad)
Ve a tu SLO tab
anterior.
Hazlo dos veces:
- Haz clic en "Crear alerta de SLO" (el botón 🔔 con un signo más a la derecha).
- Duración de la visualización, umbral del porcentaje de consumo:
- [RÁPIDA]. Primero:
60
min/10
x - [SLOW] Segundo:
720
min /2
x - Canal de notificaciones: Haz clic en Administrar canales de notificaciones.
- Primero, "Correo electrónico" -> Agregar nuevo -> ..
- Segundo, "SMS" -> Agregar nuevo -> Verificar en el teléfono.
- Sugerencia: ¡Me gusta usar emojis en los nombres! Es divertido para las demostraciones.
- cuando hayas terminado, haz clic en la X grande de la parte superior derecha.
- Seleccionar primero el teléfono (rápido) y el correo electrónico después (lento).
- Agrega documentación de muestra, como la siguiente:
[PHP Amarcord] Riccardo told me to type sudo reboot or to check documentation in http://example.com/playbooks/1.php but I guess he was joking
.
¡Exacto!
Resultado final
Podemos considerar que este ejercicio finalizó una vez que tengas 1 SLO en funcionamiento + 2 alertas de disponibilidad, y que se envíen alertas a tu correo electrónico y a tu teléfono.
Si lo deseas, puedes agregar una Latencia (y te recomendamos que lo hagas) o incluso una más compleja. Para la latencia, elige una que consideres razonable. Si tienes dudas, elige 200 ms.
11. Próximos pasos
Completaste TODO, ¿qué falta?
Algunos elementos para reflexionar:
Juega con Gemini
Puedes usar Gemini en dos variantes:
- Vertex AI. El “enfoque empresarial”, entrelazado con tu GCP, que exploramos en el capítulo 7 (GCF y Gemini). Toda la autenticación funciona como por arte de magia, y los servicios se interconectan de forma atractiva.
- IA de Google. La "Ruta del consumidor". Obtén una clave de API de Gemini aquí y comienza a compilar pequeñas secuencias de comandos que se pueden vincular a cualquier carga de trabajo que ya tengas (trabajo propietario, otras nubes, localhost, etcétera). Solo tienes que reemplazar tu clave de API y el código comenzará a funcionar mágicamente.
Te recomendamos que intentes explorar la opción (2) con tus propios proyectos personales.
Levantamiento de la IU
No soy bueno con las IU. ¡Pero Gemini sí! Puedes tomar una sola página de PHP y decir algo como lo siguiente:
I have a VERY old PHP application. I want to touch it as little as possible. Can you help me:
1. add some nice CSS to it, a single static include for tailwind or similar, whatever you prefer
2. Transform the image print with description into cards, which fit 4 per line in the canvas?
Here's the code:
-----------------------------------
[Paste your PHP page, for instance index.php - mind the token limit!]
Puedes obtener esto fácilmente en menos de 5 minutos, con una compilación de Cloud Build. :)
La respuesta de Gemini fue perfecta (es decir, no tuve que cambiar nada):
Este es el nuevo diseño en la app personal del autor:
Nota: El código se pega como imagen porque no queremos que lo tomes, sino que Gemini lo escriba por ti, con tus propias restricciones de IU o frontend de la creatividad. Créeme, después solo tendrás que hacer pequeños cambios.
Seguridad
Proteger correctamente esta app no es un objetivo de este taller de 4 horas.
Para ver algunas ideas, consulta la SECURITY
doc
.
12. ¡Felicitaciones!
Felicitaciones 🎉🎉🎉 , modernizaste con éxito tu aplicación de PHP heredada con Google Cloud.
En resumen, en este codelab aprendiste lo siguiente:
- Cómo implementar una base de datos MySQL en Google Cloud SQL y migrar a ella tu base de datos existente.
- Cómo alojar en contenedores tu aplicación de PHP con Docker y Buildpacks, y almacenar la imagen en Artifact Registry de Google Cloud
- Cómo implementar tu app alojada en contenedores en Cloud Run y hacer que se ejecute con Cloud SQL
- Cómo almacenar o usar de forma secreta parámetros de configuración sensibles (como la contraseña de la base de datos) con Google Secret Manager
- Cómo configurar tu canalización de CI/CD con Google Cloud Build para compilar y, luego, implementar automáticamente tu app de PHP en cualquier envío de código a tu repositorio de GitHub.
- Cómo usar Cloud Storage para “migrar a la nube” los recursos de tu app
- Cómo aprovechar las tecnologías sin servidores para crear flujos de trabajo increíbles en Google Cloud sin modificar el código de tu app
- Usa las funciones multimodales de Gemini para un caso de uso adecuado.
Este es un gran comienzo para tu recorrido hacia la modernización de aplicaciones con Google Cloud.
🔁 Comentarios
Si quieres contarnos sobre tu experiencia con este taller, considera completar este formulario de comentarios.
Nos complace recibir tus comentarios, así como PR para los fragmentos de código de los que te sientas particularmente orgulloso.
🙏 Gracias
El autor agradece a Mirko Gilioli y Maurizio Ipsale de Datatonic por su ayuda con la redacción y la prueba de la solución.