Play application on Centos/RedHat in production mode
tl;dr : application Play (java ou scala) sur un serveur Centos (ou Red Hat) derrière un serveur nginx.
Script de démarrage/arrêt du daemon.
Lancer une application Play en dev est assez aisé :
$ play run
.
Maintenant, si vous avez besoin de déployer votre application en production, il est plus confortable de considérer votre application comme un service à part entière du système. Il se peut aussi que vous ayez besoin de spécifier un port et une interface particulière pour pouvoir utiliser nginx comme front-end (en reverse proxy). Et évidement, à l'instar d'un environnement de développement, vous pourriez avoir besoin de compresser le JS et le CSS, et également de régler finement les en-têtes HTTP pour gérer correctement le cache.
Tout d'abord le script de lancement du daemon :
Je me suis inspiré des deux gists ci-dessous. Le premier, pour RedHat, utilise le binaire de play pour lancer le processus principal. Cette méthode facile à utiliser en développement semble assez limité en paramètre (tout du moins, très peu documentée). La seconde méthode, pour Debian, donne un bonne exemple d'une configuration un peu plus élaborée de l'exécution du daemon. Les paramètres en début de fichier parlent d'eux-mêmes, je vous laisse les découvrir et reste à votre disposition pour toute question.
Source :
- https://gist.github.com/THemming/2173037 (script pour redhat)
- https://gist.github.com/leon/2204773 (script pour debian)
Configuration de nginx
Sur un serveur web, il est souvent pratique de pouvoir faire tourner plusieurs applications utilisant des langages, des librairies, des frameworks, etc... hétérogènes (sur mon serveur, il y a l'application Play en scala, une application Nodejs en Coffescript et une application PHP/MySQL utilisant Apache). C'est là que nginx intervient. Configuré en reverse-proxy, c'est lui qui écoutera sur le port 80 de votre serveur et en fonction du nom de domaine relayera les requêtes HTTP à l'application que vous avez choisis. Il vous suffit de configurer votre application en écoute sur un port libre en localhost et d'indiquer à nginx qu'en fonction du nom de domaine (à la manière des VirtualHost d'Apache), il doit transmettre ses requêtes sur ce port.
Vous noterez une section fournissant un traitement particulier pour les fichiers statiques (js, css, png, jpg, etc...). En effet, je ne trouvais pas la configuration par défaut de play très satisfaisante pour diffuser ces fichiers. Il conviendra donc de copier tous les fichiers dans un dossier particulier au lancement de l'application (il faut également pensé à y placer les fichiers "compilé" des scripts utilisant un pre-processeurs : coffeescript, SASS/SCSS, LESS, etc...). Tous les fichiers dans ce dossier auront une durée de cache maximale afin de minimiser le nombre de requêtes au serveur (la requête la plus rapide est celle qui n'est pas faite). Cette technique a aussi l'avantage de décharger la JVM du traitement de ses fichiers, ils sont directement retourné par nginx.
Compilation des fichiers statiques
Les pré-processeurs (Coffeescript, SASS, LESS, etc...) sont d'un grand confort pour le développement de la partie front-end d'une application web. Toutefois, il y a quelques détails qui ne faut pas négliger afin d'optimiser au maximum la distribution en HTTP de ces fichiers.
Prenons comme exemple un fichier .coffee (Coffeescript). Lorsqu'en
développement vous lancer votre serveur, play se charge de
re-compiler automatiquement le fichier afin de desservir un fichier
javascript au navigateur qui a demandé le fichier. Dans notre
environnement, les fichiers statiques se trouvent tous dans un
dossier static/
. Il faut donc "traduire" ce fichier en
javascript et le placer dans ce dossier (en respectant
l'arborescence utilisée en développement) :
coffee -o static/javascripts/ -c
app/assets/javascripts/*.coffee
.
Ensuite, comme optimisation souvent préconnisée, il convient de
"minifier" ces fichiers afin qu'ils soient le plus léger possible
pendant le transport sur le réseau (qui peut-être une faible
connexion 3g). Dans mon cas, j'ai utilisé
yuicompressor
qui fonctionne bien. Il en existe certainement des mieux, je n'ai
pas testé, mais celui-là fonctionne comme je veux.
Note : comme amélioration possible, il faudrait dans cette partie là renommer les fichiers par un nom de fichier contenant un hash représentant le contenu de ce fichier afin de palier à tout problème d'invalidation du cache.
Dans le futur
Pour parfaire le déploiement de l'application, sur un VCS git par exemple, il serait pratique d'automatiser le redémarrage du serveur sur un hook post-commit. Pour éviter également une coupure de service, il faudrait également, lancer la nouvelle application sur un autre port et switcher sur la nouvelle instance uniquement avec un reload de nginx. Mais bon tout ça peut faire l'objet d'un autre article. :)
Mise à jour du 29 juillet 2013 : correction du script de lancement du daemon.