Gatling – Test de charge et cloudification

Dans le cadre du développement de l’application FastContest et de son déploiement dans le cloud d’Amazon avec Cloudify, nous avons souhaité effectuer des tests de charge automatisés afin :

  • d’évaluer la charge maximale que notre application pouvait soutenir
  • de dimensionner les machines du Cloud sur lesquelles nous déployons
  • de mettre en exergue les faiblesses de notre application
  • de jouer des scénarios définis automatiquement avec plusieurs centaines de joueurs concourants et ainsi de vérifier la bonne intégrité des données à l’issue

Nous avons choisi d’utiliser Gatling, un outil de test de charge open-source, qui permet d’écrire les scénarios de test sous forme de codes élégants et concis.

Arborescence de Gatling

Le dossier d’installation de Gatling est organisé selon l’arborescence suivante :

  • /results : Contient les résultats des benchs sous format web
  • /bin : Contient les scripts permettant de lancer Gatling
  • /target : Contient les fichiers issus de la compilation de nos scénarios + cache
  • /conf : Contient les fichiers de configuration (niveau de log…)
  • /user-files : Contient les fichiers .scala de définition des scénarios
  • /lib : jar de gatling

Des scénarios implémentés en Scala

À la différence de JMeter qui dispose d’une interface graphique pour la définition des scénarios de simulation et de ses paramètres, Gatling propose une API écrite en Scala. Contre-intuitivement, il est assez élégant et aisé de définir des scénarios en Scala plutôt que via une interface graphique, surtout qu’il n’est pas nécessaire d’être un ninja en Scala pour réaliser ses premiers scénarios. Gatling propose une multitude de fonctionnalités dont les basiques seront présentées plus loin.
La documentation complète est disponible à ce lien.
Les scénarios sont placés dans le dossier /user-files/simulations. Voici, typiquement, un scénario implémenté en Scala :

val scn = scenario("User play")
  .feed(myCustomFeeder)
  .exec(
     http("register")
      .post("/user/register")
      .param("email", "${email}")
      .param("password", "${password}")
      .param("pseudo", "${pseudo}")
      .headers(headers_1)
      .check(status.is(200)))
  .pause(0 milliseconds, 100 milliseconds)
  .repeat(10) {
    feed(csv("question_answer.csv").circular)
      .exec(
        http("answer")
         .post("/response")
         .param("questionId", "${questionId}")
         .param("answerId", "${answerId}")
         .headers(headers_1))
      .pause(0,5)
  }

Dans ce cas, Gatling va effectuer une requête post /user/register avec les paramètres email et password (défini dans un fichier séparé), et vérifiera que la réponse a bien un status 200. Enfin, après une pause de 0 à 100 ms, Gatling effectue 10 requêtes /response avec une pause de 0 à 5 sec entre chaque. Les paramètres sont fournis par un « feeder » qui permet de factoriser des variables au sein d’un fichier CSV par exemple (pour plus d’infos, suivez le lien)
Pour apprendre à écrire un scénario avec Gatling, il y a le tutorial officiel.

Exécution de bench

Pour lancer un scénario il suffit d’exécuter le script gatling.sh ou .bat selon l’environnement qui se trouve dans le dossier /bin. Gatling va compiler automatiquement les classes Scala puis vous demande de choisir le scénario à exécuter. À l’issue de la simulation, un rapport web est généré automatiquement à partir du fichier de log. Il contient toutes les métriques mises en forme de façon graphique grâce à la librairie Javascript HighChart.

Un exemple de rapport :

Cloudification

Afin d’effectuer des tests de charges proches des conditions réelles nous avons cloudifié Gatling en automatisant son installation et son exécution sur les VM d’Amazon.
Grâce à Cloudify, nous pouvons désormais lancer les tests de charge à partir d’Internet et sur autant de machine que nous voulons. Les recipes sont relativement simples puisqu’il s’agit essentiellement de télécharger et de dézipper le dossier d’installation de Gatling. Les scénarios sont uploadés avec la recipe, ils doivent donc être déplacés dans le répertoire /simulation de Gatling.
L’exécution du bench s’effectue grâce à une custom command « executeBench » dont le premier paramètre est le nom du scenario à exécuter et le second, le nom que l’on donne à cette simulation. La custom command lance alors le test de charge pour toutes les instances de Gatling sur chaque VM. Les rapports sont donc générés individuellement sur chaque VM.

