Atelier App Mod

1. Introduction

Dernière mise à jour : 01/11/2024

Comment moderniser une ancienne application PHP pour Google Cloud ?

(📽️ regardez une vidéo d'introduction de sept minutes à cet atelier de programmation)

Il est courant d'avoir des applications anciennes exécutées sur site qui doivent être modernisées. Cela signifie les rendre évolutifs, sécurisés et déployables dans différents environnements.

Au cours de cet atelier, vous allez :

  1. Conteneurisez l'application PHP.
  2. Passez à un service de base de données géré ( Cloud SQL).
  3. Déployez sur Cloud Run (alternative sans opération à GKE/Kubernetes).
  4. Sécurisez l'application avec Identity and Access Management (IAM) et Secret Manager.
  5. Définissez un pipeline CI/CD via Cloud Build. Cloud Build peut être associé à votre dépôt Git hébergé sur des fournisseurs Git populaires tels que GitHub ou GitLab, et être déclenché à chaque commit sur la branche principale, par exemple.
  6. Hébergez les images de l'application sur Cloud Storage. Pour ce faire, il suffit de monter l'application. Aucune modification de code n'est nécessaire.
  7. Présentation des fonctionnalités d'IA générative via Gemini, orchestrées via Cloud Functions (sans serveur).
  8. Familiarisez-vous avec les SLO et le fonctionnement de votre nouvelle application.

En suivant ces étapes, vous pouvez moderniser progressivement votre application PHP, en améliorant son évolutivité, sa sécurité et la flexibilité de son déploiement. De plus, le passage à Google Cloud vous permet d'exploiter son infrastructure et ses services puissants pour garantir le bon fonctionnement de votre application dans un environnement cloud natif.

Nous pensons que ce que vous apprendrez en suivant ces étapes simples pourra être appliqué à votre propre application et organisation avec différentes langues/piles et différents cas d'utilisation.

À propos de l'application

L'application ( code, sous licence MIT) que vous allez forker est une application PHP 5.7 de base avec authentification MySQL. L'objectif principal de l'application est de fournir une plate-forme sur laquelle les utilisateurs peuvent importer des photos et les administrateurs peuvent identifier les images inappropriées. L'application comporte deux tables :

  • Utilisateurs. Il est précompilé avec les administrateurs. Les nouveaux utilisateurs peuvent s'inscrire.
  • Images. Il inclut quelques exemples d'images. Les utilisateurs connectés peuvent importer de nouvelles photos. Nous allons ajouter un peu de magie ici.

Votre objectif

Nous souhaitons moderniser l'ancienne application pour l'avoir dans Google Cloud. Nous tirerons parti de ses outils et services pour améliorer l'évolutivité, renforcer la sécurité, automatiser la gestion de l'infrastructure et intégrer des fonctionnalités avancées telles que le traitement d'images, la surveillance et le stockage de données à l'aide de services tels que Cloud SQL, Cloud Run, Cloud Build, Secret Manager, etc.

445f7a9ae37e9b4d.png

Plus important encore, nous voulons le faire étape par étape afin que vous puissiez comprendre le raisonnement derrière chaque étape. En général, chaque étape ouvre de nouvelles possibilités pour les suivantes (par exemple, les modules 2 et 3, et les modules 6 et 7).

Vous n'êtes pas encore convaincu ? Regardez cette vidéo de sept minutes sur YouTube.

Prérequis

  • Un ordinateur équipé d'un navigateur et connecté à Internet.
  • Certains crédits GCP. Pour en savoir plus, consultez l'étape suivante.
  • Vous utiliserez Cloud Shell. Il est fourni avec toutes les commandes préinstallées dont vous aurez besoin et un IDE.
  • Un compte GitHub. Vous en aurez besoin pour créer une branche du code d'origine 🧑🏻‍💻 gdgpescara/app-mod-workshop avec votre propre dépôt Git. Cela est nécessaire pour disposer de votre propre pipeline CI/CD (commit automatique → compilation → déploiement).

Vous trouverez des exemples de solutions ici :

Cet atelier est conçu pour être réalisé dans Cloud Shell (sur un navigateur).

Toutefois, vous pouvez également essayer de le faire depuis votre ordinateur local.

2. Configurer un avoir et un fork

6dafc658860c0ce5.png

Utiliser le crédit GCP et configurer votre environnement GCP [facultatif]

Pour suivre cet atelier, vous avez besoin d'un compte de facturation avec un certain crédit. Si vous avez déjà votre propre facturation, vous pouvez ignorer cette étape.

Créez un compte Google Gmail (*) à associer à votre crédit GCP. Demandez à votre enseignant le lien pour utiliser le crédit GCP ou utilisez-le ici : bit.ly/PHP-Amarcord-credits .

Connectez-vous avec le compte nouvellement créé et suivez les instructions.

ff739240dbd84a30.png

(

) Pourquoi ai-je besoin d'un tout nouveau compte Gmail ?*

Nous avons constaté que certaines personnes échouaient à l'atelier de programmation, car leur compte (en particulier leur adresse e-mail professionnelle ou scolaire) avait déjà été exposé à GCP et était soumis à des Règles de l'organisation qui les empêchaient de le faire. Nous vous recommandons de créer un compte Gmail ou d'utiliser un compte Gmail (gmail.com) existant qui n'a jamais été exposé à GCP.

Cliquez sur le bouton pour utiliser le crédit.

331658dc50213403.png

Remplissez le formulaire ci-dessous avec votre nom et votre prénom, puis acceptez les conditions d'utilisation.

Vous devrez peut-être attendre quelques secondes avant que le compte de facturation n'apparaisse ici : https://console.cloud.google.com/billing.

Une fois l'opération terminée, ouvrez la console Google Cloud et créez un projet en cliquant sur le sélecteur de projet dans le menu déroulant en haut à gauche, là où "Aucune organisation" est indiqué. Voir ci-dessous

bd7548f78689db0b.png

Créez un projet si vous n'en avez pas déjà un, comme indiqué dans la capture d'écran ci-dessous. L'option "NOUVEAU PROJET" se trouve en haut à droite.

6c82aebcb9f5cd47.png

Veillez à associer le nouveau projet au compte de facturation de l'essai GCP comme suit.

f202527d254893fb.png

Vous êtes prêt à utiliser Google Cloud Platform. Si vous êtes débutant ou si vous souhaitez tout faire dans un environnement cloud, vous pouvez accéder à Cloud Shell et à son éditeur en cliquant sur le bouton en haut à gauche, comme indiqué ci-dessous.

7d732d7bf0deb12e.png

Assurez-vous que votre nouveau projet est sélectionné en haut à gauche :

Non sélectionné (mauvais) :

c2ffd36a781b276a.png

Sélectionnée (bonne) :

594563c158f4f590.png

Forker l'application depuis GitHub

  1. Accédez à l'application de démonstration : https://github.com/gdgpescara/app-mod-workshop
  2. Cliquez sur 🍴 Dupliquer.
  3. Si vous n'avez pas de compte GitHub, vous devez en créer un.
  4. Modifiez les éléments comme vous le souhaitez.

734e51bfc29ee5df.png

  1. Clonez le code de l'application à l'aide de
  2. git clone https://github.com/YOUR-GITHUB-USER/YOUR-REPO-NAME
  1. Ouvrez le dossier du projet cloné avec l'éditeur de votre choix. Si vous choisissez Cloud Shell, vous pouvez le faire en cliquant sur Ouvrir l'éditeur, comme indiqué ci-dessous.

40f5977ea4c1d1cb.png

Vous disposez de tout ce dont vous avez besoin avec l'éditeur Cloud Shell, comme le montre la figure suivante.

a4e5ffb3e9a35e84.png

Pour ce faire, cliquez sur "Ouvrir un dossier" et sélectionnez le dossier, probablement app-mod-workshop dans votre dossier de base.

3. Module 1 : Créer une instance SQL

645902e511a432a6.png

Créer l'instance Google Cloud SQL

Notre application PHP se connecte à une base de données MySQL. Nous devons donc la répliquer sur Google Cloud pour une migration sans problème. Cloud SQL est la solution idéale, car il vous permet d'exécuter une base de données MySQL entièrement gérée dans le cloud. Voici les étapes à suivre :

  1. Accédez à la page Cloud SQL : https://console.cloud.google.com/sql/instances.
  2. Cliquez sur "Créer une instance".
  3. Activez l'API (si nécessaire). Cette opération peut prendre quelques secondes.
  4. Choisissez MySQL.
  5. (Nous essayons de vous proposer la version la moins chère, pour qu'elle dure plus longtemps) :
  • Édition : Enterprise
  • Préréglage : development (nous avons essayé Sandbox, mais cela n'a pas fonctionné pour nous)
  • Version de MySQL : 5.7 (une version très ancienne)
  1. ID d'instance : choisissez appmod-phpapp (si vous le modifiez, n'oubliez pas de modifier également les futurs scripts et solutions en conséquence).
  2. Mot de passe : saisissez le mot de passe de votre choix, mais notez-le sous le nom CLOUDSQL_INSTANCE_PASSWORD.
  3. Région : conservez la même que celle que vous avez choisie pour le reste de l'application (par exemple, Milan = europe-west8).
  4. Disponibilité zonale : zone unique (nous faisons des économies pour la démo)

Cliquez sur le bouton "Create Instance" (Créer une instance) pour déployer la base de données Cloud SQL. ⌛ Cette opération prend environ 10 minutes. ⌛ En attendant, continuez à lire la documentation. Vous pouvez également commencer à résoudre le module suivant ("Conteneuriser votre application PHP"), car il n'a aucune dépendance vis-à-vis de ce module dans la première partie (jusqu'à ce que vous corrigiez la connexion à la base de données).

Remarque : Cette instance devrait vous coûter environ 7$/jour. N'oubliez pas de le désactiver après l'atelier.

Créer la base de données et l'utilisateur image_catalog dans Cloud SQL

Le projet d'application est fourni avec un dossier db/ qui contient deux fichiers SQL :

  1. 01_schema.sql : contient le code SQL permettant de créer deux tables contenant des données sur les utilisateurs et les images.
  2. 02_seed.sql : contient le code SQL permettant d'insérer des données dans les tables créées précédemment.

Ces fichiers seront utilisés ultérieurement, une fois la base de données image_catalog créée. Pour ce faire, procédez comme suit :

  1. Ouvrez votre instance et cliquez sur l'onglet "Bases de données" :
  2. cliquez sur "Créer une base de données".
  3. appelez-le image_catalog (comme dans la configuration de l'application PHP).

997ef853e5ebd857.png

Nous créons ensuite l'utilisateur de la base de données. Cela nous permet de nous authentifier dans la base de données image_catalog.

  1. Cliquez ensuite sur l'onglet Utilisateurs.
  2. Cliquez sur "Ajouter un compte utilisateur".
  3. Utilisateur : créons-en un :
  • Nom d'utilisateur : appmod-phpapp-user
  • Mot de passe : choisissez un mot de passe facile à retenir ou cliquez sur "Générer".
  • Conservez Autoriser tous les hôtes (%).
  1. cliquez sur AJOUTER.

Ouvrez la base de données aux adresses IP connues.

Notez que toutes les bases de données de Cloud SQL sont "isolées" par défaut. Vous devez configurer explicitement un réseau à partir duquel l'appareil sera accessible.

  1. Cliquez sur votre instance.
  2. Ouvrez le menu "Connexions".
  3. Cliquez sur l'onglet "Réseau".
  4. Cliquez sous "Réseaux autorisés". Ajoutez maintenant un réseau (c'est-à-dire un sous-réseau).
  • Pour l'instant, choisissons des paramètres rapides, mais NON SÉCURISÉS pour que l'application fonctionne. Vous pourrez les limiter ultérieurement aux adresses IP de confiance :
  • Nom : "Tout le monde dans le monde – NON SÉCURISÉ".
  • Réseau : "0.0.0.0/0" (Remarque : il s'agit de la partie NON SÉCURISÉE !)
  • Cliquez sur OK.
  1. Cliquez sur "Enregistrer".

L'écran qui s'affiche devrait ressembler à ce qui suit :

5ccb9062a7071964.png

Remarque : Cette solution constitue un bon compromis pour terminer l'atelier en O(heures). Toutefois, consultez le document SÉCURITÉ pour sécuriser votre solution pour la production.

Il est temps de tester la connexion à la base de données !

Vérifions si l'utilisateur image_catalog que nous avons créé précédemment fonctionne.

Accédez à "Cloud SQL Studio" dans l'instance, puis saisissez la base de données, l'utilisateur et le mot de passe pour vous authentifier, comme indiqué ci-dessous :

d56765c6154c11a4.png

Maintenant que vous êtes connecté, vous pouvez ouvrir l'éditeur SQL et passer à la section suivante.

Importer la base de données à partir du code source

Utilisez l'éditeur SQL pour importer les tables image_catalog avec leurs données. Copiez le code SQL des fichiers du dépôt ( 01_schema.sql, puis 02_seed.sql) et exécutez-les l'un après l'autre, dans l'ordre.

Vous devriez ensuite obtenir deux tables dans le catalogue d'images, à savoir users et images, comme indiqué ci-dessous :

65ba01e4c6c2dac0.png

Vous pouvez le tester en exécutant la commande suivante dans l'éditeur : select * from images;

Assurez-vous également de noter l'adresse IP publique de l'instance Cloud SQL, car vous en aurez besoin plus tard. Pour obtenir l'adresse IP, accédez à la page principale de l'instance Cloud SQL, sous la page Présentation. (Présentation > Se connecter à cette instance > Adresse IP publique).

4. Module 2 : Conteneuriser votre application PHP

e7f0e9979d8805f5.png

Nous voulons créer cette application pour le cloud.

Cela signifie que vous devez empaqueter le code dans un fichier ZIP contenant toutes les informations nécessaires à son exécution dans le cloud.

Vous pouvez l'empaqueter de plusieurs façons :

  • Docker Très populaire, mais assez complexe à configurer correctement.
  • Buildpacks Moins populaire, mais a tendance à "deviner automatiquement" ce qu'il faut compiler et exécuter. Souvent, tout fonctionne simplement !

Dans le contexte de cet atelier, nous partons du principe que vous utilisez Docker.

Si vous avez choisi d'utiliser Cloud Shell, c'est le moment de le rouvrir (cliquez en haut à droite de la console Cloud).

ec6a6b90b39e03e.png

Un shell pratique devrait s'ouvrir en bas de la page, où vous devriez avoir forké le code lors de l'étape de configuration.

6999b906c0dedeb7.png

Docker

Si vous souhaitez avoir le contrôle, cette solution est faite pour vous. Cela est logique lorsque vous devez configurer des bibliothèques spécifiques et injecter certains comportements non évidents (un chmod dans les importations, un exécutable non standard dans votre application, etc.).

Comme nous souhaitons déployer notre application conteneurisée sur Cloud Run, consultez la documentation suivante. Comment le rétroporter de PHP 8 vers PHP 5.7 ? Vous pouvez peut-être utiliser Gemini pour cela. Vous pouvez également utiliser cette version prédéfinie :

# Use the official PHP image: https://hub.docker.com/_/php
FROM php:5.6-apache

# Configure PHP for Cloud Run.
# Precompile PHP code with opcache.
# Install PHP's extension for MySQL
RUN docker-php-ext-install -j "$(nproc)" opcache mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql

RUN set -ex; \
  { \
    echo "; Cloud Run enforces memory & timeouts"; \
    echo "memory_limit = -1"; \
    echo "max_execution_time = 0"; \
    echo "; File upload at Cloud Run network limit"; \
    echo "upload_max_filesize = 32M"; \
    echo "post_max_size = 32M"; \
    echo "; Configure Opcache for Containers"; \
    echo "opcache.enable = On"; \
    echo "opcache.validate_timestamps = Off"; \
    echo "; Configure Opcache Memory (Application-specific)"; \
    echo "opcache.memory_consumption = 32"; \
  } > "$PHP_INI_DIR/conf.d/cloud-run.ini"

# Copy in custom code from the host machine.
WORKDIR /var/www/html

COPY . .

# Setup the PORT environment variable in Apache configuration files: https://cloud.google.com/run/docs/reference/container-contract#port
ENV PORT=8080

# Tell Apache to use 8080 instead of 80.
RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf

# Note: This is quite insecure and opens security breaches. See last chapter for hardening ideas.
# Uncomment at your own risk:
#RUN chmod 777 /var/www/html/uploads/

# Configure PHP for development.
# Switch to the production php.ini for production operations.
# RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# https://github.com/docker-library/docs/blob/master/php/README.md#configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

# Expose the port
EXPOSE 8080

La dernière version de Dockerfile est disponible sur cette page.

Pour tester notre application en local, nous devons modifier le fichier config.php de sorte que notre application PHP se connecte à la base de données MySQL disponible sur Google Cloud SQL. En fonction de ce que vous avez configuré auparavant, complétez les informations manquantes :

<?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 correspond à l'adresse IP publique Cloud SQL. Vous pouvez la trouver dans la console SQL :

bd27071bf450a8d0.png

  • DB_NAME doit rester inchangé : image_catalog
  • DB_USER doit être appmod-phpapp-user
  • DB_PASS est une option que vous avez choisie. Configurez-le entre guillemets simples et échappez-le si nécessaire.

N'hésitez pas non plus à traduire en anglais les quelques passages en 🇮🇹 italien avec l'aide de Gemini !

Maintenant que vous avez Dockerfile et que vous avez configuré votre application PHP pour qu'elle se connecte à votre base de données, essayons !

Installez Docker si ce n'est pas déjà fait ( lien). Vous n'en avez pas besoin si vous utilisez Cloud Shell (n'est-ce pas génial ?).

Essayez maintenant de créer et d'exécuter votre application PHP conteneurisée à l'aide des commandes docker build et run appropriées.

# 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 tout fonctionne correctement, vous devriez pouvoir voir la page Web suivante lorsque vous êtes connecté à l'hôte local. Votre application s'exécute désormais sur le port 8080. Cliquez sur l'icône "Aperçu sur le Web" (un navigateur avec un œil), puis sur Prévisualiser sur le port 8080 (ou sur "Modifier le port" pour tout autre port).

33a24673f4550454.png

Tester le résultat dans votre navigateur

Votre application devrait maintenant se présenter comme suit :

2718ece96b1f18b6.png

Si vous vous connectez avec Admin/admin123, vous devriez voir quelque chose comme ceci.

68b62048c2e86aea.png

Super ! À part le texte en italien, tout fonctionne ! 🎉🎉🎉

Si votre dockerisation est correcte, mais que les identifiants de la base de données sont incorrects, vous pouvez obtenir un message comme celui-ci :

e22f45b79bab86e1.png

Réessayez, vous y êtes presque !

Enregistrer dans Artifact Registry [facultatif]

Vous devriez maintenant disposer d'une application PHP conteneurisée fonctionnelle, prête à être déployée dans le cloud. Ensuite, nous avons besoin d'un emplacement dans le cloud pour stocker notre image Docker et la rendre accessible au déploiement sur les services Google Cloud tels que Cloud Run. Cette solution de stockage s'appelle Artifact Registry. Il s'agit d'un service Google Cloud entièrement géré, conçu pour stocker les artefacts d'application, y compris les images de conteneurs Docker, les packages Maven, les modules npm et plus encore.

Créons un dépôt dans Google Cloud Artifact Registry à l'aide du bouton approprié.

e1123f0c924022e6.png

Choisissez un nom valide, le format et la région appropriés pour stocker les artefacts.

4e516ed209c470ee.png

Revenez à votre environnement de développement local, puis ajoutez un tag à l'image de conteneur de l'application et transférez-la vers le dépôt Artifact Registry que vous venez de créer. Pour ce faire, exécutez les commandes suivantes.

  • docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
  • docker push TARGET_IMAGE[:TAG]

Le résultat doit ressembler à la capture d'écran suivante.

1e498feb4e88be9f.png

Félicitations 🎉🎉🎉, vous pouvez passer au niveau suivant. En attendant, passez peut-être deux minutes à essayer d'importer, de vous connecter, de vous déconnecter et de vous familiariser avec les points de terminaison de l'application.Vous en aurez besoin plus tard.

Erreurs possibles

Si vous rencontrez des erreurs de conteneurisation, essayez d'utiliser Gemini pour expliquer et corriger l'erreur, en fournissant :

  • Votre fichier Dockerfile actuel
  • Erreur reçue
  • [si nécessaire] le code PHP en cours d'exécution.

Autorisations d'importation : Essayez également le point de terminaison /upload.php et importez une image. L'erreur ci-dessous peut s'afficher. Si c'est le cas, vous devez effectuer une correction chmod/chown dans Dockerfile.

Avertissement : move_uploaded_file(uploads/image (3).png) : échec de l'ouverture du flux : autorisation refusée dans /var/www/html/upload.php à la ligne 11

PDOException "could not find driver" (ou "Errore di connessione: could not find driver"). Assurez-vous que votre fichier Dockerfile contient les bibliothèques PDO appropriées pour MySQL (pdo_mysql) afin de vous connecter à la base de données. Trouvez l'inspiration dans les solutions ici.

Impossible de transférer votre demande à un backend. Impossible de se connecter à un serveur sur le port 8080. Cela signifie que vous exposez probablement le mauvais port. Assurez-vous d'exposer le port à partir duquel Apache/Nginx diffusent réellement le contenu. Ce n'est pas une mince affaire. Si possible, essayez d'utiliser le port 8080 (cela simplifie l'utilisation de Cloud Run). Si vous souhaitez conserver le port 80 (par exemple, parce qu'Apache le demande), utilisez une autre commande pour l'exécuter :

$ 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. Module 3 : Déployer l'application sur Cloud Run

9ffca42774f6c5d1.png

Pourquoi utiliser Cloud Run ?

Bonne question ! Il y a quelques années, vous auriez certainement choisi Google App Engine.

En d'autres termes, Cloud Run dispose aujourd'hui d'une pile technologique plus récente, est plus facile à déployer, moins cher et effectue un scaling à la baisse jusqu'à zéro instance lorsque vous ne l'utilisez pas. Grâce à sa flexibilité qui lui permet d'exécuter n'importe quel conteneur sans état et à son intégration à divers services Google Cloud, il est idéal pour déployer des microservices et des applications modernes avec un minimum de surcharge et un maximum d'efficacité.

Plus précisément, Cloud Run est une plate-forme entièrement gérée par Google Cloud qui vous permet d'exécuter des applications conteneurisées sans état dans un environnement sans serveur. Elle gère automatiquement toute l'infrastructure, en effectuant un scaling à la hausse à partir de zéro pour répondre au trafic entrant et à la baisse lorsqu'elle est inactive, ce qui la rend économique et efficace. Cloud Run est compatible avec n'importe quel langage ou bibliothèque, à condition qu'il soit empaqueté dans un conteneur, ce qui offre une grande flexibilité de développement. Il s'intègre bien aux autres services Google Cloud et convient à la création de microservices, d'API, de sites Web et d'applications basées sur des événements sans avoir à gérer l'infrastructure de serveur.

Prérequis

Pour effectuer cette tâche, vous devez avoir installé gcloud sur votre machine locale. Si ce n'est pas le cas, consultez les instructions ici. Si vous utilisez Google Cloud Shell, aucune action n'est requise.

Avant de déployer…

Si vous travaillez dans votre environnement local, authentifiez-vous auprès de Google Cloud avec la commande suivante :

  • $ gcloud auth login –update-adc # not needed in Cloud Shell

Vous devriez ainsi être authentifié via une connexion OAuth dans votre navigateur. Assurez-vous de vous connecter à Chrome avec le même utilisateur (par exemple, vattelapesca@gmail.com) que celui connecté à Google Cloud avec la facturation activée.

Activez l'API Cloud Run avec la commande suivante :

  • $ gcloud services enable run.googleapis.com cloudbuild.googleapis.com

À ce stade, tout est prêt pour le déploiement sur Cloud Run.

Déployer votre application sur Cloud Run avec gcloud

La commande qui vous permet de déployer l'application sur Cloud Run est gcloud run deploy. Plusieurs options sont disponibles pour atteindre votre objectif. Voici l'ensemble minimal d'options que vous pouvez fournir via la ligne de commande ou que l'outil vous demandera via une invite interactive :

  1. Nom du service Cloud Run que vous souhaitez déployer pour votre application. Un service Cloud Run vous renverra une URL qui fournit un point de terminaison à votre application.
  2. Région Google Cloud dans laquelle votre application s'exécutera. (--region RÉGION)
  3. Image de conteneur qui encapsule votre application.
  4. Les variables d'environnement dont votre application a besoin pour s'exécuter.
  5. Le flag Allow-Unauthenticated qui permet à tous les utilisateurs d'accéder à votre application sans autre authentification.

Consultez la documentation (ou faites défiler la page vers le bas pour trouver une solution possible) pour savoir comment appliquer cette option à votre ligne de commande.

Le déploiement prendra quelques minutes. Si tout est correct, vous devriez voir quelque chose comme ceci dans la console Google Cloud.

ef1029fb62f8de81.png

f7191d579c21ca3e.png

Cliquez sur l'URL fournie par Cloud Run et testez votre application. Une fois l'authentification effectuée, un résultat semblable à celui-ci devrait s'afficher.

d571a90cd5a373f9.png

"gcloud run deploy" sans arguments

Vous avez peut-être remarqué que gcloud run deploy vous pose les bonnes questions et comble les lacunes que vous avez laissées. C'est incroyable !

Toutefois, dans quelques modules, nous allons ajouter cette commande à un déclencheur Cloud Build. Nous ne pouvons donc pas nous permettre de poser des questions interactives. Nous devons renseigner chaque option de la commande. Vous devez donc créer le gcloud run deploy --option1 blah --foo bar --region your-fav-region d'or. Comment faut-il que vous procédiez ?

  1. Répétez les étapes 2, 3 et 4 jusqu'à ce que gcloud cesse de poser des questions :
  2. [LOOP] gcloud run deploy avec les options trouvées jusqu'à présent
  3. Les systèmes [LOOP] demandent l'option X
  4. [LOOP] Search in public docs how to set up X from CLI adding option --my-option [my-value].
  5. Revenez à l'étape 2, sauf si gcloud se termine sans autre question.
  6. Cette commande gcloud run deploy BLAH BLAH BLAH est géniale ! Enregistrez la commande quelque part, car vous en aurez besoin ultérieurement pour l'étape Cloud Build.

Une solution possible est disponible ici. La documentation est disponible ici.

Félicitations 🎉🎉🎉 Vous avez déployé votre application dans Google Cloud, ce qui constitue la première étape de la modernisation.

6. Module 4 : Nettoyer le mot de passe avec Secret Manager

95cd57b03b4e3c73.png

À l'étape précédente, nous avons pu déployer et exécuter notre application dans Cloud Run. Toutefois, nous l'avons fait en utilisant une mauvaise pratique de sécurité : fournir des secrets en texte brut.

Première itération : mettez à jour votre fichier config.php pour utiliser ENV

Vous avez peut-être remarqué que nous avons inséré le mot de passe de la base de données directement dans le code du fichier config.php. Cela convient pour les tests et pour vérifier si l'application fonctionne. Toutefois, vous ne pouvez pas valider ni utiliser de code de cette manière dans un environnement de production. Le mot de passe (et les autres paramètres de connexion à la base de données) doivent être lus de manière dynamique et fournis à l'application au moment de l'exécution. Modifiez le fichier config.php afin qu'il lise les paramètres de la base de données à partir des variables d'environnement. Si cela ne fonctionne pas, vous devez envisager de définir des valeurs par défaut. Cela peut être utile en cas d'échec du chargement de l'ENV. La sortie de la page vous indiquera alors si elle utilise les valeurs par défaut. Remplissez les espaces vides et remplacez le code dans 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();
?>

Comme votre application est conteneurisée, vous devez trouver un moyen de fournir les variables d'environnement à l'application. Vous pouvez le faire de plusieurs façons :

  • Au moment de la compilation, sur le fichier Dockerfile. Ajoutez les quatre paramètres à votre Dockerfile précédent en utilisant la syntaxe ENV DB_VAR=ENV_VAR_VALUE. Cela définira des valeurs par défaut qui pourront être remplacées lors de l'exécution. Par exemple, "DB_NAME" et "DB_USER" peuvent être définis ici et nulle part ailleurs.
  • Lors de l'exécution. Vous pouvez configurer ces variables pour Cloud Run, à la fois depuis la CLI et depuis l'UI. C'est l'endroit idéal pour placer vos quatre variables (sauf si vous souhaitez conserver les valeurs par défaut définies dans Dockerfile).

Dans localhost, vous pouvez placer vos variables ENV dans un fichier .env (consultez le dossier solutions).

Assurez-vous également que .env est ajouté à votre .gitignore : vous ne voulez pas envoyer vos secrets à GitHub.

echo .env >> .gitignore

Vous pouvez ensuite tester l'instance localement :

docker run -it -p 8080:8080 --env-file .env my-php-app-docker

Vous avez désormais accompli les tâches suivantes :

  1. Votre application lira la variable de manière dynamique à partir de votre environnement
  2. Vous avez amélioré la sécurité en supprimant le mot de passe de la base de données de votre code.)

Vous pouvez désormais déployer une nouvelle révision sur Cloud Run. Passons à l'interface utilisateur et définissons manuellement les variables d'environnement :

  • Accédez à https://console.cloud.google.com/run.
  • Cliquez sur votre application.
  • Cliquez sur "Modifier et déployer une nouvelle révision".
  • Dans le premier onglet "Conteneur(s)", cliquez sur l'onglet inférieur "Variables et secrets".
  • Cliquez sur "+ Ajouter une variable" et ajoutez toutes les variables nécessaires. Vous devriez obtenir un résultat semblable à celui-ci :

7a5fbfa448544d3.png

f2780c35585388ca.png

Est-ce parfait ? Non, votre PASS reste visible pour la plupart des opérateurs. Vous pouvez y remédier avec Google Cloud Secret Manager.

Deuxième itération : Secret Manager

Vos mots de passe ont disparu de votre propre code : victoire ! Mais attendez, sommes-nous en sécurité ?

Vos mots de passe restent visibles par toute personne ayant accès à la console Google Cloud. En fait, si vous accédez au fichier YAML de déploiement Cloud Run, vous pourrez le récupérer. De même, si vous essayez de modifier ou de déployer une révision Cloud Run, le mot de passe est visible dans la section "Variables et secrets", comme illustré dans les captures d'écran ci-dessous.

Google Cloud Secret Manager est un service sécurisé et centralisé permettant de gérer des informations sensibles telles que des clés API, des mots de passe, des certificats et d'autres secrets.

Il vous permet de stocker et de gérer les secrets, et d'y accéder avec des autorisations précises et un chiffrement robuste. Intégré à Identity and Access Management (IAM) de Google Cloud, Secret Manager vous permet de contrôler qui peut accéder à des secrets spécifiques, ce qui garantit la sécurité des données et la conformité réglementaire.

Il est également compatible avec la rotation et la gestion des versions automatiques des secrets, ce qui simplifie la gestion du cycle de vie des secrets et améliore la sécurité des applications dans les services Google Cloud.

Pour accéder à Secret Manager, accédez aux services Sécurité depuis le menu hamburger, puis recherchez-le dans la section Protection des données, comme indiqué dans la capture d'écran ci-dessous.

6df83a1c3cb757f6.png

Une fois sur la page, activez l'API Secret Manager, comme indiqué sur l'image ci-dessous.

a96c312e2c098db1.png

  • Cliquez maintenant sur Créer un secret. Nommons-le de manière rationnelle :
  • Nom : php-amarcord-db-pass
  • Valeur du secret : mot de passe de votre base de données (ignorez la partie "Importer un fichier").
  • annoter ce lien secret, qui devrait ressembler à projects/123456789012/secrets/php-amarcord-db-pass. Il s'agit du pointeur unique vers votre secret (pour Terraform, Cloud Run et d'autres). Il s'agit du numéro unique de votre projet.

Conseil : Essayez d'utiliser des conventions de nommage cohérentes pour vos secrets, en allant de gauche à droite, par exemple : cloud-devrel-phpamarcord-dbpass

  • Organisation (avec l'entreprise)
  • Équipe (dans l'organisation)
  • Application (au sein de l'équipe)
  • Nom de la variable (dans l'application)

Vous pourrez ainsi disposer d'expressions régulières simples pour trouver tous vos secrets pour une seule application.

Créer une révision Cloud Run

Maintenant que nous avons un nouveau secret, nous devons nous débarrasser de la variable d'environnement DB_PASS et la remplacer par le nouveau secret. Exemple :

  • Accès à Cloud Run à l'aide de la console Google Cloud
  • Sélectionnez l'application.
  • Cliquez sur "Modifier et déployer la nouvelle révision".
  • Recherchez l'onglet "Variables et secrets".
  • Utilisez le bouton "+ Référencer un secret" pour réinitialiser la variable d'environnement DB_PASS.
  • Utilisez le même "DB_PASS" pour les secrets référencés et utilisez la dernière version.

9ed4e35be7654dcb.png

Une fois l'opération terminée, vous devriez obtenir l'erreur suivante :

da0ccd7af39b04ed.png

Essayez de trouver comment résoudre le problème. Pour résoudre ce problème, vous devez accéder à la section IAM et administration et modifier les autorisations d'accès. Bon débogage !

Une fois que vous avez trouvé la solution, revenez à Cloud Run et redéployez une révision. Le résultat doit ressembler à la figure suivante :

e89f9ca780169b6b.png

Conseil : L'interface utilisateur de la console Developer est idéale pour identifier les problèmes d'autorisation. Prenez le temps de parcourir tous les liens de vos entités Cloud.

7. Module 5 : Configurer votre CI/CD avec Cloud Build

ba49b033c11be94c.png

Pourquoi utiliser un pipeline CI/CD ?

À ce stade, vous avez probablement tapé gcloud run deploy plusieurs fois, peut-être en répondant à la même question encore et encore.

Vous en avez assez de déployer manuellement votre application avec gcloud run deploy ? Ne serait-il pas formidable que votre application puisse se déployer automatiquement chaque fois que vous envoyez une nouvelle modification à votre dépôt Git ?

Pour utiliser un pipeline CI/CD, vous avez besoin de deux éléments :

  1. Un dépôt Git personnel : heureusement, vous avez déjà dupliqué le dépôt de l'atelier sur votre compte GitHub à l'étape 2. Si ce n'est pas le cas, revenez en arrière et effectuez cette étape. Votre dépôt forké devrait se présenter comme suit : https://github.com/<YOUR_GITHUB_USER>/app-mod-workshop
  2. Cloud Build. Ce service incroyable et bon marché vous permet de configurer des automatisations de compilation pour à peu près tout : Terraform, applications conteneurisées, etc.

Cette section se concentre sur la configuration de Cloud Build.

Découvrez Cloud Build !

Pour ce faire, nous allons utiliser Cloud Build :

  • compiler votre source (avec Dockerfile) ; Considérez-le comme un "gros fichier ZIP" contenant tout ce dont vous avez besoin pour le compiler et l'exécuter (votre "artefact de compilation").
  • transférer cet artefact vers Artifact Registry (AR) ;
  • Déployez ensuite l'application "php-amarcord" d'AR vers Cloud Run.
  • Cela créera une version ("révision") de l'application existante (imaginez une couche avec le nouveau code). Nous la configurerons pour rediriger le trafic vers la nouvelle version si le push réussit.

Voici un exemple de versions pour mon application php-amarcord :

f30f42d4571ad5e2.png

Comment faisons-nous tout cela ?

  1. En créant un fichier YAML parfait : cloudbuild.yaml
  2. en créant un déclencheur Cloud Build ;
  3. En vous connectant à notre dépôt GitHub via l'interface utilisateur Cloud Build.

Créer un déclencheur (et connecter un dépôt)

  • Accédez à https://console.cloud.google.com/cloud-build/triggers.
  • Cliquez sur "Créer un déclencheur".
  • Compiler :
  • Nom : un nom explicite, par exemple on-git-commit-build-php-app
  • Événement : Déployer sur la branche
  • Source : "Associer un nouveau dépôt" texte alternatif
  • Une fenêtre "Connect repository" (Associer le dépôt) s'ouvre sur la droite.
  • Fournisseur de source : "Github" (premier)
  • "Continue"
  • L'authentification ouvre une fenêtre sur GitHub pour l'authentification croisée. Suivez la procédure et soyez patient. Si vous avez de nombreux dépôts, cela peut prendre un certain temps.
  • "Select repo" (Sélectionner le dépôt) : sélectionnez votre compte/dépôt et cochez la case "I understand..." (J'ai compris...).
  • Si vous avez reçu l'erreur "L'application GitHub n'est installée sur aucun de vos dépôts", cliquez sur "Installer Google Cloud Build", puis suivez les instructions.
  • 23e0e0f1219afea3.png Cliquez sur "Connecter".
  • bafd904ec07122d2.png
  • Bravo ! Votre dépôt est désormais connecté.
  • Revenons à la partie "Déclencheur"…
  • Configuration : Détection automatique (*)
  • Avancé : sélectionnez le compte de service "[NUMÉRO_DE_PROJET]- compute@developer.gserviceaccount.com".
  • xxxxx est l'ID de votre projet.
  • Le compte de service Compute par défaut est adapté à une approche de laboratoire. Ne l'utilisez pas en production. ( En savoir plus)
  • Ne modifiez pas les autres paramètres.
  • Cliquez sur le bouton "Créer".

(*) Il s'agit de la méthode la plus simple, car elle recherche un fichier Dockerfile ou cloudbuild.yaml. Toutefois, cloudbuild.yaml vous permet de décider quoi faire à chaque étape.

J'ai la puissance !

À présent, le déclencheur ne fonctionnera pas, sauf si vous accordez le rôle "Utilisateur du compte de service" au compte de service Cloud Build (qu'est-ce qu'un compte de service ? Adresse e-mail d'un "robot" qui agit en votre nom pour une tâche (dans le cas présent, la création d'éléments dans le cloud).

Votre compte de service ne pourra pas être créé ni déployé, sauf si vous l'y autorisez. Heureusement, c'est très simple !

  • Accédez à "Cloud Build" > Paramètres.
  • Compte de service "[PROJECT_NUMBER]- compute@developer.gserviceaccount.com"
  • Cochez les cases suivantes :
  • Cloud Run
  • Secret Manager
  • Comptes de service
  • Cloud Build
  • Cochez également la case "Définir comme compte de service préféré".

8715acca72286a46.png

Où se trouve le fichier YAML Cloud Build ?

Nous vous encourageons vivement à prendre le temps de créer votre propre fichier YAML Cloud Build.

Toutefois, si vous n'avez pas le temps ou si vous ne souhaitez pas en prendre, vous pouvez trouver de l'inspiration dans ce dossier de solutions : .solutions.

Vous pouvez maintenant envoyer une modification à GitHub et observer Cloud Build.

La configuration de Cloud Build peut s'avérer délicate. Vous pouvez vous attendre à des échanges :

  • Vérifier les journaux sur https://console.cloud.google.com/cloud-build/builds;region=global
  • Trouver votre erreur
  • Corrigez le code, puis réexécutez les commandes git commit et git push.
  • Parfois, l'erreur ne se trouve pas dans le code, mais dans une configuration. Dans ce cas, vous pouvez émettre une nouvelle compilation à partir de l'UI (Cloud Build > "Déclencheurs" > Exécuter).

97acd16980a144ab.png

Notez que si vous utilisez cette solution, il reste encore du travail à faire. Par exemple, vous devez définir les variables d'environnement pour les points de terminaison de développement/production nouvellement créés :

3da8723e4ff80c0a.png

Pour cela, vous avez le choix entre deux méthodes :

  • Via l'UI : en définissant à nouveau les variables d'environnement
  • Via la CLI en créant le script "parfait" pour vous. Vous trouverez un exemple ici : gcloud-run-deploy.sh . Vous devez modifier quelques éléments, comme le point de terminaison et le numéro de projet. Vous trouverez le numéro de votre projet dans la présentation de Cloud.

Comment envoyer du code sur GitHub ?

Ce workshop ne vous apprendra pas la meilleure façon de git push sur GitHub. Toutefois, si vous êtes bloqué et que vous utilisez Cloud Shell, vous avez deux options :

  1. CLI. Ajoutez une clé SSH en local et ajoutez un dépôt distant avec git@github.com:YOUR_USER/app-mod-workshop.git (au lieu de http).
  2. VSCode. Si vous utilisez l'éditeur Cloud Shell, vous pouvez utiliser l'onglet "Contrôle du code source" (Ctrl+Maj+G), cliquer sur "Synchroniser les modifications" et suivre les instructions. Vous devriez pouvoir authentifier votre compte GitHub dans VS Code, ce qui vous permettra d'effectuer des extractions et des envois facilement.

f0d53f839c7fa3b6.png

N'oubliez pas d'inclure git add clodubuild.yaml parmi les autres fichiers, sinon cela ne fonctionnera pas.

Parité développement/production "profonde" vs "superficielle" [facultatif]

Si vous avez copié la version du modèle à partir d'ici, vous aurez deux versions DEV et PROD identiques. C'est une bonne chose, car cela correspond à la règle 10 de l'application à 12 facteurs.

Toutefois, nous utilisons deux points de terminaison Web différents pour qu'une application pointe vers la même base de données. Cela suffit pour un atelier. Toutefois, dans la réalité, vous devez prendre le temps de créer un environnement de production approprié. Cela signifie que vous devez disposer de deux bases de données (une pour le développement et une pour la production), et choisir où les héberger pour la reprise après sinistre et la haute disponibilité. Cela dépasse le cadre de cet atelier, mais voici quelques pistes de réflexion.

Si vous avez le temps de créer une version "approfondie" de la production, n'oubliez pas toutes les ressources que vous devez dupliquer, comme :

  • Base de données Cloud SQL (et probablement instance SQL).
  • Bucket GCS
  • Fonction Cloud.
  • Vous pouvez utiliser Gemini 1.5 Flash comme modèle de développement (moins cher, plus rapide) et Gemini 1.5 Pro (plus puissant).

En général, chaque fois que vous effectuez une action dans l'application, réfléchissez de manière critique : la production doit-elle avoir la même valeur ou non ? Si ce n'est pas le cas, redoublez d'efforts. Bien sûr, c'est beaucoup plus facile avec Terraform, où vous pouvez injecter votre environnement (-dev, -prod) en tant que suffixe de vos ressources.

8. Module 6 : Passer à Google Cloud Storage

a680e0f287dd2dfb.png

Stockage

dc3a4b8ea92aaef6.png

Actuellement, l'application stocke l'état dans un conteneur Docker. Si la machine tombe en panne, si l'application plante ou si vous déployez une nouvelle révision, une nouvelle révision sera planifiée avec un nouvel espace de stockage vide : 🙈

Comment résoudre ce problème ? Plusieurs approches sont possibles.

  1. Stocker les images dans la base de données. C'est ce que j'ai fini par faire avec mon ancienne application PHP. C'est la solution la plus simple, car elle ne la complexifie pas. Mais elle ajoute certainement de la latence et de la charge à votre base de données.
  2. Migrer votre application Cloud Run vers une solution de stockage : GCE + disque persistant ? Peut-être GKE + Storage ? Remarque : Plus vous avez de contrôle, moins vous avez d'agilité.
  3. Accédez à GCS. Google Cloud Storage offre le meilleur stockage de sa catégorie pour l'ensemble de Google Cloud. Il s'agit de la solution la plus idiomatique pour le cloud. Toutefois, cela nous oblige à nous salir les mains avec les bibliothèques PHP. Existe-t-il des bibliothèques PHP 5.7 pour GCS ? PHP 5.7 est-il compatible avec Composer (il semble que PHP 5.3.2 soit la version la plus ancienne compatible avec Composer) ?
  4. Peut-être utiliser un side-car Docker ?
  5. Vous pouvez également utiliser les installations de volume Cloud Run de GCS. C'est incroyable.

🤔 Migrer le stockage (question ouverte)

[Open Ended] In this exercise, we want you to find a solution to move your images in a way which is persisted in some way.

Test d'acceptation

Je ne veux pas te donner la solution, mais je veux que cela se produise :

  1. Vous importez newpic.jpg. Vous le verrez dans l'application.
  2. Vous mettez à niveau l'application vers une nouvelle version.
  3. newpic.jpg est toujours là et visible.

💡 Solution possible (montages de volumes Cloud Run GCS)

Il s'agit d'une solution très élégante qui nous permet d'effectuer des importations de fichiers avec état sans toucher au code (à l'exception de l'affichage d'une description d'image, mais c'est trivial et juste pour le plaisir des yeux).

Cela devrait vous permettre de monter un dossier de Cloud Run vers GCS. Par conséquent :

  1. Tous les éléments importés dans GCS seront visibles dans votre application.
  2. Toutes les importations dans votre application seront en fait importées dans GCS.
  3. La magie opère sur les objets importés dans GCS (chapitre 7).

Remarque : Veuillez lire les mentions légales de FUSE. Ce n'est PAS acceptable si les performances sont un problème.

Créer un bucket GCS

GCS est le service de stockage omniprésent de Google Cloud. Il a été testé et est utilisé par tous les services GCP nécessitant du stockage.

Notez que Cloud Shell exporte PROJECT_ID en tant que 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/"

Configurer Cloud Run pour monter le bucket dans le dossier /uploads/

Passons maintenant à la partie élégante. Nous créons un volume php_uploads et demandons à Cloud Run d'effectuer un montage FUSE sur MOUNT_PATH (par exemple, /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"

Répétez cette étape pour tous les points de terminaison que vous souhaitez rediriger vers Cloud Storage.

Vous pouvez également effectuer la même opération depuis l'UI.

  1. Dans l'onglet "Volumes", créez des montages de volume pointant vers votre bucket, de type "Bucket Cloud Storage", par exemple avec le nom "php_uploads".
  2. Sous "Conteneur(s)" > "Montages de volume", installez le volume que vous venez de créer sur le point de volume demandé par votre application. Cela dépend du fichier Dockerfile, mais cela peut ressembler à var/www/html/uploads/ .

Dans les deux cas, si cela fonctionne, la modification de la nouvelle révision Cloud Run devrait vous donner un résultat semblable à celui-ci :

6c2bb98fc1b0e077.png

Testez maintenant la nouvelle application en important une nouvelle image dans le point de terminaison /upload.php.

Les images doivent s'afficher de manière fluide sur GCS sans écrire une seule ligne de code PHP :

70032b216afee2d7.png

Que s'est-il passé ?

Un événement magique s'est produit.

Une ancienne application avec un ancien code fait toujours son travail. Une nouvelle pile modernisée nous permet de stocker confortablement toutes les images/photos de notre application dans un bucket Cloud avec état. Les possibilités sont désormais infinies :

  • Vous souhaitez recevoir un e-mail chaque fois qu'une image contenant du contenu dangereux ou de la nudité est reçue ? Vous pouvez le faire sans toucher au code PHP.
  • Vous souhaitez utiliser un modèle Gemini multimodal chaque fois qu'une image est reçue pour la décrire, puis importer la base de données avec sa description ? Vous pouvez le faire sans toucher au code PHP. Vous ne me croyez pas ? Pour en savoir plus, consultez le chapitre 7.

Nous venons d'ouvrir un vaste champ d'opportunités.

9. Module 7 : Optimiser votre application avec Google Gemini

c00425f0ad83b32c.png

Vous disposez désormais d'une toute nouvelle application PHP moderne (comme une Fiat 126 de 2024) avec un stockage cloudifié.

À quoi sert-il ?

Prérequis

Dans le chapitre précédent, une solution de modèle nous a permis de monter des images /uploads/ sur GCS, séparant de facto la logique de l'application du stockage des images.

Pour cet exercice, vous devez :

  • Avoir réussi l'exercice du chapitre 6 (stockage).
  • Vous disposez d'un bucket GCS contenant les images importées par les utilisateurs de votre application.

Configurer une fonction Cloud (en Python)

Vous êtes-vous déjà demandé comment implémenter une application basée sur les événements ? Par exemple :

  • lorsque <event> se produit => envoyer un e-mail
  • lorsque <event> se produit => si <condition> est vrai, mettez à jour la base de données.

Un événement peut être n'importe quoi : un nouvel enregistrement disponible dans BigQuery, un nouvel objet modifié dans un dossier de GCS ou un nouveau message en attente dans une file d'attente Pub/Sub.

Google Cloud est compatible avec plusieurs paradigmes pour y parvenir. En particulier :

Dans cet exercice, nous allons nous pencher sur Cloud Functions pour obtenir un résultat spectaculaire. Nous vous proposerons également des exercices facultatifs.

Notez que l'exemple de code est fourni sous .solutions/.

Configurer une fonction Cloud (🐍 Python)

Nous essayons de créer un GCF très ambitieux.

  1. Lorsqu'une image est créée sur GCS… (probablement parce que quelqu'un l'a mis en ligne sur l'application, mais pas seulement)
  2. .. appelle Gemini pour le décrire et obtenir une description textuelle de l'image .. (il serait bien de vérifier le type MIME et de s'assurer qu'il s'agit d'une image et non d'un PDF, d'un MP3 ou d'un texte)
  3. .. and update the DB with this description. (cela peut nécessiter de corriger la base de données pour ajouter une colonne description à la table images).

Corrigez la base de données pour ajouter description aux images.

  1. Ouvrez Cloud SQL Studio :

b92b07c4cba658ef.png

  1. Saisissez votre nom d'utilisateur et votre mot de passe pour la base de données Images.
  2. Injectez ce code SQL qui ajoute une colonne pour la description d'une image :

ALTER TABLE images ADD COLUMN description TEXT;

3691aced78a6389.png

Et le tour est joué ! Testez maintenant pour voir si cela a fonctionné :

SELECT * FROM images;

La nouvelle colonne de description devrait s'afficher :

bed69d6ad0263114.png

Écrire la f(x) Gemini

Remarque : Cette fonction a été créée avec l'aide de Gemini Code Assist.

Remarque : La création de cette fonction peut entraîner des erreurs d'autorisation IAM. Certaines sont documentées ci-dessous, dans le paragraphe "Erreurs possibles".

  1. Activer les API
  2. Accédez à https://console.cloud.google.com/functions/list.
  3. Cliquez sur "Create Function" (Créer une fonction).
  4. Activez les API à partir de l'assistant d'API :

d22b82658cfd4c48.png

Vous pouvez créer la fonction Cloud à partir de l'interface utilisateur ou de la ligne de commande. Nous allons utiliser la ligne de commande.

Vous trouverez un code possible sous .solutions/.

  1. Créez un dossier pour héberger votre code, par exemple "gcf/". Accédez au dossier.
  2. Créez un fichier requirements.txt :
google-cloud-storage
google-cloud-aiplatform
pymysql
  1. Créez une fonction Python. Exemple de code : 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
  1. Déployez la fonction. Vous pouvez utiliser un script semblable à gcf/push-to-gcf.sh.

Remarque 1 : Assurez-vous de fournir les variables d'environnement avec les bonnes valeurs ou de les ajouter simplement en haut (GS_BUCKET=blah, …).

Remarque 2 : Cela enverra tout le code local (.). Veillez donc à placer votre code dans un dossier spécifique et à utiliser .gcloudignore comme un pro pour éviter d'envoyer d'énormes bibliothèques. ( exemple).

#!/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

Remarque : Dans cet exemple, generate_caption sera la méthode appelée, et Cloud Functions lui transmettra l'événement GCS avec toutes les informations pertinentes (nom du bucket, nom de l'objet, etc.). Prenez le temps de déboguer ce dictionnaire Python d'événements.

Tester la fonction

Tests unitaires

Cette fonction comporte de nombreux éléments mobiles. Vous pouvez tester tous les composants individuels.

Vous trouverez un exemple dans gcf/test.py.

Interface utilisateur Cloud Functions

Prenez également le temps d'explorer votre fonction dans l'interface utilisateur. Chaque onglet mérite d'être exploré, en particulier Source (mon préféré), Variables, Trigger et Logs. Vous passerez beaucoup de temps dans l'onglet Logs pour résoudre les erreurs (consultez également les erreurs possibles en bas de cette page). Assurez-vous également de consulter Permissions.

cf3ded30d532a2c7.png

Test E2E

Il est temps de tester manuellement la fonction.

  1. Accédez à votre application et connectez-vous.
  2. Importez une image (pas trop grande, car nous avons constaté des problèmes avec les images volumineuses).
  3. Vérifiez dans l'UI que l'image a bien été importée.
  4. Vérifiez dans Cloud SQL Studio que la description a été mise à jour. Connectez-vous et exécutez la requête suivante : SELECT * FROM images.

43a680b12dbbdda0.png

Et il est efficace ! Nous pouvons également mettre à jour l'interface utilisateur pour afficher cette description.

Mettre à jour PHP pour afficher [facultatif]

Nous avons prouvé que l'application fonctionne. Toutefois, il serait intéressant que les utilisateurs puissent également voir cette description.

Nous n'avons pas besoin d'être des experts en PHP pour ajouter la description à index.php. Ce code devrait faire ce qui suit (oui, Gemini l'a écrit pour moi aussi) :

<?php if (!empty($image['description'])): ?>
    <p class="font-bold">Gemini Caption:</p>
    <p class="italic"><?php echo $image['description']; ?></p>
<?php endif; ?>

Positionnez ce code dans foreach comme vous le souhaitez.

Dans les étapes suivantes, nous verrons également une version plus esthétique de l'UI, grâce à Gemini Code Assist. Voici un exemple de version mise en forme :

fdc12de0c88c4464.png

Conclusions

Vous avez déclenché une fonction Cloud sur de nouveaux objets déposés sur GCS, qui est capable d'annoter le contenu de l'image comme un humain pourrait le faire et de mettre à jour automatiquement la base de données. Impressionnant !

Étape suivante Vous pouvez suivre le même raisonnement pour obtenir deux fonctionnalités intéressantes.

[Facultatif] Ajouter d'autres fonctions Cloud Functions [question ouverte]

Quelques fonctionnalités supplémentaires me viennent à l'esprit.

📩 Déclencheur d'e-mail

Un déclencheur d'e-mail qui vous envoie un e-mail chaque fois qu'une personne envoie une photo.

  • Trop souvent ? Ajoutez une autre contrainte : une GRANDE image ou une image dont le contenu Gemini contient les mots "nu/nudité/violent".
  • Pour cela, vérifiez EventArc.

🚫 Modérer automatiquement les photos inappropriées

Actuellement, un administrateur humain signale les images comme "inappropriées". Et si vous laissiez Gemini faire le gros du travail et modérer l'espace ? Ajoutez un test pour signaler le contenu de déclencheur inapproprié et mettre à jour la base de données, comme nous l'avons appris dans la fonction précédente. Cela signifie qu'il faut prendre la fonction précédente, modifier l'invite et mettre à jour la base de données en fonction de la réponse.

Mise en garde L'IA générative produit des résultats imprévisibles. Assurez-vous que le "contenu créé" par Gemini est "guidé". Vous pouvez demander une réponse déterministe, comme un score de confiance compris entre 0 et 1, un JSON, etc. Pour ce faire, vous pouvez utiliser différentes méthodes, par exemple : * Utiliser les bibliothèques Python pydantic, langchain, etc. * Utiliser la sortie structurée de Gemini.

Conseil : Vous pouvez avoir PLUSIEURS fonctions ou une seule invite qui impose une réponse JSON (fonctionne très bien avec "Sortie structurée Gemini" comme indiqué ci-dessus) comme :

Quelle requête faut-il saisir pour générer cette image ?

{
    "description": "This is the picture of an arrosticino",
    "suitable": TRUE
}

Vous pouvez ajouter des champs à la requête pour obtenir des informations supplémentaires, par exemple : y a-t-il quelque chose de bien ? Mauvais ? Reconnaissez-vous cet endroit ? Il y a du texte (l'OCR n'a jamais été aussi simple) :

  • goods : "On dirait un plat délicieux"
  • bads : "On dirait de la nourriture malsaine"
  • OCR : "Da consumare preferibilmente prima del 10 Novembre 2024"
  • location : "Pescara, Lungomare"

Bien qu'il soit généralement préférable d'avoir une fonction N pour N résultats, il est incroyablement gratifiant d'en créer une qui fait 10 choses. Pour savoir comment procéder, consultez cet article de Riccardo.

Erreurs possibles (principalement liées à IAM / aux autorisations)

La première fois que j'ai développé cette solution, j'ai rencontré des problèmes d'autorisations IAM. Je vais les ajouter ici pour faire preuve d'empathie et vous donner quelques idées pour les résoudre.

Erreur : autorisations insuffisantes pour le compte de service

  1. Notez que pour déployer une fonction GCF qui écoute un bucket GCS, vous devez configurer les autorisations appropriées pour le compte de service que vous utilisez pour le job, comme indiqué dans la figure :

22f51012fa6b4a24.png

Vous devrez peut-être aussi activer les API Eventarc quelques minutes avant qu'elles ne soient entièrement disponibles.

Erreur : Demandeur Cloud Run manquant

  1. Voici un autre commentaire de l'UI pour l'autorisation GCF ( rôle Demandeur Cloud Run) :

be72e17294f2d3f3.png

Pour corriger cette erreur, exécutez la commande dans l'image, qui est semblable à fix-permissions.sh.

Ce problème est décrit sur la page https://cloud.google.com/functions/docs/securing/authenticating.

Erreur : Limite de mémoire dépassée

La première fois que je l'ai exécuté, mes journaux ont pu indiquer : "‘Limite de mémoire de 244 Mio dépassée avec 270 Mio utilisés. Envisagez d'augmenter la limite de mémoire. Pour en savoir plus, consultez https://cloud.google.com/functions/docs/configuring/memory. Ajoutez à nouveau de la RAM à votre GCF. C'est très facile à faire dans l'UI. Voici un exemple de bump :

bed69d6ad0263114.png

Vous pouvez également corriger votre script de déploiement Cloud Run pour augmenter la mémoire et le processeur. Cette opération prend un peu plus de temps.

Erreur : Pub/Sub publié

La création d'un déclencheur avec GCF v1 a généré une fois cette erreur :

e5c338ee35ad4c24.png

Là encore, il est facile de résoudre ce problème en accédant à IAM et en attribuant le rôle "Éditeur Pub/Sub" à votre compte de service.

Erreur : Vertex AI n'a pas été utilisé

Si vous recevez ce message d'erreur :

Autorisation refusée : 403 L'API Vertex AI n'a jamais été utilisée dans le projet YOUR_PROJECT ou a été désactivée. Accédez à https://console.developers.google.com/apis/api/aiplatform.googleapis.com/overview?project=YOR_PROJECT pour l'activer.

Il vous suffit d'activer les API Vertex AI. Voici le moyen le plus simple d'activer TOUTES les API nécessaires :

  1. https://console.cloud.google.com/vertex-ai
  2. Cliquez sur "Activer toutes les API recommandées".

492f05ac377f3630.png

Erreur : Déclencheur EventArc introuvable.

Si vous obtenez ce message, veuillez redéployer la fonction.

8ec4fc11833d7420.png

Erreur 400 : des agents de service sont en cours de provisionnement

400 Service agents are being provisioned ( https://cloud.google.com/vertex-ai/docs/general/access-control#service-agents ). Service agents are needed to read the Cloud Storage file provided. Veuillez réessayer dans quelques minutes.

Si cela se produit, patientez ou demandez à un employé Google.

10. Module 8 : Créer des SLO de disponibilité

Dans ce chapitre, nous allons essayer d'atteindre les objectifs suivants :

  1. Créer des SLI
  2. Créer des SLO basés sur les SLI
  3. Créer des alertes basées sur les SLO

f63426182c052123.png

Il s'agit d'un sujet très important pour l'auteur, car Riccardo travaille dans le domaine SRE / DevOps de Google Cloud.

(question ouverte) Crée des SLI et des SLO pour cette application.

À quoi sert une application si vous ne pouvez pas savoir quand elle est hors service ?

Qu'est-ce qu'un SLO ?

Oh mon Dieu ! Google a inventé les SLO. Pour en savoir plus, je vous suggère de consulter les ressources suivantes :

Étape 1 : Créez un SLI/SLO de disponibilité

Commençons par le SLO de disponibilité, car il s'agit de la mesure la plus simple et peut-être la plus importante.

Heureusement, Cloud Run est fourni avec une assistance SLO prédéfinie grâce à Istio.

Une fois votre application sur Cloud Run, c'est très simple à faire, cela me prend 30 secondes.

  • Accédez à votre page Cloud Run.
  • Cliquez/sélectionnez votre application.
  • Sélectionnez l'onglet SLOs.
  • Cliquez sur "+ Créer un SLO".
  • Disponibilité, sur demande
  • Continuer
  • Mois calendaire / 99 %.
  • cliquez sur "Créer un SLO".

e471c7ebdc56cdf6.png

Étape 2 : Configurez les alertes pour ce SLO

Je vous suggère de créer deux alertes :

  1. Un avec un taux de combustion faible ("Slowburn") pour vous alerter par e-mail (simule un ticket de priorité basse).
  2. Une alerte avec un taux de combustion élevé ("Fastburn") pour vous avertir par SMS (simule un ticket / bip de priorité élevée)

Accédez à votre SLO tab précédent.

Répétez cette opération deux fois :

314bfd6b9ef0a260.png

  • Cliquez sur "Créer une alerte de SLO" (l'icône 🔔 avec un signe plus à l'intérieur, à droite).
  • Durée de l'analyse, seuil du budget dépensé :
  • [RAPIDE]. Première : 60 min / 10x
  • [LENT]. Seconde : 720 min / 2 x
  • Canal de notification : cliquez sur "Gérer les canaux de notification".
  • Tout d'abord, "E-mail" > Ajouter > …
  • Ensuite, "SMS" > Ajouter > Valider sur le téléphone.
  • Conseil : J'aime utiliser des emoji dans les noms ! C'est amusant pour les démonstrations.
  • Lorsque vous avez terminé, cliquez sur le grand X en haut à droite.
  • Sélectionnez d'abord le téléphone (rapide), puis l'adresse e-mail (lent).
  • Ajoutez des exemples de documentation, comme :
  • [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.

Bravo !

Résultat final

Nous pouvons considérer cet exercice comme terminé une fois que vous avez un SLO fonctionnel et deux alertes pour votre disponibilité, et que vous recevez des alertes par e-mail et sur votre téléphone.

Si vous le souhaitez, vous pouvez ajouter une latence (je vous encourage vivement à le faire) ou même une latence plus complexe. Pour la latence, choisissez une valeur que vous jugez raisonnable. En cas de doute, sélectionnez 200 ms.

11. Étapes suivantes

Vous avez tout terminé. Qu'est-ce qui manque ?

Voici quelques points à prendre en compte :

Jouer avec Gemini

Vous pouvez utiliser Gemini de deux manières :

  1. Vertex AI. La "méthode Enterprise", étroitement liée à votre GCP, que nous avons explorée au chapitre 7 (GCF+Gemini). Toute l'authentification fonctionne comme par magie et les services s'interconnectent de manière fluide.
  2. IA de Google. La "méthode consommateur". Obtenez une clé API Gemini sur cette page et commencez à créer de petits scripts qui peuvent être associés à n'importe quelle charge de travail que vous possédez déjà (travail propriétaire, autres clouds, localhost, etc.). Il vous suffit de remplacer votre clé API pour que le code commence à fonctionner comme par magie.

Nous vous encourageons à essayer d'explorer le (2) avec vos propres projets personnels.

UI Lifting

Je ne suis pas très doué pour les interfaces utilisateur. Mais Gemini, oui ! Vous pouvez simplement prendre une seule page PHP et dire quelque chose comme :

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!]

Vous pouvez l'obtenir facilement en moins de cinq minutes avec Cloud Build. :)

La réponse de Gemini était parfaite (je n'ai rien eu à modifier) :

8a3d5fe37ec40bf8.png

Voici la nouvelle mise en page dans l'application personnelle de l'auteur :

81620eb90ae3229a.png

Remarque : Le code est collé sous forme d'image, car nous ne voulons pas vous encourager à le prendre, mais à demander à Gemini de l'écrire pour vous, en tenant compte de vos propres contraintes créatives d'UI/de frontend. Croyez-moi, vous n'aurez que de très petites modifications à apporter par la suite.

Sécurité

La sécurisation appropriée de cette application n'est pas un objectif de cet atelier de quatre heures, car cela augmenterait le temps nécessaire pour le terminer d'un à deux ordres de grandeur.

Cependant, ce sujet est extrêmement important. Nous avons rassemblé quelques idées dans SECURITY.

12. Félicitations !

Félicitations 🎉🎉🎉 , vous avez réussi à moderniser votre ancienne application PHP avec Google Cloud.

24cb9a39b1841fbd.png

En résumé, voici ce que vous avez appris dans cet atelier de programmation :

  • Découvrez comment déployer une base de données dans Google Cloud SQL et comment y migrer votre base de données existante.
  • Conteneuriser votre application PHP avec Docker et Buildpacks, et stocker son image dans Google Cloud Artifact Registry
  • Déployer votre application conteneurisée sur Cloud Run et l'exécuter avec Cloud SQL
  • Stocker/utiliser secrètement des paramètres de configuration sensibles (tels que le mot de passe de la base de données) à l'aide de Google Secret Manager
  • Découvrez comment configurer votre pipeline CI/CD avec Google Cloud Build pour compiler et déployer automatiquement votre application PHP chaque fois que vous envoyez du code vers votre dépôt GitHub.
  • Utiliser Cloud Storage pour "cloudifier" les ressources de votre application
  • Découvrez comment exploiter les technologies sans serveur pour créer des workflows incroyables sur Google Cloud sans toucher au code de votre application.
  • Utilisez les capacités multimodales de Gemini pour un cas d'utilisation approprié.
  • Implémenter les principes SRE dans Google Cloud

C'est un excellent point de départ pour votre parcours de modernisation des applications avec Google Cloud.

🔁 Commentaires

Si vous souhaitez nous faire part de votre expérience avec cet atelier, pensez à remplir ce formulaire de commentaires.

Nous apprécions vos commentaires et vos demandes d'extraction pour les extraits de code dont vous êtes particulièrement fier.

🙏 Merci

L'auteur tient à remercier Mirko Gilioli et Maurizio Ipsale de Datatonic pour leur aide dans la rédaction et les tests de la solution.