Il y a quelques semaines, j’ai obtenu un accès à la béta de Cloud Foundry. Pour ceux qui n’ont pas suivi l’actualité, il s’agit d’un PaaS (Platform as a Service) Open Source de VMWare, permettant d’exécuter en cloud des applications Java (WAR, Spring, ROO), Rails, ou Node.js (pour l’instant, mais d’autres pourraient bientôt venir enrichir cette liste).

Prise en main

La prise en main de l’outil de déploiement VMC via le tutoriel est extrêmement simple. On y apprend à créer et déployer une application sur le cloud en quelques commandes.

Deuxième chose à laquelle je m’intéresse, les systèmes de persistance. On a le choix entre trois systèmes, SQL (MySQL) ou NoSQL : MongoDB (base orientée documents) et Redis (base clé-valeur). Cette liberté de choix est très appréciable, et permet de répondre aux différents types de besoins que l’on peut avoir. Et là encore, on peut penser que d’autres systèmes viendront prochainement enrichir cette liste.

Côté Java, encore de bonnes surprises : contrairement au Google App Engine (par exemple), il n’y a aucune restriction sur l’utilisation de l’API : l’application est exécutée sur un serveur Tomcat. Il est donc possible de développer une application web Java complètement standard, et ensuite de la déployer sur Cloud Foundry au lieu d’un serveur d’application classique.

J’ai fait le test (avec une application simple) et ça fonctionne !

Avec Spring et l’outil de développement Spring Tool Suite, la gestion de la persistence MySQL est très simple, comme expliqué sur le blog officiel.

Déployer une application Play sur Cloud Foundry

Une fois cette prise en main effectuée avec un projet Spring, j’ai voulu voir s’il était facile de déployer une application Play Framework. Je suis donc parti d’un des projets d’exemple de la version 1.2 du framework : Yabe (Yet Another Blog Engine).

Passer par la case WAR

Les applications PlayFramework n’étant pas encore supportées nativement (mais j’espère que ça ne tardera pas trop) par Cloud Foundry, nous allons devoir passer par l’export WAR du projet, que nous mettons dans un répertoire dédié :

1
2
3
play war yabe -o yabe_war
cd yabe_war
jar -cvf /tmp/yabecloud/yabe.war .

Essayons maintenant de déployer cette application :

1
2
cd /tmp/yabecloud
vmc push

On répond aux différentes questions (sans mettre en place de service de persistance dans un premier temps). J’ai donc un projet yabe, qui sera accessible à l’adresse http://yabe.cloudfoundry.com/

Et là… ça ne marche pas ! J’avoue que sans avoir modifié quoi que ce soit au projet, je n’y croyais qu’à moitié.

Analyser les logs

A ce stade, pour comprendre ce qui ne va pas, le message de Cloud Foundry n’est pas vraiment suffisant… Il va donc nous falloir analyser les logs. Cela se fait directement via l’outil VMC, qui permet (entre autres choses) de lister le contenu du disque de l’instance :

1
2
3
vmc files yabe logs # Liste le contenu du répertoire logs
vmc files yabe logs/stdout.log # Affichage de la sortie standard
vmc files yabe logs/errout.log # Affichage de la sortie d'erreur

Première erreur : le Bootstrap de l’application lance un job, qui a besoin de l’URL du projet dans le fichier de configuration. J’ajoute donc au fichier application.properties :

1
application.baseUrl=http://yabe.cloudfoundry.com/

On régénère comme précédemment le WAR, et on met à jour l’application :

1
vmc update yabe

On remarque au passage que vmc n’a presque rien à uploader ! En effet, il analyse le WAR, et n’uploade que les fichiers modifiés, et qu’il ne connaît pas déjà (librairies standard, etc.).

Et là… ça ne marche toujours pas ! Mais l’analyse des logs montre que la raison est différente : on a donc progressé ! Cependant, il s’agit d’un problème lié à la classe Fixtures de Play qui n’a rien à voir avec Cloud Foundry. Comme ce n’est pas le but de l’article, je remplace le code de la classe Bootstrap par :

