Si vous voulez pouvoir gérer efficacement les apps web en développement et en production, vous devez comprendre les variables d’environnement.

Ce n’était pas toujours le cas. Il y a quelques années seulement, presque personne ne configurait ses apps Rails avec des variables d’environnement. Mais Heroku est arrivé.

Heroku a fait découvrir aux développeurs l’approche des apps à 12 facteurs. Dans leur manifeste des apps à 12 facteurs, ils exposent un grand nombre de leurs meilleures pratiques pour créer des apps faciles à déployer. La section sur les variables d’environnement a été particulièrement influente.

L’app à douze facteurs stocke la configuration dans des variables d’environnement (souvent abrégées en env vars ou env). Les env vars sont faciles à modifier entre les déploiements sans modifier le code ; contrairement aux fichiers de configuration, il y a peu de chance qu’ils soient vérifiés dans le repo du code par accident ; et contrairement aux fichiers de configuration personnalisés, ou à d’autres mécanismes de configuration tels que les propriétés système de Java, ils constituent un standard agnostique de langage et de système d’exploitation.

Plus de Rubyistes que jamais utilisent les variables d’environnement. Mais c’est souvent d’une manière cargocentrique. Nous utilisons ces choses sans vraiment comprendre comment elles fonctionnent.

Ce post vous montrera comment les variables d’environnement fonctionnent vraiment – et peut-être plus important encore, comment elles NE fonctionnent PAS. Nous allons également explorer certaines des façons les plus courantes de gérer les variables d’environnement dans vos applications Rails. Commençons !

NOTE : Vous pouvez lire sur la sécurisation des variables d’environnement ici.

Chaque processus a son propre ensemble de variables d’environnement

Chaque programme que vous exécutez sur votre serveur a au moins un processus. Ce processus obtient son propre ensemble de variables d’environnement. Une fois qu’il les a, rien en dehors de ce processus ne peut les modifier.

Une erreur compréhensible que les débutants font est de penser que les variables d’environnement sont en quelque sorte à l’échelle du serveur. Des services comme Heroku donnent certainement l’impression que la définition des variables d’environnement est l’équivalent de l’édition d’un fichier de configuration sur le disque. Mais les variables d’environnement n’ont rien à voir avec les fichiers de configuration.

Chaque programme que vous exécutez sur votre serveur obtient son propre ensemble de variables d’environnement au moment où vous le lancez.

Chaque processus a son propre environnement. Chaque processus a son propre environnement.

Les variables d’environnement meurent avec leur processus

Vous avez déjà défini une variable d’environnement, redémarré et constaté qu’elle avait disparu ? Puisque les variables d’environnement appartiennent aux processus, cela signifie que chaque fois que le processus quitte, votre variable d’environnement disparaît.

Vous pouvez le constater en définissant une variable d’environnement dans une session IRB, en la fermant et en essayant d’accéder à la variable dans une 2e session irb.

Lorsqu'un processus s'arrête, ses variables d'environnement sont perduesLorsqu’un processus s’arrête, ses variables d’environnement sont perdues

C’est le même principe qui fait que vous perdez les variables d’environnement lorsque votre serveur redémarre, ou lorsque vous quittez votre shell. Si vous voulez qu’elles persistent à travers les sessions, vous devez les stocker dans une sorte de fichier de configuration comme .bashrc .

Un processus obtient ses variables d’environnement de son parent

Chaque processus a un parent. C’est parce que chaque programme doit être lancé par un autre programme.

Si vous utilisez votre shell bash pour lancer vim, alors le parent de vim est le shell. Si votre application Rails utilise imagemagick pour identifier une image, alors le parent du programme identify sera votre application Rails.

Les processus enfants héritent des env vars de leur parentLes processus enfants héritent des env vars de leur parent

Dans l’exemple ci-dessous, je fixe la valeur de la variable d’environnement $MARCO dans mon processus IRB. Ensuite, j’utilise des back-ticks pour shell out et faire écho à la valeur de cette variable.

Puisque IRB est le processus parent du shell que je viens de créer, il obtient une copie de la variable d’environnement $MARCO.

Les variables d'environnement définies en Ruby sont héritées par les processus enfantsLes variables d’environnement définies en Ruby sont héritées par les processus enfants

Les parents peuvent personnaliser les variables d’environnement envoyées à leurs enfants

Par défaut, un enfant obtient des copies de toutes les variables d’environnement dont dispose son parent. Mais le parent a le contrôle sur cela.

Depuis la ligne de commande, vous pouvez utiliser le programme env. Et dans bash, il y a une syntaxe spéciale pour définir les vars env sur l’enfant sans les définir sur le parent.

Utiliser la commande env pour définir les variables d'environnement pour un enfant sans les définir sur le parent Utiliser la commande env pour définir les variables d’environnement pour un enfant sans les définir sur le parent

Si vous shelez depuis l’intérieur de Ruby, vous pouvez également fournir des variables d’environnement personnalisées au processus enfant sans encombrer votre hachage ENV. Utilisez simplement la syntaxe suivante avec la méthode system:

Comment passer des variables d'environnement personnalisées dans la méthode système de Ruby Comment passer des variables d’environnement personnalisées dans la méthode système de Ruby

Les enfants ne peuvent pas définir les variables d’environnement de leurs parents

Puisque les enfants n’obtiennent que des copies des variables d’environnement de leurs parents, les changements effectués par l’enfant n’ont aucun effet sur le parent.

