Cet article est le 4ème et dernier dans la série “Migration vers Passenger” qui comprend également :
- le préambule.
- Ruby Entreprise Edition
- VirtualHosts
Et voilà, c’est fini !
Mardi 28 janvier, aux alentours de 22h, la phase finale de cette migration a eu lieu. Voilà ce qu’il a fallu gérer pour que ça se termine bien.
Les VirtualHosts
Par rapport à l’article précédent, j’ai encore fait quelques modifs sur les VirtualHosts.
Les directives de compression des fichiers pouvant l’être est identique d’un site à l’autre, j’ai donc créé un fichier /etc/apache2/deflate.conf qui est inclus dans chaque VHost.
AddOutputFilterByType DEFLATE application/x-javascript text/html text/plain text/css text/javascript text/xml BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Idem pour /etc/apache2/expires.conf qui définit des expirations de cache. Ça peut encore être amélioré, mlais c’est déjà pas mal.
# turn on the module for this directory ExpiresActive on # cache common graphics for 3 days ExpiresByType image/jpg "access plus 3 days" ExpiresByType image/gif "access plus 3 days" ExpiresByType image/jpeg "access plus 3 days" ExpiresByType image/png "access plus 3 days" # cache css and javascript for 3 days ExpiresByType text/javascript "access plus 3 days" ExpiresByType application/x-javascript "access plus 3 days" ExpiresByType text/css "access plus 3 days" ExpiresDefault "access plus 24 hours"
J’ai également rajouté (pour les applications Rails) la redirection vers la page de maintenance au cas où elle existe
# Check for maintenance file and redirect all requests RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f RewriteCond %{SCRIPT_FILENAME} !maintenance.html RewriteRule ^.*$ /system/maintenance.html [R=307,L]
À la fin de la migration, je prévois de désactiver tous les VHosts de Nginx, au cas où j’aurai besoin de relancer Nginx pour autre chose.
Les ports
Comme plusieurs serveurs ne peuvent pas écouter le même port en même temps, il fallait faire les changements.
Jusque là Nginx écoutait le port 80 et Apache le port 8080.
La modification du port d’Apache se fait à un seul endroit de sa config générale. Sur Debian, ça se passe dans /etc/apache2/ports.conf. J’y ai ajouté le port 80. Le port 8080 peut rester pour le moment.
Pour Nginx, c’est plus compliqué car il est indiqué dans chaque VirtualHost. Je ne sais pas si c’est une maladresse de ma part, mais dans mon cas c’est fait comme ça. Je n’avais pas très envie de modifier chaque VHost, mais comme Nginx n’avait pas besoin de continuer à fonctionner après la bascule, pas besoin de changer quoi que ce soit.
Les logs
Pour copier les logs de Nginx vers le dossier d’Apache, je pouvais faire une simple copie du contenu du répertoire, mais tout ne m’intéressait pas, notamment parce qu’il y a pas mal de logs de scripts ou sites dont je n’ai plus besoin.
J’ai donc écrit un script en bash pour faciliter ça.
#!/bin/sh if [ $(whoami) != "root" ]; then echo "Vous devez etre super-utilisateur pour executer ce script." exit else rm /var/log/apache2/*.access* rm /var/log/apache2/*.error* cp /var/log/nginx/default.access* /var/log/apache2/ cp /var/log/nginx/site1.access* /var/log/apache2/ # (...) cp /var/log/nginx/siteX.access* /var/log/apache2/ invoke-rc.d apache2 restart invoke-rc.d nginx stop fi
Comme Apache ne servait à rien d’important jusque là, j’ai commencé par nettoyer tout son dossier de logs. Ensuite je copie uniquement les logs des sites voulus. Le redémarrage d’Apache permettait de reprendre les logs là où ils en étaient et de changer le port d’écoute. L’arrêt de Nginx permettait de libérer le port 80. J’aurais cerainement dû inverser l’arrêt de Nginx et le restart d’Apache, mais ça a bien marché.
Enfin Webalizer utilise /var/log/nginx/siteX.access.log comme source, il suffit de changer le dossier cible avant qu’il fasse son analyse suivante.
Monit et Munin
Je voulais que Monit puisse suivre l’écoute du port 80 par Apache. J’ai donc suivi la recommendation courante et créé un fichier vide dans /var/www/monit/token. Monit va donc tester une connexion HTTP vers http://mon.addresse.ip.publique/monit/token.
Mais comme je veux éviter d’avoir des milliers de logs pour cette URL, j’ai ajouté une directive dans le VHost “default”
SetEnvIf Request_URI "^\/monit\/token$" dontlog CustomLog /var/log/apache2/access.log combined env=!dontlog
Nginx devant s’arrêter, il fallait le sortir de la liste des ressources à surveiller. Pour cela il suffit de commenter l’inclusion de son fichier de config dans le fichier de config de Monit (/etc/monit/monitrc).
Inversement, j’ai décommenté l’inclusion du fichier pour Apache.
Au niveau de Munin, les plugins sont des scripts qui renvoient du texte dans un format normalisés. Ils sont stockés dans /usr/share/munin/plugins/. Pour les activer, il suffit de créer un lien symbolique dans /etc/munin/plugins/.
J’ai supprimé le lien pour les scripts de Nginx.
J’avais déjà préparé le terrain pour Apache et activé ses scripts en les faisant tester le port 80, ce qui jusqu’à la bascule ne rendait aucune info.
Capistrano et Mongrel
Dans la situation initiale, ce sont des process Mongrel qui faisaient fonctionner les applis Rails. Ils étaient démarrés et relancés par une recette de déploiement Capistrano.
Dans #{RAILS_ROOT}/config/deploy/production.rb il y avait
namespace :deploy do desc "Start the application" task :start, :roles => :app do mongrel.start end desc "Stop the application" task :stop, :roles => :app do mongrel.stop end namespace :mongrel do desc "Restart the Mongrel cluster" task :restart do stop start end desc "Start the Mongrel cluster" task :start do run "/usr/bin/mongrel_rails cluster::start -C #{shared_path}/config/mongrel_cluster.yml --clean" end desc "Stop the Mongrel cluster" task :stop do run "/usr/bin/mongrel_rails cluster::stop -C #{shared_path}/config/mongrel_cluster.yml --clean" end end end
J’ai simplifié comme ça
namespace :deploy do namespace :passenger do desc "Restart the application within Passenger Phusion" task :restart do run "touch #{release_path}/tmp/restart.txt" end end desc "Restart the application" task :restart, :roles => :app do passenger.restart end end
Une fois la modification faite il suffisait de stopper les applis qui tournaient via Mongrel :
$ cap production deploy:stop
Les oublis
Un seul oubli en fait ; mettre certains droits à l’utilisateur www-data (celui qui est attribué à Apache) au niveau de certains fichiers des blogs Wordpress. En conséquence, les fichier .htaccess ne pouvaient plus être utilisés pour les RewriteRules.
Je m’en suis rendu compte car la page d’accueil du site neomarco.com se connecte sur le flux RSS d’un des blogs et là ça ne fonctionnait plus.
Conclusion
Tout s’est passé dans un délai très court ; quelques dizaines de secondes pour l’enchaînement des taches cruciales. Toutes les modifications de config qui pouvaient se faire un amont l’avaient été et celles à faire ensuite n’étaient pas urgente.
Par contre, tout le temps de préparation – recherche de tous les points possibles de changement, établissement d’un enchaînement idéal, tests de portion de la bascule sur d’autres serveurs, … – a pris beaucoup plus de temps. J’ai pas mesuré précisément, mais ça représente une bonne douzaine d’heures.
Il reste certainement des petites modifications pour affiner l’ensemble, mais déjà je trouve que le site réponds beaucoup plus vite.
Le cache semble mieux marcher au niveau du navigateur. Je ne pense pas que ça soit dû à une défaillance de Nginx, mais plutôt à une config mal faite de mon côté.
Par contre il est indéniable que les ressources mobilisés sont bien moindres. J’ai économisé plus de 2go de ram en confiant à Apache+Passenger le soin de lancer les process dont il a besoin.
Je vais maintenant pouvoir mettre en place un bon gros serveur memcached avec la ram libérée. Mais là c’est une autre histoire.