Deployer une application Rails avec Capistrano et Phusion Passenger
Intéressé pour créer un API avec Ruby on Rails?
Jette un coup d'œil à mon livre: API on Rails 6. Tu peux télécharger une version gratuite au format PDF sur Github. Si tu aimes mon travail tu peux acheter un version payante sur Leanpub.
🇬🇧 Hello
Récemment, j’ai déployé une application Ruby on Rails sur mon petit VPS: https://killer.rsseau.fr . C’est toujours un peu complexe à faire car il faut penser à pas mal de choses. Dans cet article, je vais retracer tout ce que j’ai fais.
Dans mon cas, j’ai la stack suivante:
- Serveur Linux sous Debian 9
- Apache HTTP server
- Phusion Passenger, il s’agit d’un moyen d’éxécuter du Ruby
- RVM en tant que Ruby version manager
- Ruby on Rails 6
- SQlite en tant que base de données simple pour ne pas me prendre la tête
Si tu as une stack un peu différente, la mise en place peut être un peu différente mais elle restera très similaire.
Pour automatiser le déploiement, j’utiliserai Capistrano. Capistrano va s’occuper de plein de choses pour nous:
- se connecter en SSH au serveur
- cloner la dernière version du projet GIT
- installer les dépendances, lancer les migrations, construire les assets, etc..
- créer des symlink pour les fichiers partagés (ex:
production.sqlite
,master.key
, database, etc..)
Ca demande un peu de travail pour le mettre en place, mais crois moi: ça vaut le coup. Une fois mis en place, une commande est suffisante pour déployer une nouvelle version de ton site.
Mise en place du serveur
/var/www
On va commencer par créer quelques dossier dans /var/www
. Ce dossier contient tout le code de ton site afin qu’Apache puisse le faire fonctionner.
sudo mkdir /var/www/killer
Vu que Capistrano et Apache on besoin d’avoir accès à ce dossier, on va faire en sorte que ce dossier appartienne à l’utilisateur courant (debian
dans mon cas):
sudo chown debian /var/www/killer
Ensuite, on va créer le dossier shared
. Capistrano va utiliser ce dossier en faisant des liens symboliques lors des nouvelles releases. Je vais aussi créer les dossiers shared/config
et shared/config/credentials
(nous les utiliserons juste ensuite):
mkdir -p /var/www/killer/shared/
mkdir -p /var/www/killer/shared/config/credentials
mkdir -p /var/www/killer/shared/db
Dans mon cas, je veux ajouter les fichiers master.key
, production.key
(qui ne sont pas suivit dans le projet Git). Je vais le faire avec scp
# on local env
scp config/master.key user@server:/var/www/killer/shared/config/master.key
scp config/credentials/production.key user@server:/var/www/killer/shared/config/credentials/production.key
scp db/production.sqlite user@server:/var/www/killer/shared/db/production.sqlite
J’ai aussi besoin de créer une base de données SQlite. Celle-ci sera partagé lors des nouvelles release afin que les données persistent:
sqlite3 /var/www/killer/shared/db/production.sqlite
sqlite> SELECT 1;
sqlite> .exit;
NOTE: SQLite a besoin de lancer une requête pour que la base de données soit créées. C’est pour cela que j’ai lancé SELECT 1;
.
Installer Ruby
Maintenant on a besoin d’installer la même version de Ruby que celle utilisée par le projet. La façon la plus simple de faire est d’utiliser un manager de version Ruby
Dans l’écosystème de Ruby, il en existe deux: Rbenv & RVM. J’utilise ce dernier.
Donc, si tu n’as pas encore installé RVM, clique sur ce lien et laisse toi guider par la documentation. Ensuite, installe la version de Ruby en executant:
rvm install 3.1.2
Et on est bon pour le moment
Mise en place de Capistrano
Nous allons maintenant installer Capistrano et quelques plugins nécessaires dans notre cas:
bundle add capistrano --group development
bundle add capistrano-rvm --group development
Maintenant que Capistrano est installé, nous pouvons l’initialiser pour notre projet:
cap install
Tu dois désormais voir que certains fichiers on été créés.
Capfile
Le premier fichier Ă modifier est Capfile
. Ce fichier est responsable de charger les plugins. On a juste besoin d’ajouter quelques require
s
# Capfile
# ...
require "capistrano/deploy"
require 'capistrano/rails'
require "capistrano/bundler"
require "capistrano/rvm"
deploy.rb
Maintenant passons au fichier config/deploy.rb
. Ce fichier contient la configuration du déploiement que nous allons effectuer en production.
On va commencer par ajouter quelques paramètre de notre serveur distant:
# config/deploy.rb
# ...
# Global information about your repo
set :application, "killer-game"
set :repo_url, "git@github.com:madeindjs/killer-game.git"
set :branch, :main
# where to deploy and RVM conf
set :deploy_to, "/var/www/killer"
set :rvm_ruby_version, '3.1.2'
La dernière étape est de lister les fichiers qui seront partagés entre chaque déploiements. Attention car ces fichiers doivent être présents dans le dossier share
du serveur (heureusement, nous les avons créés dans la section précédente).
# config/deploy.rb
# ...
# every shared file we need
append :linked_files, 'config/master.key', 'config/credentials/production.key', 'db/production.sqlite'
production.rb
Le dernier fichier est config/deploy/production.rb
. Ce fichier contient les informations de connexion au serveur. Nous allons juste mettre Ă jour la directive server
:
server "vps-1bf61d44.vps.ovh.net", user: "debian", roles: %w{app db web}
Mon cas d’usage est vraiment très simple, je n’utilise pas de clé SSH ou de rôle spécifique pour l’utilisateur. Mais sache que Capistrano te propose beaucoup plus de paramètres pour t’aider à te connecter au serveur.
Premier essai
Maintenant, tout est prêt! Essayons donc d’effectuer un déploiement.
La première chose à faire avant d’aller plus loin est de pousser les modifications sur le repository GIT. En effet, Capistrano va cloner le projet sur le serveur et executer le code depuis le clone. On a donc besoin qu’il prenne en compte nos modifications:
git add .
git commit -m "Setup Capistrano"
git push origin
Une fois que c’est fait, tu peux lancer le déploiement sur la production:
cap production deploy
Si ça a marché, tu devrais voir apparaître des nouveaux fichier sur le serveur:
- un dossier
/var/www/killer/releases/$timestamp
qui contient le code du projet et les liens symboliques - un lien symbolique
/var/www/killer/current
qui pointe vers/var/www/killer/releases/$timestamp
Configuration du serveur
Revenons à nouveau au serveur afin qu’on le configure pour exécuter notre projet.
Installer Phusion Passenger
Comme je l’ai dit plus haut, Passenger est un moyen parmi tant d’autres de servir une application Rails avec Apache. J’ai choisi Passenger parce qu’il est Open Source et facile à mettre en place.
Aussi, Passenger a une excellente documentation. Pour l’installer, il suffit de suivre ce tutoriel.
NOTE: Je préfère éviter de copier/coller le tutoriel de Passenger ici car il est amené à changer.
Configuration de Apache HTTP server
Maintenant que Passenger est prêt, la partie la plus délicate nous attend: configurer Apache. Ne t’inquiètes pas, j’ai un template pour toi!
Créé un fichier killer.rsseau.fr.conf
dans /etc/apache2/sites-available/
sudo vim /etc/apache2/sites-available/killer.rsseau.fr.conf
… et colle ce contenu:
ServerName DefaultServer
DocumentRoot /var/www
PassengerDefaultRuby /home/debian/.rvm/wrappers/ruby-3.1.2/ruby
<VirtualHost *:80>
# RAILS CONF
# tell to Passenger which Ruby binary he need to use
PassengerRuby /home/debian/.rvm/wrappers/ruby-3.1.2/ruby
# setup rails environment
RailsEnv production
# APACHE CONF
# basic configuration of your webserver
ServerName killer.rsseau.fr
ServerAlias www.killer.rsseau.fr
ServerAdmin alexandre@rsseau.fr
# setup HTTP2 (not mandatory but better)
Protocols h2 http/1.1
# setup log, one file per day (not mandatory but better)
ErrorLog ${APACHE_LOG_DIR}/killer_fr_error.log
CustomLog "|/usr/bin/rotatelogs -f /var/log/apache2/killer.access.%Y-%m-%d.log 86400" combined
# FOLDER CONF
# serve you current version of the project
DocumentRoot /var/www/killer/current/public/
<Directory "/var/www/killer/current">
Options FollowSymLinks
Allow From All
Require all granted
Options -Indexes
</Directory>
# use apache to serve static files to improve perf
Alias / "/var/www/killer/current/public/"
<Directory "/var/www/killer/current/public/">
Options FollowSymLinks
</Directory>
</VirtualHost>
Ensuite, tu devrais pouvoir activer cette configuration avec a2ensite
sudo a2ensite killer.rsseau.fr.conf
Et pour terminer, tu dois redémarrer ton serveur pour prendre en compte les changements:
sudo /etc/init.d/apache2 restart
Pour tester que tout fonctionne, tu peux ouvrir ton navigateur ou utiliser cURL
comme un hacker:
curl http://killer.rsseau.fr
VoilĂ !
Troubleshooting
A ce moment, beaucoup de problèmes diverses peuvent survenir. Les logs peuvent arriver dans divers fichiers:
/var/log/apache2/error.log
/var/log/apache2/killer_fr_error.log
/var/www/killer/current/log/production.log
Je recommande de tous les regarder au début pour voir si un problème est détecté:
tail -f /var/log/apache2/error.log /var/log/apache2/killer_fr_error.log /var/www/killer/current/log/production.log
Conclusion
De nos jours, déployer une application Rails est “facile”.
Beaucoup de développeurs utilisent un outil comme Heroku pour déployer rapidement une application Rails. Il n’y a rien de mal à cela. Mais je ne veux pas dépendre d’un service externe pour mon application. De plus, lorsque tu sais comment déployer toi-même une application Rails, c’est plus rapide que de le faire avec Heroku. Faire soi-même est un bon moyen de améliorer tes compétences DevOps et d’économiser de l’argent. J’héberge de nombreux sites Web sur des serveurs VPS à 3 € par mois, alors que le plan de démarrage de Heroku coûte 7 $ par mois (et coûte rapidement plus cher).
Mais ne te méprends pas, les solutions Heroku ont des avantages. Elles offrent un moyen rapide de scaler ton application: tu dois juste payer plus cher. Aussi, si tu héberge ton application toi-même, tu dois surveiller les journaux de votre serveur web, sauvegarder la base de données, mettre à jour le serveur HTTP Apache régulièrement… Heroku peut s’en charger pour toi.
C’est à toi de choisir la bonne réponse.
Tu pouvez aller plus loin dans l’auto-hébergement avec ces sujets :
- configurer HTTPS en utilisant Certbot
- utiliser un autre serveur de base de données (même si sqlite peut être suffisant)
- faire une sauvegarde en utilisant une CRONtab
Voir les autres articles liés
Participez au développement de votre navigateur preéferé
Participez au développement de votre navigateur preéferé