Les fichiers.env
sont de plus en plus populaires comme moyen de configurer une application en stockant de manière sécurisée les paramètres de configuration, les variables d'environnement et les informations sensibles. Cette norme peu contraignante offre un certain nombre d'avantages, dont la plupart sont pleinement exploités sur Upsun. Cependant, les fichiers .env
doivent également être utilisés correctement ; une mauvaise utilisation, comme pour toute autre chose, peut être pire que de ne pas les utiliser du tout.
Pour comprendre la meilleure façon d'utiliser les fichiers .env
, il faut d'abord comprendre ce que l'on entend par "environnement".
Quel que soit le langage dans lequel elle est écrite, votre application est en fin de compte une pile de code. Cette pile de code est statique et immuable entre les différents moments et endroits où elle s'exécute.
Cependant, lorsqu'elle s'exécute, elle va s'intéresser à d'autres "choses". Il peut s'agir d'une base de données, d'un serveur de cache, d'un système de fichiers, d'une passerelle d'authentification à distance ou d'un millier d'autres choses. Ces autres "choses" constituent le contexte dans lequel l'application s'exécute. Ou, alternativement, son environnement.
Cet environnement peut être variable. Votre application peut nécessiter un serveur PostgreSQL, mais le serveur PostgreSQL auquel elle se connecte et les données qu'il contient à un moment donné font partie de l'environnement et peuvent changer indépendamment de votre code. Vous voulez que votre application communique avec une passerelle de paiement, mais les informations d'identification qu'elle utilise peuvent varier en fonction du contexte dans lequel vous travaillez. (Intégrer les clés de l'API de paiement de production dans votre application et l'envoyer ensuite à des fins de test a tendance à mal se terminer. Croyez-moi...)
Lors de la création d'une application, il est important d'établir une séparation nette entre "les éléments qui sont les mêmes dans tous les environnements" et "les éléments qui changent dans chaque environnement". Le premier est votre code. Le second est la configuration de votre environnement.
Les systèmes d'exploitation de type Unix disposent depuis des décennies d'un mécanisme permettant de gérer cette configuration spécifique à l'environnement : les variables d'environnement. Les variables d'environnement sont des valeurs de chaînes globales du système que toute application peut lire à tout moment et utiliser pour décider du code à exécuter.
Ce n'est pas la seule façon dont les applications peuvent varier leur comportement, bien sûr. La plupart des applications disposent d'une sorte de "fichier de configuration", qui contient d'autres paramètres susceptibles de modifier le comportement de l'application. Il peut s'agir de fichiers exécutables (PHP, Javascript, Python, etc.) ou non exécutables(YAML, XML, ini, JSON, TOML, etc.), et les détails varient autant que les applications.
), et les détails varient aussi largement que les applications. La distinction importante est que certaines de ces configurations doivent varier avec l'installation de l'application, tandis que d'autres varient avec l'environnement. N'oubliez pas qu'une application donnée peut être exécutée dans plusieurs instances à des fins de test.
Par exemple, si vous créez une application que les utilisateurs peuvent installer et configurer eux-mêmes, le "nom de l'entreprise" pour laquelle l'application est conçue variera en fonction de l'utilisateur qui l'exécute. Mais la base de données à laquelle elle se connecte variera pour chaque instance de l'application exécutée par l'utilisateur. Pensez à la production, aux tests, à l'ordinateur portable local, etc. Ces instances devraient toutes avoir le même nom d'entreprise, mais des identifiants de base de données différents.
C'est la première étape importante : séparer la configuration de votre application par installation (nom de la société) de la configuration par environnement (base de données). En les mettant dans le même fichier, il est beaucoup plus difficile de faire varier la configuration par environnement sans faire varier également la configuration par installation.
Un fichier de configuration exécutable comporte parfois une option dérobée permettant de faire varier l'environnement. Selon la façon dont le fichier est écrit, il peut être possible de le modifier manuellement pour lire certaines valeurs ailleurs : un fichier include supplémentaire, des variables d'environnement, etc. Il s'agit toujours d'un piratage, cependant. Vous voulez être en mesure de mettre la configuration cohérente dans Git, afin que ses changements soient mis à jour à travers toutes les instances, mais pas la configuration spécifique à l'environnement.
C'est là que les variables d'environnement entrent en jeu.
L'endroit idéal pour stocker la configuration spécifique à l'environnement est dans les variables d'environnement. Les mécanismes permettant de les définir sont bien établis. Les API permettant de les lire sont universelles. Même si deux applications différentes n'utilisent pas le même nom de variable, il existe de nombreux moyens simples de définir une variable d'environnement en fonction d'une autre.
Pour la production et les tests, les variables d'environnement constituent donc le meilleur endroit pour gérer la configuration spécifique à l'environnement. Concevez votre application de manière à ce qu'elle les lise directement ou qu'elle dispose d'un fichier de configuration exécutable et modifiable par l'utilisateur, qui peut être modifié pour lire les valeurs de l'environnement plutôt que de les coder directement en dur. De cette façon, lorsque vous déplacez l'application de la production à la mise à l'essai, puis de la mise à l'essai à un environnement spécifique à une branche, vous n'avez qu'à mettre à jour les variables d'environnement pour ces nouveaux environnements et l'application continuera à fonctionner.
L'inconvénient de cette approche concerne toutefois le développement local. Il y a de fortes chances que vous ne souhaitiez pas définir une variable globale sur l'ensemble de votre ordinateur simplement pour indiquer à la copie de développement de votre application les fausses informations d'identification à utiliser ou l'emplacement de votre base de données de test. Même si vous utilisez un environnement conteneurisé localement, vous ne voudrez peut-être pas manipuler directement les variables d'environnement.
C'est là que le fichier .env
entre en jeu. .env
est un standard de facto pour un fichier de type ini qui contient de fausses variables d'environnement. Une application qui prend en charge les fichiers .env
parcourra, au démarrage, chaque ligne de ce fichier et lira les paires clé/valeur
. Pour chacune d'entre elles, elle exécutera la commande suivante : "SI une variable d'environnement portant ce nom n'existe pas encore, définissez-la en fonction de ce fichier". Cela permet de définir la variable uniquement dans le cadre du processus de votre application, sans avoir d'impact sur les autres processus de l'ordinateur. Le reste de votre application peut alors procéder et lire l'environnement comme il le ferait n'importe où ailleurs, en ignorant tout de ce tour de passe-passe. (N'écrivez pas ce code vous-même. Il existe des bibliothèques de support .env
dans tous les langages qui font exactement la même chose. Utilisez l'une d'entre elles).
C'est là, et uniquement là, le but des fichiers .env
: des valeurs qui changent en fonction de l'environnement, et qui ne font donc pas partie de votre base de code. Ce qui nous amène à la chose la plus importante à retenir à propos des fichiers .env
: ils n'ont pas leur place dans Git. Tout ce qui se trouve dans Git sera le même dans chaque environnement, par conception, ce qui est exactement le contraire de ce à quoi servent les variables d'environnement et les fichiers .env
.
Les valeurs qui ne changent pas d'un environnement à l'autre n'ont pas non plus leur place dans un fichier .env
. Le nom du site, l'adresse email de l'administrateur, et ainsi de suite doivent être soit dans un fichier de configuration en lecture seule qui est livré à Git, soit dans la base de données, selon que vous voulez que ces valeurs de configuration soient modifiables par l'utilisateur final. (Mais ces valeurs n'ont pas leur place dans le fichier .env
, car elles ne sont pas spécifiques à l'environnement.
Il arrive que l'on veuille faire varier le code lui-même en fonction de l'environnement. En général, il ne s'agit pas du code source, mais du processus de compilation. Dans un langage compilé (C, Rust, Go, Java, etc.), vous pouvez vouloir laisser des symboles de débogage dans le code compilé en développement mais pas en production. Même dans les langages interprétés(PHP, Javascript, Python, etc.), vous pouvez vouloir compiler votre CSS ou votre Javascript agrégé différemment, en supprimant les espaces blancs uniquement en production pour faciliter le débogage, par exemple.
Cela pose un problème sur Upsun, car par conception, l'étape de compilation est exécutée indépendamment de toute valeur spécifique à l'environnement. En effet, la sortie de la compilation peut être réutilisée dans un environnement différent, comme la production. Plus précisément, dans le cas d'une fusion rapide vers la production, nous n'avons pas besoin de reconstruire votre application. La version construite à partir d'une branche est réutilisée, ce qui signifie que ce que vous testiez dans une branche est exactement les mêmes bits sur le disque que ce qui est déployé en production. C'est la seule façon de minimiser les erreurs du type "fonctionne sur ma branche" et cela fait partie intégrante de l'idée de déploiement conteneurisé.
Mais que se passe-t-il si vous voulez "développer" sur une branche ? C'est là que la convention de nommage des fichiers .env
devient importante. Ne considérez pas les environnements de non-production comme du développement. Le développement est l'endroit où vous écrivez le code, c'est-à-dire votre ordinateur local. Sur votre ordinateur local, vous pouvez définir toutes les variables d'environnement (ou fichiers .env
) que vous souhaitez. Au lieu de considérer chaque branche comme un environnement de développement, considérez chaque branche comme un environnement de mise à l'essai. Cet environnement doit être aussi proche que possible de l'environnement de production, y compris en ce qui concerne les modes de construction.
Vu sous cet angle, il est absurde que le mode de compilation varie en fonction de l'environnement, car cette variation est un lieu d'apparition des heisenbugs. Vous ne voulez pas d'heisenbugs. (Le "mode débogage" doit se produire à l'endroit où vous déboguez et écrivez le code, c'est-à-dire dans votre environnement local.
C'est le seul endroit où vous pouvez, et devriez, utiliser un fichier .env.
Récapitulons :
.env
sont des variables d'environnement de substitution pour le développement local uniquement, mais ne doivent jamais être livrés à Git.