Pour obtenir un rapport unique, on pourrait scripter la récupération de tous les résultats générés, leur fusion et la regénération d’un nouveau rapport global.
Le rapport est ensuite poussé sur S3 soit automatiquement, soit via une custom command (pushResult).

À travers ce use-case de Cloudify, nous montrons, une fois encore, sa simplicité et sa commodité d’utilisation en automatisant complètement la chaîne : déploiement, installation et exécution de tests de charge à partir du Cloud Amazon EC2.

Conclusion

L’un des avantages le plus important de Gatling est sans conteste sa capacité à générer des rapports graphiques de qualité à l’issue de chaque simulation. De cette façon, le testeur a immédiatement accès aux résultats de manière visuelle, sans post-traitement supplémentaire.
De plus, l’écriture des scénarios de test de façon fonctionnelle en Scala peut faciliter la lisibilité du test. Surtout grâce aux feeders qui permettent de factoriser les paramètres dans des fichiers à part.

Enfin, le lancement des tests via des simples commandes de script rend sa cloudification aisée.

Créer rapidement un prototype d’application HTML5 pour téléphones portable avec Sencha Touch.

Sencha Touch est un framework Javascript. Il dispose d’une bibliothèque riche pour mettre en place rapidement une application HTML5 orienté Single Page Application.

Nous avons utilisé Sencha Touch pour développer rapidement notre jeux de quizz pour le Devoxx France 2013. Il s’agissait d’expérimenter ce framework dans le cadre d’un développement court et au budget limité. Sencha répond à cette problématique en produisant des applications HTML5 utilisables sur une grande majorité des téléphones du marché sans développement spécifique pour chaque plateforme (mis à part un design spécifique pour les tablettes).

FastContestSenchaTouch

Points positifs :

Points négatifs :

  • fort couplage (l’application créée ne pourra se défaire de Sencha)
  • documentation pas très à jour
  • forte dépendance à webkit ( => ne supporte pas Firefox, Opera, IE ainsi que de nombreux autres navigateurs)

Installer Sencha

Pour développer une application HTML5 en utilisant Sencha, il est nécessaire de télécharger l’API Sencha Touch ainsi que l’application Sencha Cmd. Le premier permet à l’application de fonctionner tandis que le second permet de créer l’archétype de l’application et de fabriquer le paquet que l’on mettra en production (ne copier que les bibliothèques Sencha effectivement utilisées, minification du Javascript, …)

API Sencha

  1. Télécharger Sencha Touch (http://www.sencha.com/products/touch/download/)
  2. Dézipper et placer dans un serveur Apache (pour éviter les problèmes de Cross Domain, sinon lancer un navigateur en désactivant la sécurité pour tester votre application en développement).

Sencha Cmd

  1. Télécharger Sencha Cmd (http://www.sencha.com/products/sencha-cmd/download)
  2. Installer (répertoire par défaut : ~/bin/Sencha)

Créer une application de type HelloWorld

Plutôt que de présenter l’application utilisée lors du Devoxx, on commencera par mettre au point une simple application.

Pour générer l’archétype de l’application, il faut créer un dossier portant le nom de l’application (ex : myapp) et lancer la commande idoine :

~\Desktop\blog\touch-2.1.1>mkdir myapp
~\Desktop\blog\touch-2.1.1>cd myapp
~\Desktop\blog\touch-2.1.1\myapp>sencha generate app myapp ../myapp

Maintenant le dossier « myapp » contient un projet Sencha. Quelques explications sur les ressources créés :

  • le fichier app.js est le point d’entrée de l’application
  • le dossier app contient les différentes classes javascript du projet,
  • le dossier ressources contient les éléments externes (icones, libs…)
  • le dossier touch contient un sous-ensemble de l’API

Développer

Nous vous proposons maintenant de créer une application Sencha. Plutôt que de vous donner le code de notre jeux de quizz, nous allons créer une application plus simple qui permet de lister des pizzas et de voir leurs ingrédients.

Sencha repose sur un framework MVC et il propose des classes que l’on peut étendre : Ext.data.Model, Ext.dataview.List, Ext.Panel, …

Nous allons débuter par décrire le modèle de donnée : ici nos pizzas et leurs ingrédients. Une relation « One to Many » relient les pizzas à leurs ingrédients, sachant qu’un ingrédient ne peut se trouver plus d ‘une fois dans une pizza.

myapp/app/model/ingredient.js

Ext.define('myapp.model.Ingredient', {
  extend: 'Ext.data.Model',
  config: {
    fields: [
     {name: 'name'}
    ]
  }
});

myapp/app/model/pizza.js

Ext.define('myapp.model.Pizza', {
  extend: 'Ext.data.Model',
  uses: ['myapp.model.Ingredient'],
  config: {
    fields: [
      {name: 'name'}
    ],
    hasMany: {
      model: 'myapp.model.Ingredient',
      name: 'ingredients'
    }
  }
});

Nous allons maintenant implémenter un store de pizzas. Un store permet de gérer les données, de lire ou de sauvegarder depuis une source locale (json, xml) ou distante (ajax, jsonp, …). Dans notre cas, on lira des données directement écrites dans le code.

myapp/app/store/menu.js

Ext.define('myapp.store.Menu', {
  extend: 'Ext.data.Store',
  requires: ['myapp.model.Pizza'],
  config: {
    model: 'myapp.model.Pizza',
    storeId: 'Menu',
    autoLoad: true,
    data: [
      {
        name: 'marguerita',
        ingredients:[
          {name: 'Tomato'},
          {name: 'Cheese'},
          {name: 'Olives'}
        ]
      }
    ]
  }
});

Les vues de l’application sont la liste des pizzas et une fenêtre qui s’ouvre lors de la sélection d’une pizza pour afficher les ingrédients

myapp/app/view/MenuList.js

Ext.define('myapp.view.MenuList', {
  extend: 'Ext.dataview.List',
  requires: ['myapp.store.Menu'],
  origin: 'menu', //custom identifier for the controller pizzaiolo
  config: {
    store: 'Menu',
    itemTpl: [
      '<div>{name}</div>'
    ]
  }
});

myapp/app/view/ingredientsListOverlay.js

Ext.define('myapp.view.IngredientsListOverlay', {
  extend: 'Ext.Panel',
  alias: 'widget.ingredientsListOverlay',
  config: {
    centered: true,
    height: 200,
    width: 200,
    modal: true,
    items: [
      {html: '<h3>Ingredients</h3>',styleHtmlContent: true}
    ]
  }
});

Nous allons maintenant implémenter un contrôleur qui gèrera l’affichage de la liste d’ingrédients quand une pizza est sélectionnée.

myapp/app/controller/pizzaiolo.js

Ext.define('myapp.controller.Pizzaiolo', {
  extend: 'Ext.app.Controller',
  requires: ['myapp.view.IngredientsListOverlay'],
  config: {
    control: {
      'list[origin=menu]': {
        itemtap: 'displayIngredients'
      }
    }
  },
  displayIngredients: function(list, index, target, record, e, eOpts){
    var menu = new myapp.store.Menu();
    overlay = Ext.widget('ingredientsListOverlay');
    Ext.Viewport.add(overlay);
    menu.getAt(index).ingredients().each(
      function(ingredient){
        overlay.insert(overlay.getItems().length,{html: ingredient.get("name")});
      }
    );
  }
});

Enfin, on modifie app.js pour qu’il charge le store et affiche la première vue (la liste de pizzas) au démarrage.

var menu = new myapp.store.Menu();
Ext.Viewport.add(Ext.create('myapp.view.MenuList'));

Mise en production d’une application dans le Cloud: gestion du déploiement par Cloudify

Le déploiement dans le Cloud possède quelques difficultés propres dont nous allons discuter dans cet article. Nous aborderons en particulier l’automatisation des déploiements qui permet de gagner en agilité mais aussi de diminuer sa facture pour un environnement qui ne fonctionne pas en 24×7.

Dans cet article nous expliquons comment l’outil devops Cloudify nous a permis d’automatiser le déploiement de notre application et de tous les middlewares dont il dépend. Il nous a permis aussi d’automatiser certaines tâches d’administration telles que les backups de la base de données. De plus, Cloudify offre des fonctionnalités de monitoring, d’auto-réparation et d’auto-scaling qui permettent d’adapter notre application dynamiquement.

Contexte

Devoxx France, le salon de développeurs qui se tenait une fois de plus à Paris cette année 2013, a compté parmi ses sponsors FastConnect. Dans une optique d’animation de notre stand, nous avons développé une application mobile nommée Fastcontest, un quiz en ligne avec des cadeaux pour les gagnants.

Pour sa réalisation, nous avons mis en œuvre plusieurs des technologies dont nous avons l’expertise au sein du pôle Cloud de FastConnect : Java, Spring, HTML5, méthodologie Scrum, bases NoSQL, Cloudify, etc. Le déploiement en production a été effectué grâce à Cloudify sur Amazon EC2 (le choix d’un cloud publique s’imposait du fait de la faible qualité de l’accès Internet dans nos locaux…) Le quiz, en plus d’offrir une activité ludique sur notre stand, nous a permis de montrer notre savoir faire, en particulier dans le domaine du Cloud Computing.

FastContestArchitecture

Cloudi-quoi?

Cloudify ! C’est une solution open source permettant de fabriquer son custom PaaS (une PaaS factory) éditée par GigaSpaces Technologies.
Cet outil permet d’effectuer un ensemble de tâches relatives au déploiement d’une application sur un cloud et à la gestion du cycle de vie de cette dernière. Il permet notamment :

  • l’automatisation du déploiement via des recettes (recipes)
  • une portabilité sur plusieurs cloud (EC2, OpenStack, Azure, etc. ou un data center « classique ») via la configuration d’un driver
  • la gestion des dépendances entre les différentes composantes de l’application
  • du monitoring
  • la gestion du failover et de l’élasticité
  • des tâches d’administration (via des custom commands)

Toutes ces routines sont décrites dans différents scripts/recettes (recipes). Dans le cadre de notre application, nous utilisons majoritairement le langage de programmation Groovy, mais nous nous servons aussi quelques fois de scripts Bash.

Le principal outil entre le développeur et le cloud où il déploie est le shell Cloudify. Il existe aussi une interface Web très ergonomique qui permet notamment de visualiser toutes les recettes, l’état des déploiements, les alertes et les métriques remontées par le monitoring applicatif.

Mais on ne saurait parler de scripts sans toutefois parler de tests et de debug ! Mais comment faire ? Faut-il utiliser le cloud d’Amazon chaque fois que nous voulons tester nos scripts ? Même en phase de développement et compte tenu de son coût ? Ce sont là des questions que nous nous sommes posées lors de cette phase du projet. Nous évoquerons la solution adoptée un peu plus bas dans l’article.

FastContest : les différentes briques

Revenons à notre mouton: notre application de Quiz. Elle est composée de trois tiers :

  1. une base de données
  2. une API REST pour les fonctions du jeu
  3. un front HTML5

L’API REST

L’API REST étant un projet Web, nous avons eu besoin d’un serveur d’application, en occurrence Apache Tomcat. Pour la base de données, nous avons choisi MongoDB dont nous avons l’expertise (nous sommes partenaire 10gen).

Le frontEnt Sencha

Nous avons opté pour le framework Sencha Touch pour développer le frontend mobile de notre application. Du point de vu serveur, l’application mobile est un contenu statique, nous avons choisi de l’héberger dans un serveur Apache HTTP.

Soulignons au passage que les tests de performance ont été effectués avec Gatling, pour lequel nous avons aussi créé une recette Cloudify. Nous publierons un article dédié sur ce sujet…

Si nous faisons un résumé des briques constitutives de notre application de quiz, nous recensons les services (tiers) suivants :

  • Une base de données NoSQL : MongoDB
  • Un serveur d’application : Apache Tomcat
  • Un serveur Web : Apache HTTPD avec mod_proxy_balancer pour des problématique de load-balancing et de redirection.
  • Gatling

Les Recipes Cloudify (recettes)

À chaque service correspond une recette, qui décrit un certain nombre d’informations et/ou de configuration dudit service :

  • L’identité du service sur le cloud : nom, icône, template de machine à utiliser, …
  • Le cycle de vie : on peut greffer n’importe quel comportement à chaque évenement (install, start, stop, …) via un script Groovy, Shell ou MS-DOS
  • Les custom commands : permettant de définir des actions que nous pourrons effectuer sur chaque instance du service après son déploiement. Exemples pour un service Tomcat : update du war, archivage des logs, …
  • Monitoring applicatif : Cloudify permet de remonter n’importe quel métrique. On peut l’afficher dans l’interface Web ou l’utiliser pour configurer une alerte ou une règle d’auto-scaling.
  • détection de panne : en cas de panne, Cloudify peut relancer le service défaillant automatiquement.
  • élasticité : le nombre d’instances d’un service peut varier dans le temps, suite aux pannes, auto-réparation ou bien pour répondre à un burst. Cloudify permet de définir des règles d’auto-scaling.

Voici un extrait de notre recette Tomcat :

service {
  name "tomcat"
  icon "tomcat.gif"
  type "APP_SERVER"
  // ...

  lifecycle {
    install     "tomcat_install.groovy"
    postInstall "tomcat_postInstall.groovy"
    preStart    "tomcat_preStart.groovy"
    //...
  }

  customCommands ([
    "updateWarUrl" : { warUrl ->
      context.attributes.thisService["warUrl"] = "${warUrl}"
      return true
    },
    "updateWarFile" : "updateWarFile.groovy"
  ])
  //...
}

Une application, au sens de Cloudify, est un ensemble de services (ou tiers) ayant des dépendances entre eux. Déployer une application signifie donc déployer tous ses services, dans un ordre convenable, et assurer l’injection des informations requises entre chaque couche.

Voici un extrait de la recette de notre application FastContest :

application {
  name "fastcontest"
  service {
    name = "mongod"
    compute {
      template "MONGO_TEMPLATE"
  }
}
service {
  name = "apacheLB"
  compute {
    template "APACHE_TEMPLATE"
  }
}
service {
  name = "tomcat"
  dependsOn = [ "mongod", "apacheLB" ]
  compute {
    template "TOMCAT_TEMPLATE"
  }
}
//...
}

Nous pouvons constater dans cet extrait que le service « tomcat » dépend des services « mongod » et « apacheLB ». En effet, tomcat a besoin des paramètres provenant du service mongod (adresse IP de la VM sur laquelle il est déployé par exemple) pour rendre l’application – ou du moins l’API REST – fonctionnelle ; et devra enregistrer son « end-point » auprès du service ApacheLB afin que ce dernier puisse mettre à jour sa configuration de load balancing.

Coder des recipes : les aspects à prendre en compte

Tout au long du projet, nous avons identifié quelques aspects primordiaux à prendre en compte dans les recettes Cloudify.

La clarté du code :

La première règle de programmation s’applique aussi aux scripts : faire simple. Le code doit être clair aussi bien dans sa forme que dans son fonctionnement (KISS).

Sonar est un outil d’analyse de qualité du code source. Il existe un plugin pour Groovy. Aussi nous avons mis tous nos scripts dans notre software factory afin de profiter de nos outils préférés.

Opérations à automatiser :

Il est nécessaire de recenser au préalable les différentes opérations à effectuer. Il s’agit notamment de lister les configurations nécessaires et de déterminer à quel moment du cycle de vie du service les appliquer : postInstall, start, postStart, ou bien en tant que custom command appelée depuis un autre service.

Un exemple. Dans notre cas le service Tomcat a besoin de communiquer le end-point (IP + context) de notre API REST au serveur HTTPD qui sert aussi de load-balancer. Il faut noter que le nombre d’instances de Tomcat – et de notre API REST – est variable et peut même changer dynamiquement si l’on a configuré des règles d’autoscaling.

Pour ce faire, nous avons créé une custom command nommée « addEndPoint » dans la recette d’ApacheLB, et cette commande est appelée par chaque instance de Tomcat lors de leur phase postStart.

Les custom commands sont une fonctionnalité très importantes de Cloudify. Elles permettent de coder des tâches d’administration (dump des logs, etc.) mais aussi de gérer des événements pour mettre à jour sa propre configuration. Ceci nous mène à un autre point : l’adaptation des services…

Adaptation des services à l’environnement

Nous entendons par là que les recettes doivent permettre aux différents services de prendre en compte les éventuels changement dans leur environnement et mettre à jour le service en conséquence. Ceci est particulier à la dynamicité d’un environnement Cloud où l’on peut être amené à gérer un changement d’adresse IP ou l’augmentation du nombre d’instances…
Cette notion d’adaptation en elle même est très large, et intègre d’autres notions telles que le « failover » et la « scalabilité ».

Fail-over

On désigne par là la capacité du système à se remettre d’une ou plusieurs pannes. Cloudify nous facilite la tâche : grâce aux détecteurs de fautes que nous définissons dans le script de description du service, Cloudify génére une alerte et il est capable de lancer des actions réparatrices : simple redémarrage du service, réinstallation ou ré-déploiement de la machine et du service.

Il est donc important d’écrire des recettes prenant en compte cet aspect, afin de d’assurer le meilleur comportement possible dans tous les cas (leak applicatif, bug Tomcat, crash d’une VM, etc.)

Scalabilité

Une fois de plus, Cloudify nous fournit un énorme coup de main dans cette problématique. Il permet de gérer l’élasticité d’un service de deux façons :

  • Manuellement : Si nous avons défini notre service en tant que « service élastique », alors nous avons la possibilité, via le shell Cloudify, d’augmenter ou de diminuer son nombre d’instances (le paramètre « maxAllowedInstances » nous protège contre une mauvaise manipulation).
  • Automatiquement : Cloudify permet, par l’intermédiaire de règles d’autoScaling, de définir une politique qui permettra de jouer dynamiquement avec le nombre d’instances du service. En général la politique d’autoscaling se fonde sur une des métriques applicative que l’on monitore.

Cette liste n’est pas exhaustive, et s’agrandira certainement avec l’expérience.

Déployer en environnement de Développement / Test

Tester notre application directement sur Amazon EC2 peut se révéler extrêmement couteux. Rappelons que par défaut, Amazon facture les machines à l’heure et que tout heure commencée est due. C’est pourquoi il faut éviter de déployer son application sur Amazon, de l’éteindre, de corriger une ligne et de recommencer. Ce qui est pourtant si facile quand on a tout automatisé…

Pour répondre à cette problématique, un expert Cloud de FastConnect, Mathias KLUBA, a développé un driver VirtualBox pour Cloudify. Grâce à ce driver, nous pouvons donc créer un cloud de VM VirtualBox sur notre machine de développeur et tester ainsi nos scripts Groovy en toute tranquillité. Vous trouverez un article sur ce driver : Driver VirtualBox pour Cloudify.

Pour information FastConnect est en train de construire un cloud interne OpenStack qui servira notamment lors de nos développements internes. Si vous avez besoin d’expertise sur OpenStack, contactez-nous ;-)

En production

Pour le passage en production, nous déployons sur le cloud d’Amazon EC2. Et là, on se dit « Vive Cloudify !! » car pas besoin de changer quoi que ce soit dans nos recettes, on remplace le driver VirtualBox par le driver Amazon EC2 et tout fonctionne.

Automatiser les déploiements et certaines actions d’administration

Pour pouvoir déployer sur l’environnement de Production de manière automatisée, en prenant les derniers packages à déployer, nous avons utilisé Jenkins.
Grâce à des scripts Groovy dans Jenkins, et l’API REST de Cloudify, nous avons pu déployer en 1 click sur Amazon (et détruire en 1 click). La procédure est la suivante :

  • Le matin, on exécute le job « Deploy » pour déployer l’application en 1 click
  • Le soir, on exécute le job « Undeploy » qui va:
    • Exécuter la « custom command » Dump du service MongoDB. Cette commande va faire un Dump de notre base, zipper et stocker dans S3.
    • Exécuter « uninstall-application » pour détruire l’application et les VMs utilisées.
  • Le lendemain, on exécute le job « Deploy » pour re-déployer l’application, ce qui va:
    • Exécuter « install-application » pour déployer l’application sur Amazon EC2.
    • Exécuter la « custom command » RestoreDump du service MongoDB. Cette commande télécharge le dernier dump depuis S3 pour le restaurer.

Pour des problématiques de supports, Jenkins exécute aussi régulièrement des « dump » de la base ainsi que des logs.

Dans notre cas le volume des données était faible, aussi un simple dump de MongoDB était très efficace. Un SnapShot de l’EBS aurait été plus intéressant si le volume avait été plus important.
L’opération de Dump n’était pas nécessaire tout au long de la journée puisque nous utilisions un ReplicatSet pour la résilience (et Cloudify est capable de re-démarrer les instances et les VMs après un crash)… Mais nous ne voulions prendre aucun risque :)

Conclusion

Au terme de cet article, nous avons mis en œuvre un bon nombre de technologies et d’outils relatifs au Cloud, et avons vu les différentes possibilités qu’ils offraient.
Nous constatons en particulier, que le déploiement d’une application sur un cloud et la gestion de son cycle de vie sont véritablement simplifiés grâce à Cloudify. Cependant, le mot « simplification » ne doit pas nous nous entraîner à la relâche ! En effet, les recipes étant le cœur de toute ces procédures automatisées, il ne faut pas négliger l’effort nécessaire pour produire des recettes de bonnes qualités.