Aller au contenu
Développement medium

Ruby pour les ops : déployer et exploiter

9 min de lecture

Ruby fait surtout tourner des applications web avec Ruby on Rails, et l'exploiter ne demande pas de coder en Ruby, mais de comprendre comment Rails s'exécute en production. Ce guide s'adresse aux ops : versions et support, la gestion des versions avec rbenv, Bundler pour les dépendances, le serveur d'application Puma, le déploiement et la performance avec YJIT. Commandes validées sur Ruby 3.4.

  • Suivre les versions de Ruby et leur fin de support
  • Isoler les versions avec rbenv et installer les gems avec Bundler
  • Comprendre Puma (workers et threads) et déployer une app Rails
  • Activer YJIT et scanner les gems vulnérables

Recadrage utile : Ruby 4.0 est la version stable courante (sortie fin 2025), et 3.4 reste la branche conseillée pour la production prudente. Chaque branche suit trois phases : maintenance normale (bugs + sécurité), maintenance sécurité seule, puis fin de vie (EOL).

BranchePhase (mi-2026)
4.0maintenance normale (stable courante)
3.4maintenance normale (choix sûr en prod)
3.3sécurité seule (EOL prévu 2027)
3.2 et avantEOL

Comme pour tout langage, une branche EOL ne reçoit plus de correctifs : la montée de version est une tâche d'exploitation planifiée.

N'utilisez pas le Ruby du système : il sert à des outils de l'OS, et le figer à la version d'une distribution casse vos projets. Un gestionnaire de versions isole chaque projet. Le plus répandu est rbenv, qui intercepte ruby, gem et bundle et lit un fichier .ruby-version à la racine du projet.

Fenêtre de terminal
rbenv install 3.4.9 # installer une version
rbenv local 3.4.9 # écrit .ruby-version dans le projet
rbenv versions # lister les versions (l'active marquée d'un *)

Le fichier .ruby-version est devenu un standard de fait : asdf et mise (deux gestionnaires multi-langages) le lisent aussi. rvm reste une alternative historique. L'essentiel est qu'un projet déclare sa version dans le dépôt.

Les bibliothèques Ruby sont des gems, gérées par Bundler via deux fichiers :

  • Gemfile : les dépendances déclarées et leurs contraintes.
  • Gemfile.lock : les versions exactes résolues, à committer pour des installations reproductibles.

En production, on active le mode deployment : il exige un Gemfile.lock à jour, isole les gems dans vendor/bundle et exclut les groupes de développement.

Fenêtre de terminal
bundle config set --local deployment true
bundle config set --local without 'development test'
bundle install

Ruby n'est pas un serveur HTTP. En production, on place un serveur d'application devant l'app, le plus courant étant Puma, lui-même derrière un reverse proxy Nginx. Le modèle de Puma est hybride :

  • Threads : chaque requête est servie dans un thread, ce qui augmente le débit avec peu de mémoire.
  • Workers (mode cluster) : plusieurs processus forkés, qui partagent la mémoire par copy-on-write.

Pourquoi les deux ? À cause du GVL (Global VM Lock) de Ruby : un seul thread exécute du code Ruby à la fois. Les threads aident donc surtout pour l'I/O en attente (base de données, appels HTTP), mais pour du parallélisme CPU réel, il faut plusieurs workers. D'où la règle de dimensionnement :

Fenêtre de terminal
WEB_CONCURRENCY=3 puma -t 5:5 # 3 workers x 5 threads = 15 requêtes simultanées

Le nombre de threads doit être aligné sur le pool de connexions à la base (RAILS_MAX_THREADS), sinon des threads attendent une connexion libre.

Un déploiement type enchaîne dépendances, migrations, assets, puis redémarrage de Puma :

Fenêtre de terminal
git pull
bundle config set --local deployment true
bundle config set --local without 'development test'
bundle install
RAILS_ENV=production bundle exec rails db:migrate
RAILS_ENV=production bundle exec rails assets:precompile
# puis redémarrer Puma (systemd, pumactl...)

La configuration passe par des variables d'environnement : RAILS_ENV=production, RAILS_MAX_THREADS, WEB_CONCURRENCY, et RAILS_LOG_TO_STDOUT (indispensable en conteneur pour que les logs partent sur la sortie standard).

Les secrets sont gérés par les credentials chiffrés de Rails : config/credentials.yml.enc, déchiffré par config/master.key ou la variable RAILS_MASTER_KEY. La master.key ne doit jamais être committée. La secret_key_base qui en dérive chiffre les cookies et sessions : la changer invalide toutes les sessions actives.

En conteneur, l'image officielle se décline en ruby:4.0, ruby:3.4 et leurs variantes -slim (Debian minimal) et -alpine. Le Dockerfile type installe les gems avant de copier le code, pour profiter du cache de couches :

FROM ruby:3.4
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .

YJIT est le compilateur JIT de Ruby : il compile le code chaud en code machine et apporte un gain net (plus de 3 fois plus rapide que l'interpréteur sur certains benchmarks). Deux niveaux à distinguer :

  • Au niveau Ruby, YJIT n'est pas activé par défaut : on l'active par le flag --yjit ou RUBYOPT="--yjit".
  • Au niveau Rails, depuis la version 7.2, YJIT est activé automatiquement au démarrage.

Au-delà de tenir Ruby et Rails à jour (branches non EOL), le réflexe ops est de scanner les gems contre les vulnérabilités connues avec bundler-audit, qui compare votre Gemfile.lock à la base ruby-advisory-db, hors ligne :

Fenêtre de terminal
gem install bundler-audit
bundle-audit check --update # met à jour la base puis audite

À intégrer en CI pour bloquer un déploiement qui embarque une gem vulnérable. Côté secrets : jamais de master.key dans le dépôt, et SECRET_KEY_BASE / RAILS_MASTER_KEY injectés par l'environnement.

Fenêtre de terminal
ruby -v # version de Ruby + moteur
bundle --version # version de Bundler
bundle check # toutes les dépendances du Gemfile sont-elles satisfaites ?

Sorties réelles sur l'image officielle ruby:3.4 :

ruby 3.4.9 (2026-03-11) +PRISM [x86_64-linux]
Bundler version 2.6.9

YJIT y est disponible : ruby --yjit -e 'puts RubyVM::YJIT.enabled?' renvoie true.

  • Ruby 4.0 est la stable courante, 3.4 le choix sûr en prod ; ne tournez jamais sur une branche EOL (3.2 et avant).
  • Isolez la version avec rbenv et un fichier .ruby-version ; n'utilisez pas le Ruby système.
  • En prod : bundle config set deployment true + without development test, jamais en dev.
  • Puma combine workers (parallélisme CPU, à cause du GVL) et threads (I/O) ; alignez les threads sur le pool de connexions BDD.
  • Déploiement : bundle install, db:migrate, assets:precompile, redémarrage Puma ; secrets par credentials chiffrés (master.key jamais committée).
  • YJIT pour la performance (auto sous Rails 7.2+) ; éviter ZJIT en prod ; auditer les gems avec bundler-audit.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn