À propos de cet atelier de programmation
1. Présentation
Dans cet atelier de programmation, vous allez créer un service Cloud Run, le service de montage, qui sera déclenché par Cloud Scheduler à intervalles réguliers. Le service récupère les dernières photos importées et crée un montage à partir de celles-ci: il recherche la liste des images récentes dans Cloud Firestore, puis télécharge les fichiers image à partir de Cloud Storage.
Points abordés
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. Préparation
Configuration de l'environnement au rythme de chacun
- Connectez-vous à la console Google Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)
- Le nom du projet est le nom à afficher pour les participants au projet. Il s'agit d'une chaîne de caractères qui n'est pas utilisée par les API Google, et que vous pouvez modifier à tout moment.
- L'ID du projet doit être unique sur l'ensemble des projets Google Cloud et doit être immuable (vous ne pouvez pas le modifier une fois que vous l'avez défini). Cloud Console génère automatiquement une chaîne unique dont la composition importe peu, en général. Dans la plupart des ateliers de programmation, vous devrez référencer l'ID du projet (généralement identifié comme
PROJECT_ID
), donc s'il ne vous convient pas, générez-en un autre au hasard ou définissez le vôtre, puis vérifiez s'il est disponible. Il est ensuite "gelé" une fois le projet créé. - La troisième valeur est le numéro de projet, utilisé par certaines API. Pour en savoir plus sur ces trois valeurs, consultez la documentation.
- Vous devez ensuite activer la facturation dans Cloud Console afin d'utiliser les ressources/API Cloud. L'exécution de cet atelier de programmation est très peu coûteuse, voire sans frais. Pour arrêter les ressources afin d'éviter qu'elles ne vous soient facturées après ce tutoriel, suivez les instructions de nettoyage indiquées à la fin de l'atelier. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai gratuit pour bénéficier d'un crédit de 300 $.
Démarrer Cloud Shell
Bien que Google Cloud puisse être utilisé à distance depuis votre ordinateur portable, nous allons nous servir de Google Cloud Shell pour cet atelier de programmation, un environnement de ligne de commande exécuté dans le cloud.
Depuis la console GCP, cliquez sur l'icône Cloud Shell de la barre d'outils située dans l'angle supérieur droit :
Le provisionnement et la connexion à l'environnement prennent quelques instants seulement. Une fois l'opération terminée, le résultat devrait ressembler à ceci :
Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez réaliser toutes les activités de cet atelier dans un simple navigateur.
3. Activer les API
Vous aurez besoin de Cloud Scheduler pour déclencher le service Cloud Run à intervalles réguliers. Assurez-vous qu'elle est activée:
gcloud services enable cloudscheduler.googleapis.com
L'opération doit s'afficher pour se terminer correctement:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
4. Cloner le code
Clonez le code (si vous ne l'avez pas déjà fait dans l'atelier de programmation précédent) :
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
Vous pouvez ensuite accéder au répertoire contenant le service:
cd serverless-photosharing-workshop/services/collage/nodejs
La mise en page des fichiers du service est la suivante:
services | ├── collage | ├── nodejs | ├── Dockerfile ├── index.js ├── package.json
Dans le dossier, vous avez trois fichiers:
index.js
contient le code Node.jspackage.json
définit les dépendances de la bibliothèque.Dockerfile
définit l'image de conteneur.
5. Explorer le code
Dépendances
Le fichier package.json
définit les dépendances de bibliothèque nécessaires:
{
"name": "collage_service",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"bluebird": "^3.7.2",
"express": "^4.17.1",
"imagemagick": "^0.1.3",
"@google-cloud/firestore": "^4.9.9",
"@google-cloud/storage": "^5.8.3"
}
}
Nous dépendons de la bibliothèque Cloud Storage pour lire et enregistrer des fichiers image dans Cloud Storage. Nous déclarons une dépendance à Cloud Firestore pour récupérer les métadonnées d'image que nous avons stockées précédemment. Express est un framework Web JavaScript / Node. Bluebird est utilisé pour traiter les promesses, et imagemagick est une bibliothèque dédiée à la manipulation des images.
Dockerfile
Dockerfile
définit l'image de conteneur pour l'application:
FROM node:14-slim
# installing Imagemagick
RUN set -ex; \
apt-get -y update; \
apt-get -y install imagemagick; \
rm -rf /var/lib/apt/lists/*
WORKDIR /picadaily/services/collage
COPY package*.json ./
RUN npm install --production
COPY . .
CMD [ "npm", "start" ]
Nous utilisons une image de base légère de base Node 14. Nous installons la bibliothèque imagemagick. Ensuite, nous installons les modules NPM nécessaires à notre code, et nous exécutons le code de notre nœud avec npm start.
index.js
Examinons de plus près notre code index.js
:
const express = require('express');
const imageMagick = require('imagemagick');
const Promise = require("bluebird");
const path = require('path');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
Nous avons besoin des différentes dépendances nécessaires à l'exécution de notre programme: Express est le framework Web Node que nous allons utiliser, ImageMagick pour la manipulation des images, Bluebird est une bibliothèque permettant de gérer les promesses JavaScript, Path est utilisé pour traiter les chemins de fichiers et de répertoires, tandis que Storage et Firestore sont utilisés respectivement avec Google Cloud Storage (nos buckets d'images) et le datastore Cloud Firestore.
const app = express();
app.get('/', async (req, res) => {
try {
console.log('Collage request');
/* ... */
} catch (err) {
console.log(`Error: creating the collage: ${err}`);
console.error(err);
res.status(500).send(err);
}
});
Ci-dessus, nous avons la structure de notre gestionnaire de nœuds: notre application répond aux requêtes HTTP GET. Et nous faisons un peu de gestion des erreurs au cas où quelque chose ne fonctionnerait pas. Voyons maintenant le contenu de cette structure.
const thumbnailFiles = [];
const pictureStore = new Firestore().collection('pictures');
const snapshot = await pictureStore
.where('thumbnail', '==', true)
.orderBy('created', 'desc')
.limit(4).get();
if (snapshot.empty) {
console.log('Empty collection, no collage to make');
res.status(204).send("No collage created.");
} else {
/* ... */
}
Notre service de montage nécessite au moins quatre photos (dont les vignettes ont été générées). Assurez-vous donc d'importer quatre images au préalable.
Nous récupérons les quatre dernières photos importées par nos utilisateurs à partir des métadonnées stockées dans Cloud Firerstore. Nous vérifions si la collection obtenue est vide ou non, puis nous poursuivons dans la branche "else" de notre code.
Collectons la liste des noms de fichiers:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
Nous allons télécharger chacun de ces fichiers à partir du bucket de vignettes, dont le nom provient d'une variable d'environnement que nous avons définie au moment du déploiement:
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);
await Promise.all(thumbnailFiles.map(async fileName => {
const filePath = path.resolve('/tmp', fileName);
await thumbBucket.file(fileName).download({
destination: filePath
});
}));
console.log('Downloaded all thumbnails');
Une fois les dernières vignettes importées, nous allons utiliser la bibliothèque ImageMagick pour créer une grille 4x4 de ces vignettes. Nous utilisons la bibliothèque Bluebird et son implémentation de Promise pour transformer le code basé sur le rappel en code convivial async
/ await
, puis nous attendons la promesse de réaliser le montage d'images:
const collagePath = path.resolve('/tmp', 'collage.png');
const thumbnailPaths = thumbnailFiles.map(f => path.resolve('/tmp', f));
const convert = Promise.promisify(im.convert);
await convert([
'(', ...thumbnailPaths.slice(0, 2), '+append', ')',
'(', ...thumbnailPaths.slice(2), '+append', ')',
'-size', '400x400', 'xc:none', '-background', 'none', '-append',
collagePath]);
console.log("Created local collage picture");
Comme l'image du montage a été enregistrée localement sur le disque dans le dossier temporaire, nous devons maintenant l'importer dans Cloud Storage, puis renvoyer une réponse réussie (code d'état 2xx):
await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");
res.status(204).send("Collage created.");
Il est maintenant temps de faire en sorte que notre script Node écoute les requêtes entrantes:
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started collage service on port ${PORT}`);
});
À la fin de notre fichier source, nous avons les instructions pour qu'Express démarre notre application Web sur le port 8080 par défaut.
6. Tester en local
Testez le code localement pour vous assurer qu'il fonctionne avant de le déployer dans le cloud.
Dans le dossier collage/nodejs
, installez les dépendances npm et démarrez le serveur:
npm install; npm start
Si tout s'est déroulé comme prévu, le serveur doit démarrer sur le port 8080:
Started collage service on port 8080
Appuyez sur CTRL-C
pour quitter.
7. Compiler et déployer sur Cloud Run
Avant le déploiement sur Cloud Run, définissez la région Cloud Run sur l'une des régions et la plate-forme compatibles sur managed
:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
Vous pouvez vérifier que la configuration est définie:
gcloud config list ... [run] platform = managed region = europe-west1
Au lieu de créer et de publier l'image de conteneur manuellement à l'aide de Cloud Build, vous pouvez également compter sur Cloud Run pour créer l'image de conteneur pour vous à l'aide des packs de création Google Cloud.
Exécutez la commande suivante pour créer l'image de conteneur:
BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT SERVICE_NAME=collage-service gcloud run deploy $SERVICE_NAME \ --source . \ --no-allow-unauthenticated \ --update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS
Notez l'indicateur –-source
. Il s'agit du déploiement basé sur la source dans Cloud Run. Si un Dockerfile
est présent dans le répertoire du code source, le code source importé est créé à l'aide de ce Dockerfile
. Si aucun Dockerfile
n'est présent dans le répertoire du code source, les buildpacks Google Cloud détectent automatiquement le langage que vous utilisez et récupèrent les dépendances du code afin de créer une image de conteneur prête pour la production, à l'aide d'une image de base sécurisée gérée par Google. Cela indique à Cloud Run d'utiliser des Buildpacks Google Cloud pour créer l'image de conteneur définie dans Dockerfile
.
Notez également que le déploiement basé sur la source utilise Artifact Registry pour stocker les conteneurs créés. Artifact Registry est une version moderne de Google Container Registry. La CLI vous invitera à activer l'API si elle n'est pas déjà activée dans le projet, et créera un dépôt nommé cloud-run-source-deploy
dans la région vers laquelle vous effectuez le déploiement.
L'option --no-allow-unauthenticated
fait du service Cloud Run un service interne qui ne sera déclenché que par des comptes de service spécifiques.
8. Configurer Cloud Scheduler
Maintenant que le service Cloud Run est prêt et déployé, il est temps de créer la programmation standard pour appeler le service toutes les minutes.
Créez un compte de service :
SERVICE_ACCOUNT=collage-scheduler-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Collage Scheduler Service Account"
Autorisez le compte de service à appeler le service Cloud Run:
gcloud run services add-iam-policy-binding $SERVICE_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --role=roles/run.invoker
Créez un job Cloud Scheduler à exécuter toutes les minutes:
SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --format 'value(status.url)') gcloud scheduler jobs create http $SERVICE_NAME-job --schedule "* * * * *" \ --http-method=GET \ --location=europe-west1 \ --uri=$SERVICE_URL \ --oidc-service-account-email=$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --oidc-token-audience=$SERVICE_URL
Vous pouvez accéder à la section Cloud Scheduler de Cloud Console pour vérifier qu'il est configuré et qu'il pointe vers l'URL du service Cloud Run:
9. Tester le service
Pour vérifier que la configuration fonctionne, recherchez l'image du montage (appelée collage.png
) dans le bucket thumbnails
. Vous pouvez également consulter les journaux du service:
10. Nettoyer (facultatif)
Si vous n'avez pas l'intention de suivre les autres ateliers de la série, vous pouvez nettoyer les ressources pour réduire les coûts et utiliser globalement le cloud comme il se doit. Vous pouvez nettoyer les ressources individuellement comme suit.
Supprimez le service :
gcloud run services delete $SERVICE_NAME -q
Supprimez le job Cloud Scheduler:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
Vous pouvez également supprimer l'intégralité du projet:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. Félicitations !
Félicitations ! Vous avez créé un service planifié: grâce à Cloud Scheduler, qui envoie un message toutes les minutes sur un sujet Pub/Sub, votre service de montage Cloud Run est appelé et peut ajouter des images les unes aux autres pour créer l'image qui en résulte.
Points abordés
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore