Ruby on Rails, ce n’est vraiment pas la panacée du point du déploiement, et je dirais même que c’est une technologie chiante avec tous ses modules et bugs obscurs dû à des dépendances pourries, mais lorsqu’on désire utiliser l’excellent gestionnaire de projet redmine, il faut bien mettre les mains dans le cambouis.
Jusqu’à présent, je faisais tourner redmine en utilisant mongrel, donc avec une passerelle fastcgi pour le faire communiquer avec nginx.
C’est une solution complètement naze, j’en conviens, car de cette manière, une seule requête pouvait être traitée à la fois, mais au moins c’était fonctionnel.
J’ai pu tricher en détournant les requêtes vers les ressources statiques vers nginx de la manière suivante :
server {
listen 443;
listen [mon_ipv6]:443 ssl ipv6only=on;
server_name redmine.mondomaine.com;
access_log /var/log/nginx/redmine.access_log main;
error_log /var/log/nginx/redmine.error_log notice;
root /var/www/redmine/htdocs/public;
location ~* (^$|/$|^/(projects|attachments)|^[^\.]+$) {
proxy_pass http://127.0.0.1:1091;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X_FORWARDED_PROTO 'https';
proxy_redirect http://redmine.mondomaine.com https://$host;
}
}
Mais ce genre de rustine atteint très rapidement ses limites dès lors que plusieurs personnes utilisent le site en même temps.
Depuis que redmine est passé en version 1.4.x, j’ai mis à jour les modules demandés selon les prérequis, et là ça marche… si on veut :
- consommation de mon quad-core de manière très variable mais plus souvent vers le 80% que vers le 0%, même lorsqu’il n’y a personne
- warning en folie sur des instructions dépréciées
C’est une situation qui n’est pas tenable très longtemps, mon instance teamspeak sur le même serveur pourra confirmer, ça laggait grave.
Comment remédier à ces 3 problèmes que je rappelle :
- consommation CPU délirante
- warnings
- mono-tache (1 requête à la fois)
J’ai tenté la solution phusion passenger, qui consiste à compiler un module passenger à Nginx. Nginx n’étant pas modulaire, compiler un module pour Nginx revient à recompiler Nginx.
Solution 1
J’ai installé la dernière version stable disponible dans portage, la version =www-apache/passenger-3.0.7 , puis utilisé la commande passenger-install-nginx-module . J’ai tenté, j’ai eu une erreur, je n’ai pas cherché très longtemps car cette solution ne me plaît pas : la commande va recompiler nginx, avec les modules par défaut et le module passenger, donc exit les USE que j’avais utilisés sur nginx.
Solution 2
J’ai utilisé passenger –start . A la première exécution, il va compiler une version de nginx avec passenger et l’installer quelque part dans /var/lib.
Cette solution est mieux au niveau architecture car on se retrouve avec deux instances nginx :
- l’instance d’origine, qui était là avant passenger, celle que j’ai compilé et configuré reste et prend le rôle de frontend
- passenger se lance dans une seconde instance d’une autre compilation de nginx (celle incluant le module passenger, ici ce nginx n’est qu’une coquille pour passenger). Elle a le rôle de backend et héberge donc l’application ruby. Elle communique avec le frontend par fastcgi.
Ca n’a pas marché, passenger n’étant pas fichu de compiler correctement la dépendance libev.
Solution 3
Mettons donc à jour passenger avec gem en version 3.0.13 (gem install passenger -v 3.0.13 ), non encore stable sur ma distribution au moment où je rédige ce billet. En retestant la solution 2, ça marche 🙂
Mais j’ai toujours une consommation CPU délirante.
Solution 4 (c’est la bonne)
OK, la solution 3 fonctionne, mais avoir 2 nginx, c’est un peu naze. N’y-a-t-il pas moyen de compiler « manuellement » nginx ? Ainsi j’aurais passenger directement intégré à mon nginx principal.
En lisant la doc un peu plus loin, c’est effectivement possible.
Et bah c’est partie, je copie l’ebuild nginx dans mon overlay, et zou on intègre passenger.
Ça compile, très bon signe ; on notera que des fichiers supplémentaires ont été générés durant la compilation pour phusion passenger : l’agent Nginx.
J’ajoute la configuration suivante dans nginx :
http {
# path obtenu avec passenger-config --root
passenger_root /usr/local/lib64/ruby/gems/1.8/gems/passenger-3.0.13;
passenger_max_pool_size 10;
}
server {
listen 443;
listen [mon_ipv6]:443 ssl ipv6only=on;
server_name redmine.mondomaine.com;
access_log /var/log/nginx/redmine.access_log main;
error_log /var/log/nginx/redmine.error_log notice;
root /var/www/redmine/htdocs/public;
passenger_enabled on;
passenger_use_global_queue on;
passenger_user mongrel_redmine;
}
Et là c’est jackpot, tous les problèmes ont été résolus, que ça soit les vieux pics cpu ou les warnings, c’est maintenant de l’histoire ancienne (jusqu’à la prochaine grosse update de redmine…), et j’ai gagné en rapidité dans un environnement multi-utilisateurs vu que j’ai désormais un pool et non plus un seul processus pour gérer les requêtes vers l’application redmine (qui repose sur le framework ruby on rails). Le changement se ressent immédiatement.
Je n’ai pas trop cherché à comprendre pourquoi, mais j’ai obtenu une conf parfaitement fonctionnelle, donc ON NE TOUCHE PLUS.
Pour les intéressés sous Gentoo, j’ai un overlay contenant un ebuild permettant de compiler nginx avec passenger. Il faut juste ajouter ça dans layman pour synchroniser l’overlay : https://raw.github.com/LordVeovis/gentoo/master/repositories.xml.
Je suppose, sans l’avoir testé, que cet ebuild est capable de fonctionner avec une version plus ancienne de passenger, comme celle marquée comme stable dans portage, mais je ne testerais pas, tant que ça ne bug pas.
Voir aussi