1
2
3
4
5
6
7
8
9
10
11
@OnApplicationStart
public class Bootstrap extends Job {
 
    public void doJob() {
        // Check if the database is empty
        if(User.count() == 0) {
            // Fixtures.load("initial-data.yml"); Ne marche pas en export WAR
            (new User("admin@admin.com", "admin", "Administrateur")).save();
        }
    }
}

On réexporte le WAR, on redéploie sur Cloud Foundry… et ça marche !!!

Pour à peine quelques modifications de code (liées à Play et non pas à Cloud Foundry d’ailleurs) dans un projet Play pré-existant, et quelques commandes dans la console, nous avons un projet déployé et fonctionnel.

Gérons la persistence

Jusqu’à maintenant, nous ne nous sommes pas préoccupés de la persistence. Par défaut, ce projet Play utilise une base mémoire H2. Ca fonctionne sans soucis, mais à chaque redéploiement, les données sont évidemment perdues.

Intéressons-nous donc de plus près à la gestion de la persistence de Cloud Foundry :

1
vmc create-service mysql mysql-yabe yabe

Et c’est tout… Un service nommé mysql-yabe a été créé et bindé à mon application yabe.

Par contre, c’est là que les choses se compliquent. Les identifiants d’accès à cette base sont enregistrés dans une variable d’environnement VCAP_SERVICES, mais celle-ci n’est accessible que depuis l’application elle-même. Si je me trompe et que quelqu’un sait comment y accéder depuis l’outil VMC, je suis preneur de l’information !

Faute de mieux pour l’instant, je  suis donc passé par un contrôleur et un template Play pour obtenir ces informations :

1
2
3
4
5
6
public class Vcap extends Controller {
    public static void index() {
        String vcap = System.getEnv("VCAP_SERVICES");
        render(vcap);
    }
}

Et le template :

1
2
3
4
5
<html>
    <body>
        <p>${vcap}</p>
    </body>
</html>

On redéploie, et on se rend sur la page associée :

1
{"mysql-5.1":[{"name":"mysql-yabe","label":"mysql-5.1","plan":"free","credentials":{"node_id":"mysql_node_1","hostname":"123.123.123.123","port":3306,"password":"my_password","name":"my_db_name","user":"my_user"}}]}

Bingo : dans la zone credentials de ce JSON, il y a toutes les informations dont on a besoin pour configurer notre base de données. On reporte ça dans application.conf, et comme précédemment, on redéploie notre application. Ca marche !

Le résultat est visible sur http://yabe.cloudfoundry.com/

Créer sa propre instance de Cloud Foundry

Cloud Foundry est écrit en Ruby, et disponible en Open Source sur GitHub. Après des heures de galère à essayer d’installer Gitorious, j’appréhendais beaucoup l’installation de Cloud Foundry. Mais les vacances aidant, je me suis lancé.

Deuxième énorme claque ! Sur mon Ubuntu 11.04 fraichement installée, il a suffit de lancer le programme vcap_setup, et de suivre les instructions du README du projet. Aucune mauvaise surprise : j’en suis encore bouche-bée.

TODO

Après cette première expérience très positive avec Cloud Foundry, voici en guise de conclusion quelques idées d’optimisations. Les vacances s’achevant ce soir, je risque de manquer de temps… N’hésitez donc pas à me les voler : je ne porterai pas plainte !

  • créer une évolution de la gestion du paramètre db de la configuration de Play (ou un module/plugin), pour inclure la gestion automatique de la variable d’environnement VCAP_SERVICES de Cloud Foundry [Mise à jour le 5 mai 2011]Fait (du moins dans une version minimaliste) : le plugin en question est disponible sur GitHub.[Fin de mise à jour]
  • faire évoluer Cloud Foundry lui-même, pour gérer nativement les applications Play Framework (et concurrencer PlayApps), pour ne plus être obligé de passer par l’émulation Servlet, très préjudiciable aux performances.

Redmine, Gitorious… et maintenant Cloud Foundry : ça va vraiment achever de me convaincre d’aller sérieusement voir du côté de Ruby/Rails cet été. Si certains connaissent un bon livre pour débuter, je suis preneur…