Comment stocker le noeud.paramètres de déploiement js / fichiers de configuration?
j'ai travaillé sur quelques applications nodales, et j'ai été à la recherche d'un bon modèle de stockage des paramètres liés au déploiement. Dans le monde Django (d'où je viens), la pratique courante serait d'avoir un fichier settings.py
contenant les réglages standard (fuseau horaire, etc.), puis un fichier local_settings.py
pour les réglages spécifiques au déploiement, c'est-à-dire. à quelle base de données parler, à quelle socket memcache, adresse e-mail pour les administrateurs et ainsi de suite.
je cherchais similaire les modèles de Nœud. Juste un fichier de configuration serait bien, donc il n'a pas à être bloqué avec tout le reste dans app.js
, mais je trouve qu'il est important d'avoir un moyen d'avoir une configuration spécifique au serveur dans un fichier qui n'est pas sous contrôle source. La même application pourrait bien être déployée sur différents serveurs avec des paramètres très différents, et avoir à faire face à des conflits de fusion et tout ce qui n'est pas mon idée de plaisir.
donc il y a une sorte de cadre/outil pour cela, ou fait tout le monde pirate quelque chose ensemble?
23 réponses
j'utilise un package.json
pour mes paquets et un config.js
pour ma configuration, qui ressemble à:
var config = {};
config.twitter = {};
config.redis = {};
config.web = {};
config.default_stuff = ['red','green','blue','apple','yellow','orange','politics'];
config.twitter.user_name = process.env.TWITTER_USER || 'username';
config.twitter.password= process.env.TWITTER_PASSWORD || 'password';
config.redis.uri = process.env.DUOSTACK_DB_REDIS;
config.redis.host = 'hostname';
config.redis.port = 6379;
config.web.port = process.env.WEB_PORT || 9980;
module.exports = config;
je charge la configuration de mon projet:
var config = require('./config');
et ensuite je peux accéder à mes affaires à partir de config.db_host
, config.db_port
, etc... Cela me permet soit d'utiliser des paramètres codés en dur, ou des paramètres stockés dans des variables environnementales si Je ne veux pas stocker les mots de passe dans le contrôle source.
j'ai aussi générez un package.json
et insérez une section de dépendances:
"dependencies": {
"cradle": "0.5.5",
"jade": "0.10.4",
"redis": "0.5.11",
"socket.io": "0.6.16",
"twitter-node": "0.0.2",
"express": "2.2.0"
}
quand j'ai cloné le projet sur ma machine locale, j'ai lancé npm install
pour installer les paquets. Plus d'informations sur ce ici .
le projet est stocké dans GitHub, avec des télécommandes ajoutées pour mon serveur de production.
vous pouvez demander des fichiers JSON à partir du noeud v0.5.x ( faisant référence à cette réponse )
config.json:
{
"username" : "root",
"password" : "foot"
}
app.js:
var config = require('./config.json');
log_in(config.username, config.password);
beaucoup plus tard, j'ai trouvé un assez bon noeud.module js pour la gestion de la configuration: nconf .
un exemple simple:
var nconf = require('nconf');
// First consider commandline arguments and environment variables, respectively.
nconf.argv().env();
// Then load configuration from a designated file.
nconf.file({ file: 'config.json' });
// Provide default values for settings not provided above.
nconf.defaults({
'http': {
'port': 1337
}
});
// Once this is in place, you can just use nconf.get to get your settings.
// So this would configure `myApp` to listen on port 1337 if the port
// has not been overridden by any of the three configuration inputs
// mentioned above.
myApp.listen(nconf.get('http:port'));
il supporte également le stockage des paramètres dans Redis , l'écriture des fichiers de configuration, et dispose d'une API assez solide, et est également soutenu par l'un des Noeuds les plus respectés.js shops, Nodejitsu , dans le cadre du Flatiron il s'agit d'une initiative-cadre, donc elle devrait être assez résistante à l'avenir.
Check out nconf at github .
ma solution est assez simple:
Charger l'environnement de config ./config / index.js
var env = process.env.NODE_ENV || 'development'
, cfg = require('./config.'+env);
module.exports = cfg;
définit quelques valeurs par défaut ./config / config.mondial.js
var config = module.exports = {};
config.env = 'development';
config.hostname = 'dev.example.com';
//mongo database
config.mongo = {};
config.mongo.uri = process.env.MONGO_URI || 'localhost';
config.mongo.db = 'example_dev';
outrepasse les valeurs par défaut./config / config.test.js
var config = require('./config.global');
config.env = 'test';
config.hostname = 'test.example';
config.mongo.db = 'example_test';
module.exports = config;
./ models / user.js:
var mongoose = require('mongoose')
, cfg = require('../config')
, db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);
lancer votre application dans un environnement de test:
NODE_ENV=test node ./app.js
Ceci est expliqué plus en détail ici: http://www.chovy.com/node-js/managing-config-variables-inside-a-node-js-application /
vous pourriez aussi regarder à dotenv qui suit les principes d'un douze facteurs app .
j'utilisais node-config, mais j'ai créé dotenv pour cette raison. Il a été entièrement inspiré par la bibliothèque dotenv de ruby.
L'Usage est assez facile:
var dotenv = require('dotenv');
dotenv.load();
alors vous créez juste un .env fichier et de mettre vos paramètres comme:
S3_BUCKET=YOURS3BUCKET
SECRET_KEY=YOURSECRETKEYGOESHERE
OTHER_SECRET_STUFF=my_cats_middle_name
C'est dotenv pour nodejs.
vous utilisez npm pour démarrer vos scripts (env etc) ?
si vous utilisez les fichiers .env
vous pouvez les inclure dans votre package.json
et utiliser npm à la source/start.
exemple:
{
"name": "server",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node test.js",
"start-dev": "source dev.env; node test.js",
"start-prod": "source prod.env; node test.js"
},
"dependencies": {
"mysql": "*"
}
}
lancez ensuite les scripts npm:
$ npm start-dev
décrites ici https://gist.github.com/ericelliott/4152984 Tout le crédit à Eric Elliot
vous pouvez aussi regarder node-config qui charge le fichier de configuration en fonction de $HOST et $NODE_ENV variable (un peu comme RoR): documentation .
cela peut être très utile pour différents réglages de déploiement ( development
, test
ou production
).
il suffit de faire une simple settings.js
avec exports
:
exports.my_password = 'value'
ensuite, dans votre script, faites un require
:
var settings = require('./settings.js');
tous vos paramètres maintenant seront disponibles via settings
variable:
settings.my_password // 'value'
Convict est une autre option qui ajoute un schéma pour la validation. Comme nconf, il prend en charge les paramètres de chargement à partir de n'importe quelle combinaison de variables d'environnement, d'arguments, de fichiers et d'objets json.
exemple tiré du README:
var convict = require('convict');
var conf = convict({
env: {
doc: "The applicaton environment.",
format: ["production", "development", "test"],
default: "development",
env: "NODE_ENV"
},
ip: {
doc: "The IP address to bind.",
format: "ipaddress",
default: "127.0.0.1",
env: "IP_ADDRESS",
},
port: {
doc: "The port to bind.",
format: "port",
default: 0,
env: "PORT"
}
});
Article pour commencer: configurations de Taming avec noeud-convict
vous pouvez utiliser Konfig pour les fichiers de configuration spécifiques à l'environnement. Il charge automatiquement les fichiers de configuration JSON ou yaml, il a une valeur par défaut et des fonctionnalités de configuration dynamique.
exemple tiré de Konfig repo:
File: config/app.json
----------------------------
{
"default": {
"port": 3000,
"cache_assets": true,
"secret_key": "7EHDWHD9W9UW9FBFB949394BWYFG8WE78F"
},
"development": {
"cache_assets": false
},
"test": {
"port": 3001
},
"staging": {
"port": #{process.env.PORT},
"secret_key": "3F8RRJR30UHERGUH8UERHGIUERHG3987GH8"
},
"production": {
"port": #{process.env.PORT},
"secret_key": "3F8RRJR30UHERGUH8UERHGIUERHG3987GH8"
}
}
en développement:
> config.app.port
3000
dans la production, supposons que nous commençons l'application avec $ NODE_ENV=production PORT=4567 node app.js
> config.app.port
4567
plus de détails: https://github.com/vngrs/konfig
je vais jeter mon chapeau dans le ring ici parce qu'aucune de ces réponses traitent de tous les composants critiques dont à peu près tous les systèmes ont besoin. Considérations:
- Public de configuration (qui peut être vu par le frontend) vs privé de configuration (guy mograbi a obtenu ce droit). Et s'assurer que ces sont séparés.
- Secrets comme les touches
- par défaut vs dérogations spécifiques à l'environnement
- Frontend bundles
Voici comment je fais ma configuration:
-
config.default.private.js
- dans le contrôle de version, ce sont des options de configuration par défaut qui ne peuvent être vues que par votre arrière-plan. -
config.default.public.js
- dans le contrôle de version, ce sont des options de configuration par défaut qui peuvent être vues par backend et frontend -
config.dev.private.js
- si vous avez besoin de différents paramètres privés par défaut pour dev. -
config.dev.public.js
- si vous avez besoin de différentes valeurs par défaut pour dev. -
config.private.js
- pas dans le contrôle de version, ce sont des options spécifiques à l'environnement qui outrepassentconfig.default.private.js
-
config.public.js
- pas dans le contrôle de version, ce sont des options spécifiques à l'environnement qui outrepassentconfig.default.public.js
-
keys/
- un dossier où chaque fichier stocke un différent le secret d'une certaine sorte. Ce n'est pas non plus sous contrôle de version (les clés ne devraient jamais être sous contrôle de version).
j'utilise de vieux fichiers javascript pour la configuration afin d'avoir la pleine puissance du langage javascript (y compris les commentaires et la capacité de faire des choses comme charger le fichier de configuration par défaut dans le fichier spécifique à l'environnement afin qu'ils puissent être dépassés). Si vous souhaitez utiliser des variables d'environnement, vous pouvez les charger à l'intérieur de ces fichiers de configuration (quoique je déconseillé d'utiliser envvars pour la même raison que je ne recommande pas d'utiliser les fichiers json - vous n'avez pas la puissance d'un langage de programmation pour construire votre configuration).
la raison pour laquelle chaque clé est dans un fichier séparé est pour l'utilisation par l'installateur. Cela vous permet d'avoir un installateur qui crée les clés sur la machine et les stocke dans le dossier des clés. Sans cela, votre installateur pourrait échouer lorsque vous chargez votre fichier de configuration qui ne peut pas accéder à vos clés. De cette façon, vous pouvez traverser la répertorier et charger les fichiers clés qui sont dans ce dossier sans avoir à se soucier de ce qui existe et ce qui n'existe pas dans une version donnée de votre code.
puisque vous avez probablement des clés chargées dans votre configuration privée, vous certainement ne voulez pas charger votre configuration privée dans un code frontal. Alors que son probablement strictement plus idéal pour séparer complètement votre base de code frontend de votre arrière-plan, beaucoup de fois que PITA est un assez grand barrière pour empêcher les gens de le faire,donc config privée vs publique. Mais il y a deux choses que je fais pour éviter que private config ne soit chargé dans le frontend:
- j'ai un test unitaire qui garantit que mes paquets frontend ne contiennent pas une des clés secrètes que j'ai dans la config privée.
- j'ai mon code frontend dans un dossier différent de mon code backend, et j'ai deux fichiers différents nommés" config.js" - un pour chaque extrémité. Pour le backend, config.js charge la config privée, pour frontend, il charge la config publique. Ensuite, vous avez toujours besoin de ('config') et ne vous inquiétez pas d'où il vient.
une dernière chose: votre configuration doit être chargée dans le navigateur via un complètement fichier séparé que l'un de vos autres codes frontend. Si vous regroupez votre code frontend, la configuration publique doit être construite comme un ensemble complètement séparé. Sinon, votre config n'est pas vraiment config plus - son juste une partie de votre code. Config doit pouvoir être différent sur différentes machines.
je vais créer un dossier comme config un fichier nommé config.js
et plus tard j'utiliserai ce fichier là où requis comme ci-dessous
exemple de configuration.js
module.exports = {
proxyURL: 'http://url:port',
TWITTER: {
consumerkey: 'yourconsumerkey',
consumerSecrete: 'yourconsumersecrete'
},
GOOGLE: {
consumerkey: 'yourconsumerkey',
consumerSecrete: 'yourconsumersecrete'
},
FACEBOOK: {
consumerkey: 'yourconsumerkey',
consumerSecrete: 'yourconsumersecrete'
}
}
alors si je veux utiliser ce fichier de configuration quelque part
je vais d'abord importer comme ci-dessous
var config = require('./config');
et je peux accéder aux valeurs comme ci-dessous
const oauth = OAuth({
consumer: {
key: config.TWITTER.consumerkey,
secret: config.TWITTER.consumerSecrete
},
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return crypto.createHmac('sha1', key).update(base_string).digest('base64');
}
});
je suis un peu en retard dans le jeu, mais je ne pouvais pas trouver ce dont j'avais besoin ici - ou ailleurs - donc j'ai écrit quelque chose moi-même.
mes exigences pour un mécanisme de configuration sont les suivantes:
- Support frontal. Quel est le but si le front-end ne peut pas utiliser la configuration?
- Support
settings-overrides.js
- qui ressemble au même mais permet des dérogations de configuration àsettings.js
. L'idée est ici est de modifier la configuration facilement sans changer le code. Je le trouve utile pour saas.
même si je me soucie moins des environnements de soutien - la volonté expliquer comment l'ajouter facilement à ma solution
var publicConfiguration = {
"title" : "Hello World"
"demoAuthToken" : undefined,
"demoUserId" : undefined,
"errorEmail" : null // if null we will not send emails on errors.
};
var privateConfiguration = {
"port":9040,
"adminAuthToken":undefined,
"adminUserId":undefined
}
var meConf = null;
try{
meConf = require("../conf/dev/meConf");
}catch( e ) { console.log("meConf does not exist. ignoring.. ")}
var publicConfigurationInitialized = false;
var privateConfigurationInitialized = false;
function getPublicConfiguration(){
if (!publicConfigurationInitialized) {
publicConfigurationInitialized = true;
if (meConf != null) {
for (var i in publicConfiguration) {
if (meConf.hasOwnProperty(i)) {
publicConfiguration[i] = meConf[i];
}
}
}
}
return publicConfiguration;
}
function getPrivateConfiguration(){
if ( !privateConfigurationInitialized ) {
privateConfigurationInitialized = true;
var pubConf = getPublicConfiguration();
if ( pubConf != null ){
for ( var j in pubConf ){
privateConfiguration[j] = pubConf[j];
}
}
if ( meConf != null ){
for ( var i in meConf ){
privateConfiguration[i] = meConf[i];
}
}
}
return privateConfiguration;
}
exports.sendPublicConfiguration = function( req, res ){
var name = req.param("name") || "conf";
res.send( "window." + name + " = " + JSON.stringify(getPublicConfiguration()) + ";");
};
var prConf = getPrivateConfiguration();
if ( prConf != null ){
for ( var i in prConf ){
if ( prConf[i] === undefined ){
throw new Error("undefined configuration [" + i + "]");
}
exports[i] = prConf[i];
}
}
return exports;
explication
-
undefined
cette propriété est requise." -
null
signifie qu'il est facultatif -
meConf
- actuellement, le code est la cible d'un fichier sousapp
.meConf
est le fichier overrides qui est ciblé surconf/dev
- qui est ignoré par mon vcs. -
publicConfiguration
- sera visible de l'avant et de l'arrière. -
privateConfiguration
- sera visible de l'arrière seulement. -
sendPublicConfiguration
- une route qui exposera la configuration publique et l'assignera à une variable globale. Par exemple, le le code ci-dessous exposera la configuration publique en tant que variable globale myConf dans la partie frontale. Par défaut, il utilisera le nom de la variable globaleconf
.app.get ("/backend/conf", require ("conf").sendPublicConfiguration);
logique des dérogations
- privateConfiguration est fusionné avec publicConfiguration et puis meConf.
- publicConfiguration vérifie chaque clé si elle a une surpassement, et utilise cette surpassement. De cette façon, nous n'exposons rien de privé.
ajout de soutien à l'environnement
même si Je ne trouve pas utile de" support environnemental", peut-être que quelqu'un le fera.
pour ajouter le support d'environnement, vous devez changer l'instruction require meConf en quelque chose comme ceci (pseudo-code)
si ( environnement = production" ) { meConf = require ("../ conf / dev / meConf").production; }
si ( environnement == "développement" ) { meConf = require ("../ conf / dev / meConf").développement; }
de même, vous pouvez avoir un fichier par Environnement
meConf.development.js
meConf.production.js
et importer le bon. Le reste de la logique reste la même.
un exemple alt que je viens d'utiliser parce que je voulais plus de flexibilité qu'un typique .fichier json, mais ne voulais pas qu'il disparaît dans une bibliothèque qui nécessiterait une dépendance est quelque chose comme cela. Essentiellement, exporter une fonction invoquée immédiatement qui renvoie un objet avec des valeurs que je voulais définir. Donne beaucoup de flexibilité.
module.exports = function(){
switch(node_env){
case 'dev':
return
{ var1 = 'development'};
}
}();
il y a une bien meilleure explication avec un exemple complet ici. utilisant des fichiers de configuration dans Node.js
je sais que c'est un très vieux post. Mais je veux partager mon module pour configurer les variables d'environnement, je pense qu'il est solution très flexible. Voici le module JSON-configurateur
var configJson = {
'baseUrl': 'http://test.com',
'$prod_baseUrl': 'https://prod.com',
'endpoints': {
'users': '<%= baseUrl %>/users',
'accounts': '<%= baseUrl %>/accounts'
},
foo: 'bar',
foobar: 'foobar',
$prod_foo: 'foo in prod',
$test_foo: 'foo in test',
deep:{
veryDeep: {
publicKey: 'abc',
secret: 'secret',
$prod_secret: 'super secret'
}
}
};
var config = require('json-configurator')(configJson, 'prod');
console.log(config.deep.veryDeep.secret)
// super secret
console.log(config.endpoints.users)
// https://prod.com/users
, Alors vous pouvez utiliser process.env.NODE_ENV
pour obtenir toutes les variables de votre environnement.
en plus du module nconf mentionné dans cette réponse , et noeud-config mentionné dans cette réponse , Il ya aussi noeud-iniparser et IniReader , qui semblent être plus simples .analyseurs de fichiers de configuration ini.
je viens de sortir un petit module pour charger n'importe quel type de fichiers de configuration. C'est assez simple, vous pouvez vérifier à https://github.com/flesler/config-node
vous pouvez utiliser pconf: https://www.npmjs.com/package/pconf
exemple:
var Config = require("pconf");
var testConfig = new Config("testConfig");
testConfig.onload = function(){
testConfig.setValue("test", 1);
testConfig.getValue("test");
//testConfig.saveConfig(); Not needed
}
il est préférable de séparer 'développement' et 'production' configs.
j'utilise la manière suivante: Voici mon config / index.js fichier:
const config = {
dev : {
ip_address : '0.0.0.0',
port : 8080,
mongo :{
url : "mongodb://localhost:27017/story_box_dev",
options : ""
}
},
prod : {
ip_address : '0.0.0.0',
port : 3000,
mongo :{
url : "mongodb://localhost:27017/story_box_prod",
options : ""
}
}
}
Pour exiger la config suivante:
const config = require('../config')[process.env.NODE_ENV];
que vous pouvez utiliser votre objet de configuration:
const ip_address = config.ip_address;
const port = config.port;
pour ceux qui visitent ce vieux fil, voici un paquet que je trouve bon.
j'ai essayé quelques-unes des solutions suggérées ici, mais n'a pas été sattisfié avec eux, donc j'ai créé mon propre module. Il est appelé mikro-config
et la principale différence est qu'il honore la convention sur la configuration, donc vous pouvez juste exiger le module et commencer à l'utiliser.
vous stockez votre configuration dans des fichiers JS ou json du dossier /config
. D'abord il charge le fichier default.js
, puis tous les autres fichiers du répertoire /config
, puis il charge configuration spécifique à l'environnement basée sur la variable $NODE_ENV
.
il permet également de modifier cette configuration pour le développement local avec local.js
ou /config/env/$NODE_ENV.local.js
spécifique à l'environnement .
, Vous pouvez prendre à la regarder ici:
Pendant longtemps, j'ai utilisé l'approche mentionné dans la solution ici. Toutefois, la sécurité des secrets dans un texte clair suscite des inquiétudes. Vous pouvez utiliser un autre paquet sur le dessus de config
de sorte que les bits de sécurité sont prises en charge.
Check this out: https://www.attosol.com/secure-application-secrets-using-masterkey-in-azure-key-vault /
il suffit d'utiliser npm
module config
(plus de 300000 téléchargements)
https://www.npmjs.com/package/config
Node-config organise des configurations hiérarchiques pour vos déploiements d'applications.
permet de définir un ensemble de paramètres par défaut, et de les étendre pour différents environnements de déploiement (développement, qa, staging, production, etc.).
$ npm install config
$ mkdir config
$ vi config/default.json
{
// Customer module configs
"Customer": {
"dbConfig": {
"host": "localhost",
"port": 5984,
"dbName": "customers"
},
"credit": {
"initialLimit": 100,
// Set low for development
"initialDays": 1
}
}
}
$ vi config/production.json
{
"Customer": {
"dbConfig": {
"host": "prod-db-server"
},
"credit": {
"initialDays": 30
}
}
}
$ vi index.js
var config = require('config');
//...
var dbConfig = config.get('Customer.dbConfig');
db.connect(dbConfig, ...);
if (config.has('optionalFeature.detail')) {
var detail = config.get('optionalFeature.detail');
//...
}
$ export NODE_ENV=production
$ node index.js