Les variables dLes variables d’environnement sont « passées par valeur » et non « par référence »

Ici, nous utilisons la syntaxe back-tick pour shell out et essayer de définir une variable d’environnement. Alors que la variable sera définie pour l’enfant, la nouvelle valeur ne remonte pas jusqu’au parent.

Les processus enfants ne peuvent pas modifier les vars env de leurs parentsLes processus enfants ne peuvent pas modifier les vars env de leurs parents

Les modifications de l’environnement ne sont pas synchronisées entre les processus en cours d’exécution

Dans l’exemple ci-dessous, j’exécute deux copies d’IRB côte à côte. L’ajout d’une variable à l’environnement d’une session IRB n’a aucun effet sur l’autre session IRB.

L'ajout d'une variable d'environnement à un processus ne le modifie pas pour les autres processus L’ajout d’une variable d’environnement à un processus ne le modifie pas pour les autres processus

Votre shell n’est qu’une interface utilisateur pour le système de variables d’environnement.

Le système lui-même fait partie du noyau de l’OS. Cela signifie que le shell n’a pas de pouvoir magique sur les variables d’environnement. Il doit suivre les mêmes règles que tous les autres programmes que vous exécutez.

Les variables d’environnement ne sont PAS les mêmes que les variables de l’interpréteur de commandes

L’un des plus grands malentendus se produit parce que les interpréteurs de commandes fournissent leurs propres systèmes de variables d’interpréteur de commandes « locales ». La syntaxe pour utiliser les variables locales est souvent la même que pour les variables d’environnement. Et les débutants confondent souvent les deux.

Mais les variables locales ne sont pas copiées sur les enfants.

Les variables d'environnement ne sont pas les mêmes que les variables de shell Les variables d’environnement ne sont pas les mêmes que les variables de shell

Regardons un exemple. Tout d’abord, je définis une variable locale de l’interpréteur de commandes nommée MARCO. Comme il s’agit d’une variable locale, elle n’est pas copiée dans les processus enfants. Par conséquent, lorsque j’essaie de l’imprimer via Ruby, cela ne fonctionne pas.

Puis, j’utilise la commande export pour convertir la variable locale en variable d’environnement. Maintenant, elle est copiée dans chaque nouveau processus que ce shell crée. Maintenant la variable d’environnement est disponible pour Ruby.

Les variables locales ne sont pas disponibles pour les processus enfants. L'exportation convertit la variable locale en variable d'environnement. Les variables locales ne sont pas disponibles pour les processus enfants. L’exportation convertit la variable locale en une variable d’environnement.

Gestion des variables d’environnement en pratique

Comment tout cela fonctionne-t-il dans le monde réel ? Faisons un exemple :

Supposons que vous avez deux applications Rails en cours d’exécution sur un seul ordinateur. Vous utilisez Honeybadger pour surveiller ces apps à la recherche d’exceptions. Mais vous avez rencontré un problème.

Vous aimeriez stocker votre clé API Honeybadger dans la variable d’environnement $HONEYBADGER_API_KEY. Mais vos deux applications ont deux clés API distinctes.

Comment une variable d’environnement peut-elle avoir deux valeurs différentes ?

J’espère maintenant que vous connaissez la réponse. Puisque les env vars sont par processus, et que mes deux applications rails sont exécutées dans des processus différents, il n’y a aucune raison pour qu’elles ne puissent pas avoir chacune leur propre valeur pour $HONEYBADGER_API_KEY.

Maintenant la seule question est de savoir comment le configurer. Heureusement, il existe quelques gemmes qui rendent cela très facile.

Figaro

Lorsque vous installez la gemme Figaro dans votre application Rails, toutes les valeurs que vous entrez dans config/application.yml seront chargées dans le hash ENV de ruby au démarrage.

Vous installez simplement la gemme:

# Gemfilegem "figaro"

Et commencez à ajouter des éléments à application.yml. Il est très important que vous ajoutiez ce fichier à votre .gitignore, afin de ne pas commettre accidentellement vos secrets.

# config/application.ymlHONEYBADGER_API_KEY: 12345

Dotenv

La gemme dotenv est très similaire à Figaro, sauf qu’elle charge les variables d’environnement depuis .env, et qu’elle n’utilise pas YAML.

Il suffit d’installer la gemme :

# Gemfilegem 'dotenv-rails'

Et d’ajouter vos valeurs de configuration à .env – et assurez-vous que vous ignorez git le fichier afin de ne pas le publier accidentellement sur github.

HONEYBADGER_API_KEY=12345

Vous pouvez ensuite accéder aux valeurs dans votre hachage Ruby ENV

ENV

Vous pouvez également exécuter des commandes dans le shell avec votre ensemble prédéfini de vars env comme ceci:

dotenv ./my_script.sh

Secrets.yml?

Désolé. Secrets.yml – bien que cool – ne définit pas les variables d’environnement. Ce n’est donc pas vraiment un remplacement pour des gems comme Figaro et dotenv.

Plain old Linux

Il est également possible de maintenir des ensembles uniques de variables d’environnement par app en utilisant des commandes linux de base. Une approche consiste à faire en sorte que chaque application tournant sur votre serveur soit détenue par un utilisateur différent. Vous pouvez alors utiliser le .bashrc de l’utilisateur pour stocker les valeurs spécifiques à l’application.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.