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 que deben ser escalables, seguros y se deben poder 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 la app en Cloud Run (es una alternativa sin operaciones a GKE/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.
- Aloja 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 infraestructura y sus servicios potentes 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 simples 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 la licencia MIT) que clonarás es una aplicación básica de PHP 5.7 con autenticación de MySQL. La idea principal de la app es proporcionar una plataforma en la que los usuarios puedan subir fotos y los administradores puedan 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, aumentar la seguridad, automatizar la administración de la infraestructura y, además, 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, Secret Manager y mucho más.
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? Descarga la versión 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 (compromiso automático -> compilación -> implementación).
Aquí encontrarás soluciones de muestra:
- Repositorio del autor: https://github.com/Friends-of-Ricc/app-mod-workshop
- El repositorio original del taller, en carpetas
.solutions/
, por capítulo.
Puedes realizar este taller desde tu computadora local o completamente en un navegador.
2. Configuración de crédito y bifurcación
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 Google Gmail (*) 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 aparezca la cuenta de facturación 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 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):
Crea una bifurcación de 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/
YOUR-GITHUB-USER/YOUR-REPO-NAME
- 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.
Para hacerlo, haz clic en "Open Folder" y selecciona la carpeta, probablemente app-mod-workshop
en tu carpeta principal.
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 y, por lo tanto, debemos replicarla en Google Cloud para realizar una migración sin problemas. Cloud SQL es la opción perfecta, ya que te permite ejecutar una base de datos de 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ó)
- Versión de MySQL: 5.7 (¡vaya, un recuerdo del 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 anótala como 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 demora alrededor de 10 minutos⌛. 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 costarte alrededor de USD 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 la 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 la opción "Permitir cualquier host (%)".
- haz clic en AGREGAR.
Abre la BD a IPs conocidas.
Ten en cuenta que todas las bases de datos de 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 red (es decir, una subred).
- Por ahora, elijamos una configuración rápida pero INSEGUR para permitir que funcione la app. Más adelante, te recomendamos que la restrinjas a las IPs de confianza:
- Nombre: "Todos en el mundo: INSECURE".
- Red: "
0.0.0.0/0"
(Nota: esta es la parte INSEGURA) - Haz clic en LISTO.
- 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 estás en el editor, puedes abrirlo 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 image_catalog
con sus datos. Copia el código SQL de los archivos del repositorio ( 01_schema.sql y, luego, 02_seed.sql) y ejecútalos uno tras otro en un orden secuencial.
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 de la instancia de Cloud SQL, ya que la necesitarás más adelante. Para obtener la IP, ve a la página principal de la instancia de Cloud SQL en la página Descripción general. (Descripción general > Conéctate a esta instancia > Dirección IP pública).
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 maneras de empaquetar el contenido:
- Docker Es muy popular, pero es bastante complejo configurarlo correctamente.
- Paquetes de compilación. Es 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.
Si elegiste usar Cloud Shell, este es el momento de volver a abrirlo (haz clic en la parte superior derecha de la consola de Cloud).
Se debería abrir una shell conveniente en la parte inferior de la página, en la que deberías haber bifurcado el código en el paso de configuración.
Docker
Si quieres tener control, esta es la solución adecuada para ti. Esto tiene sentido cuando necesitas configurar bibliotecas específicas y, además, insertar ciertos comportamientos no obvios (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. ¿Cómo lo portarías a PHP 5.7 desde PHP 8? Tal vez puedas usar Gemini para ello. Como alternativa, puedes usar esta versión precompilada:
La versión más reciente de Dockerfile
está disponible aquí.
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:
<?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();
?>
DB_HOST
es la dirección IP pública de Cloud SQL, que puedes encontrar en la consola de SQL:
DB_NAME
no debe cambiar:image_catalog
DB_USER
debe serappmod-phpapp-user
DB_PASS
es algo que elegiste. Establece la cadena entre comillas simples y escapa según sea necesario.
Además, no dudes en traducir las pocas piezas 🇮🇹 italianas al inglés con la ayuda de Gemini.
Bien, ahora que tienes el Dockerfile
y configuraste tu app de PHP para conectarte a tu BD, 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.
# Build command - don't forget the final . This works if Dockerfile is inside the code folder:
$ docker build -t my-php-app-docker .
# Local Run command: most likely ports will be 8080:8080
$ docker run -it -p <CONTAINER_PORT>:<LOCAL_MACHINE_PORT> my-php-app-docker
Si todo funciona, deberías poder ver la siguiente página web cuando te conectes al host local. Ahora 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 lo siguiente.
¡Excelente! Aparte del texto en italiano, 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.
Guardado en Artifact Registry [opcional]
A estas alturas, deberías tener una aplicación de PHP alojada en contenedores en funcionamiento lista para implementarse en la nube. A continuación, necesitamos un lugar en la nube para almacenar nuestra imagen de Docker y que sea accesible para la implementación en servicios de Google Cloud, como Cloud Run. Esta solución de almacenamiento se denomina Artifact Registry, un servicio de Google Cloud completamente administrado diseñado para almacenar artefactos de aplicaciones, incluidas imágenes de contenedores de Docker, paquetes de Maven, módulos de npm y mucho más.
Crear 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. Antes de eso, dedica 2 minutos a intentar subir, acceder y salir, y familiarizarte con los extremos de la app.Los necesitarás más adelante.
Posibles errores
Si recibes errores de contenedorización, intenta usar Gemini para explicar y corregir el error. Para ello, proporciona la siguiente información:
- Tu Dockerfile actual
- El error recibido
- [si es necesario] el código PHP que se ejecuta
Permisos de carga. También prueba el extremo /upload.php
y sube una foto. Es posible que recibas el siguiente error. Si es así, tienes que corregir chmod/chown
en Dockerfile
.
Advertencia: move_uploaded_file(uploads/image (3).png): no se pudo abrir la transmisión: Se denegó el permiso en /var/www/html/upload.php en la línea 11
PDOException "could not find driver" (o "Errore di connessione: could not find driver"). Asegúrate de que tu Dockerfile tenga las bibliotecas de PDO adecuadas para mysql (pdo_mysql
) para conectarse a la BD. Obtén inspiración de las soluciones que se encuentran aquí.
No se pudo reenviar tu solicitud a un backend. No se pudo conectar a un servidor en el puerto 8080. Esto significa que probablemente estás exponiendo el puerto incorrecto. Asegúrate de exponer el puerto desde el que Apache o Nginx realmente se entregan. Esto no es trivial. Si es posible, intenta que ese puerto sea el 8080 (facilita la vida con Cloud Run). Si quieres conservar el puerto 80 (p. ej., porque Apache lo quiere de esa manera), usa un comando diferente para ejecutarlo:
$ docker run -it -p 8080:80 # force 80
# Use the PORT environment variable in Apache configuration files.
# https://cloud.google.com/run/docs/reference/container-contract#port
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf
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.
Más 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 usas Google Cloud Shell, no es necesario que realices ninguna acción.
Antes de implementar…
Si trabajas en tu entorno local, autenticarte en Google Cloud con lo siguiente
$ 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 Chrome con el mismo usuario (p. ej., vattelapesca@gmail.com) que accedió a Google Cloud con la facturación habilitada.
Habilita la API de Cloud Run con el siguiente comando:
$ gcloud services enable run.googleapis.com cloudbuild.googleapis.com
En este punto, todo está listo para implementarse en Cloud Run.
Implementa tu app en Cloud Run a través de 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 de opciones (que puedes proporcionar a través de la línea de comandos o que la herramienta te pedirá con una instrucción interactiva) 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. (
--region
REGION) - Imagen de contenedor que une tu app.
- Variables de entorno que tu app debe usar durante su ejecución.
- La marca Allow-Unauthenticated, que permite que todas las personas accedan a tu app sin autenticación adicional.
Consulta la documentación (o desplázate hacia abajo para encontrar una posible solución) para ver cómo aplicar esta opción a tu línea de comandos.
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" sin argumentos
Es posible que 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 podremos permitirnos preguntas interactivas. Debemos completar todas las opciones del comando. Por lo tanto, quieres crear el gcloud run deploy --option1 blah --foo bar --region your-fav-region
dorado. ¿Cómo lo harí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] Los sistemas solicitan 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í. Los documentos se encuentran 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 de seguridad incorrecta: 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 desde 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') ?: 'localhost';
$db_name = getenv('DB_NAME') ?: 'image_catalog';
$db_user = getenv('DB_USER') ?: 'appmod-phpapp-user';
$db_pass = getenv('DB_PASS') ?: 'wrong_password';
// 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, ya sea desde la CLI o 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 ENV 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. Vayamos 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:
¿Está bien? 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
Tus 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” y llámalo de forma racional:
- Nombre:
php-amarcord-db-pass
- Valor secreto: "your DB password" (ignora la parte "upload file").
- annotate this secret link, should look like
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, que se especialicen 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 figura:
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.
En esta sección, nos enfocaremos en configurar Cloud Build.
¡Ingresa a Cloud Build!
Para ello, usaremos Cloud Build:
- compilar tu fuente (con Dockerfile) Piensa en esto como un “gran archivo .zip” 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 para mi app de php-amarcord
:
¿Cómo hacemos todo esto?
- Con la creación de un archivo YAML perfecto:
cloudbuild.yaml
- Crea un activador de Cloud Build.
- Conectándonos a nuestro repositorio de GitHub a través de la IU de Cloud Build.
Cómo crear un activador (y conectar un repositorio)
- Ve a https://console.cloud.google.com/cloud-build/triggers.
- Haz clic en “Crear activador”.
- Compila:
- 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 demore 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.
Tengo el poder.
Ahora, el activador no funcionará, a menos que le proporciones 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 implementar la app, a menos que le des permiso 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 opción “Establecer como la 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
- Cómo encontrar el error
- Corrige el código y vuelve a emitir git commit o 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, si tienes un problema 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, o no funcionará.
"Paridad de dev/prod" profunda o superficial [opcional]
Si copiaste la versión del modelo de aquí, tendrás dos versiones idénticas de DEV y PROD. 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 en 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: Cómo migrar 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 revisión, con un almacenamiento vacío: 🙈
¿Cómo lo solucionamos? 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 compatible con el almacenamiento: GCE + disco persistente? ¿Quizás GKE + Storage? Nota: Lo que ganas en control, lo pierdes en agilidad.
- 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 nos ensuciemos con las bibliotecas de 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 realizar cargas de archivos con estado sin tocar el código en ABSOLUTO (aparte de mostrar una descripción de 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 ocurrirá con los objetos subidos a GCS (capítulo 7).
Nota. Lee la letra pequeña de FUSE. Esto NO es correcto 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 montaje 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 > Activación de volúmenes, activa el volumen que acabas de crear en el punto de activación que solicitó 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 nueva aplicación 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?
Ocurrió 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 se recibe una imagen con contenido “peligroso” o “nudo”? 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 Google Gemini
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 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)
Estamos tratando de 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 BD con esta descripción. (es posible que debas aplicar un parche a la BD 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 la función f(x) de Gemini.
Nota. Esta función se creó con la ayuda de Gemini Code Assist.
Nota. Si creas esta función, es posible que cometas 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
- Crea 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 le pasará el evento de GCS con toda la información relevante (nombre del bucket, nombre del objeto, etc.). Tómate un tiempo para depurar ese diccionario de Python del evento.
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, en particular Source
(mi favorita), Variables
, Trigger
y Logs
. Pasarás mucho tiempo en Logs
para solucionar problemas (también puedes ver los posibles errores en la parte inferior 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
- Sube una foto (no demasiado grande, ya que tuvimos problemas con imágenes grandes).
- Comprueba en la IU que la foto se haya subido.
- Verifica en Cloud SQL Studio que se haya actualizado la descripción. Accede y ejecuta esta consulta:
SELECT * FROM images
.
¡Y funciona! También podríamos 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ó para 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 bonita 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 Puedes seguir el mismo razonamiento para lograr dos grandes funcionalidades.
[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 otra restricción: una imagen GRANDE o una imagen cuyo contenido de Gemini contenga las palabras "nudo/desnudez/violento".
- Considera consultar
EventArc
para ello.
🚫 Modera automáticamente las imágenes inapropiadas
Actualmente, un administrador humano marca las imágenes como "inapropiadas". ¿Qué tal si Gemini se encarga del 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 de la creatividad" de Gemini esté "en orden". 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 algún 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)
Cuando comencé a desarrollar esta solución, encontré algunos problemas de permisos de IAM. Los agregaré aquí por empatía y para darte algunas ideas sobre cómo solucionarlos.
Error: No hay suficientes permisos 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, lo que puedes hacer unos minutos antes de que estén disponibles por completo.
Error: Falta el invocador de Cloud Run
- Este es otro comentario de la IU para los permisos de GCF ( 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. Una vez más, agrega RAM a tu GCF. Esto es muy fácil de hacer en la IU. Esta es una posible irregularidad:
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 tardará 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. Para habilitarla, visita 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 aprovisionan 400 agentes de servicio
Se aprovisionan 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 lo siguiente:
- 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) Crea SLI y SLO para esta app
¿Qué tan buena es una app si no puedes saber cuándo 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 obtener más información sobre cómo 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 lo más fácil y, posiblemente, lo más importante que deseas 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 las alertas en este SLO
Te sugiero que crees 2 alertas:
- Uno con una tasa de agotamiento baja ("Slowburn") para enviarte una alerta por correo electrónico (simula un ticket de prioridad baja).
- Uno con una tasa de quema alta ("Fastburn") para enviarte una alerta por SMS (simula un ticket de alta prioridad o un localizador)
Ve a tu SLO tab
anterior.
Haz lo siguiente 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, Límite de tasa de gasto:
- [RÁPIDA]. Primero:
60
min /10
x - [LENTA]. 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 termines, haz clic en la X grande de la esquina superior derecha.
- Selecciona el teléfono primero (rápido) y, luego, el correo electrónico (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
.
¡Bingo!
Resultado final
Podemos considerar que este ejercicio está terminado 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 (te recomiendo 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?
Ten en cuenta lo siguiente:
Juega con Gemini
Puedes usar Gemini en dos versiones:
- Vertex AI. La “manera empresarial”, entrelazada con tu GCP, que exploramos en el capítulo 7 (GCF+Gemini). Toda la autenticación funciona de forma mágica y los servicios se interconectan de forma excelente.
- 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 un 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
La seguridad adecuada de esta app no es un objetivo de este taller de 4 horas, ya que aumentaría el tiempo de finalización en 1 o 2 órdenes de magnitud.
Sin embargo, este tema es muy importante. Recopilamos algunas ideas en SECURITY
.
12. ¡Felicitaciones!
¡Felicidades! 🎉🎉🎉 Modernizaste correctamente tu aplicación heredada de PHP con Google Cloud.
En resumen, en este codelab aprendiste lo siguiente:
- Cómo implementar una base de datos en Google Cloud SQL y cómo migrar tu base de datos existente a ella
- Cómo alojar en contenedores tu aplicación de PHP con Docker y Buildpacks, y almacenar su imagen en Google Cloud Artifact Registry
- 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 e implementar automáticamente tu app de PHP cada vez que envíes 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.
- Implementa los principios de SRE en Google Cloud
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.