web-dev-qa-db-fra.com

Comment stocker les paramètres de déploiement / fichiers de configuration de Node.js?

J'ai travaillé sur quelques Node applications et je cherchais un bon modèle de stockage des paramètres liés au déploiement. Dans le monde Django (d'où je viens), la pratique habituelle est d'avoir un fichier settings.py contenant les paramètres standard (fuseau horaire, etc.), puis un local_settings.py pour paramètres spécifiques au déploiement, c.-à-d. quelle base de données à qui parler, quel socket memcache, adresse e-mail pour les administrateurs, etc.

Je cherchais des modèles similaires pour Node. Juste un fichier de configuration serait agréable, il ne doit donc pas être coincé avec tout le reste dans app.js, mais j'estime qu'il est important d'avoir un moyen d'avoir une configuration spécifique au serveur dans un fichier qui n'est pas dans le source contrôle. La même application pourrait bien être déployée sur différents serveurs avec des paramètres très différents et devoir faire face à des conflits de fusion et tout ce qui n’est pas mon idée du plaisir.

Y a-t-il une sorte de cadre/outil pour cela, ou est-ce que tout le monde pirate quelque chose ensemble?

608
mikl

Beaucoup plus tard, j'ai trouvé un très bon module Node.js pour gérer 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 prend également en charge le stockage des paramètres dans Redis , l'écriture de fichiers de configuration, et possède une API assez solide. Il est également soutenu par l'un des magasins les plus respectés de Node.js, Nodejits =, dans le cadre de l’initiative-cadre Flatiron , il devrait donc être assez évolutif.

Départ nconf sur Github .

189
mikl

J'utilise un package.json pour mes paquets et un config.js pour ma configuration, qui ressemble à ceci:

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 depuis mon projet:

var config = require('./config');

et puis je peux accéder à mes affaires à partir de config.db_Host, config.db_port, etc ... Cela me permet d'utiliser des paramètres codés en dur ou des paramètres stockés dans des variables d'environnement si je ne souhaite pas stocker de mots de passe dans le contrôle de source .

Je génère également un package.json et insère 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"
}

Lorsque je clone le projet sur ma machine locale, je lance npm install pour installer les packages. Plus d'informations à ce sujet ici .

Le projet est stocké dans GitHub, avec des télécommandes ajoutées pour mon serveur de production.

741
noli

Vous pouvez exiger des fichiers JSON à partir de Node 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);
233
TinyTimZamboni

Ma solution est assez simple:

Chargez la configuration de l'environnement dans ./config/index.js

var env = process.env.NODE_ENV || 'development'
  , cfg = require('./config.'+env);

module.exports = cfg;

Définir des valeurs par défaut dans ./config/config.global.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';

Remplacer les valeurs par défaut dans ./config/config.test.js

var config = require('./config.global');

config.env = 'test';
config.hostname = 'test.example';
config.mongo.db = 'example_test';

module.exports = config;

Utilisation dans ./models/user.js:

var mongoose = require('mongoose')
, cfg = require('../config')
, db = mongoose.createConnection(cfg.mongo.uri, cfg.mongo.db);

Exécution de 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/

86
chovy

Vous pourriez aussi regarder dotenv qui suit les principes d'un application à douze facteurs .

J'avais l'habitude d'utiliser node-config, mais j'ai créé dotenv pour cette raison. Il a été complètement inspiré par la bibliothèque dotenv de Ruby.

L'utilisation est assez facile:

var dotenv = require('dotenv');
dotenv.load();

Ensuite, il vous suffit de créer un fichier .env et de définir vos paramètres comme suit:

S3_BUCKET=YOURS3BUCKET
SECRET_KEY=YOURSECRETKEYGOESHERE
OTHER_SECRET_STUFF=my_cats_middle_name

C'est dotenv pour nodejs.

32
scottmotte

Est-ce que vous utilisez npm pour lancer vos scripts (env, etc.)?

Si vous utilisez des fichiers .env, vous pouvez les inclure dans votre package.json et utiliser npm pour les générer/les démarrer.

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": "*"
  }
}

puis exécutez les scripts npm:

$ npm start-dev

Son décrit ici https://Gist.github.com/ericelliott/4152984 Tout crédit à Eric Elliot

30
lxx

Vous pouvez également rechercher 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 paramètres de déploiement (development, test ou production).

22
ngryman

Il suffit de faire un simple settings.js avec exports:

exports.my_password = 'value'

Puis, dans votre script, faites un require:

var settings = require('./settings.js');

Tous vos réglages seront maintenant disponibles via settings variable:

settings.my_password // 'value'
20
Vanuan

Je vais me lancer dans l’affrontement car aucune de ces réponses ne tient compte de tous les composants essentiels dont tout système a besoin. Considérations:

  • Configuration publique (visible par le frontend) vs configuration privée (c'est ce que mograbi a donné). Et en veillant à ce qu'ils soient séparés.
  • Des secrets comme des clés
  • Valeurs par défaut vs remplacements spécifiques à l'environnement
  • Bundles Frontend

Voici comment je fais ma configuration:

  • config.default.private.js - Dans le contrôle de version, il s'agit d'options de configuration par défaut qui ne peuvent être vues que par votre backend.
  • config.default.public.js - Dans le contrôle de version, il s'agit d'options de configuration par défaut visibles par le serveur et le client
  • config.dev.private.js - Si vous avez besoin de valeurs par défaut privées différentes pour dev.
  • config.dev.public.js - Si vous avez besoin de valeurs par défaut publiques différentes pour dev.
  • config.private.js - Pas dans le contrôle de version, ce sont des options spécifiques à l'environnement qui remplacent config.default.private.js
  • config.public.js - Pas dans le contrôle de version, ce sont des options spécifiques à l'environnement qui remplacent config.default.public.js
  • keys/ - Un dossier dans lequel chaque fichier stocke un type de secret différent. Ce n'est pas non plus sous contrôle de version (les clés ne doivent jamais être sous contrôle de version).

J'utilise des fichiers javascript ordinaires pour la configuration afin de disposer de toute la puissance de la langue javascript (y compris des commentaires et la possibilité d'effectuer des opérations telles que le chargement du fichier de configuration par défaut dans le fichier spécifique à l'environnement afin de pouvoir ensuite être remplacé). Si vous souhaitez utiliser des variables d'environnement, vous pouvez les charger dans ces fichiers de configuration (mais je vous déconseille d'utiliser env. Vars pour la même raison. Je vous déconseille d'utiliser des fichiers json. Vous n'avez pas le pouvoir de créer un langage de programmation. votre config).

La raison pour laquelle chaque clé est dans un fichier séparé est destinée à être utilisée par l'installateur. Cela vous permet d'avoir un programme d'installation qui crée des clés sur la machine et les stocke dans le dossier des clés. Sans cela, votre programme d'installation peut échouer lorsque vous chargez votre fichier de configuration qui ne peut pas accéder à vos clés. De cette façon, vous pouvez parcourir le répertoire et charger tous les fichiers de clé qui se trouvent dans ce dossier sans vous soucier de ce qui existe ou non dans une version donnée de votre code.

Puisque vous avez probablement des clés chargées dans votre configuration privée, vous ne voulez certainement pas charger votre configuration privée dans aucun code frontal. Bien que son probablement strictement plus idéal pour séparer complètement votre base de code frontend de votre backend, souvent, PITA est une barrière assez grande pour empêcher les gens de le faire, donc config privé vs public. Mais il y a deux choses que je fais pour éviter que la configuration privée ne soit chargée dans l'interface:

  1. J'ai un test unitaire qui m'assure que mes paquets frontaux ne contiennent pas l'une des clés secrètes que j'ai dans la configuration privée.
  2. J'ai le code de l'interface utilisateur dans un dossier différent de celui de l'arrière-plan et j'ai deux fichiers différents nommés "config.js", un pour chaque extrémité. Pour backend, config.js charge la configuration privée, pour frontend, il charge la configuration publique. Ensuite, vous devez toujours juste ('config') et ne vous inquiétez pas pour savoir d'où ça vient.

Une dernière chose: votre configuration devrait être chargée dans le navigateur via un fichier complètement distinct de tout autre code frontal. Si vous associez votre code frontal, la configuration publique doit être générée comme un ensemble complètement séparé. Sinon, votre configuration n'est plus vraiment une configuration - c'est juste une partie de votre code. La configuration doit pouvoir être différente sur différentes machines.

12
B T

Vous pouvez utiliser Konfig pour les fichiers de configuration spécifiques à l’environnement. Il charge automatiquement les fichiers de configuration json ou yaml, il possède des fonctions de valeur par défaut et de configuration dynamique.

Un exemple tiré du référentiel Konfig:

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

En 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

11
Ali Davut

Convict est une autre option qui ajoute un schéma pour la validation. Comme nconf, il prend en charge le chargement des paramètres à partir de n’importe quelle combinaison de variables d’environnement, d’arguments, de fichiers et d’objets json.

Exemple tiré du fichier 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 de mise en route: Configurations matricielles avec node-convict

11
hurrymaplelad

Je vais créer un dossier comme fichier de configuration avec le nom config.js et plus tard, j'utiliserai ce fichier chaque fois que nécessaire, comme indiqué ci-dessous.

Exemple de config.js

module.exports = {
    proxyURL: 'http://url:port',
    Twitter: {
        consumerkey: 'yourconsumerkey',
        consumerSecrete: 'yourconsumersecrete'
    },
    GOOGLE: {
        consumerkey: 'yourconsumerkey',
        consumerSecrete: 'yourconsumersecrete'
    },
    FACEBOOK: {
        consumerkey: 'yourconsumerkey',
        consumerSecrete: 'yourconsumersecrete'
    }
}

Ensuite, 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 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');
    }
});
8
Ron

Il est préférable de séparer 'développement' et 'production' configs.

J'utilise la manière suivante: Voici mon fichier config/index.js:

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 requérir l'utilisation de la configuration suivante:

const config = require('../config')[process.env.NODE_ENV];

Alors vous pouvez utiliser votre objet config:

const ip_address = config.ip_address;
const port = config.port;
4
Aram Manukyan

Utilisez simplement le module npm _ config (plus de 300 000 téléchargements).

https://www.npmjs.com/package/config

Node-config organise les configurations hiérarchiques pour les déploiements de vos applications.

Il vous 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, transfert, 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
4
аlex dykyі

un exemple alt que je viens d'utiliser parce que je voulais plus de flexibilité qu'un fichier .json typique, mais que je ne voulais pas qu'il soit abstrait dans une bibliothèque qui nécessiterait une dépendance, c'est quelque chose comme ceci. En gros, l’exportation d’une fonction appelée immédiatement renvoyait un objet avec les 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. tilisation des fichiers de configuration dans Node.js

3
captainavi

Je sais que c'est un très vieux post. Mais je veux partager mon module pour configurer les variables d'environnement, je pense que c'est une solution très flexible. Voici le module json-configurator

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 

Ensuite, vous pouvez utiliser process.env.NODE_ENV pour obtenir toutes les variables de votre environnement.

3
Christian

Je suis un peu en retard dans le jeu, mais je ne trouvais pas ce dont j'avais besoin ici - ou ailleurs - alors j'ai écrit quelque chose moi-même.

Mes exigences pour un mécanisme de configuration sont les suivantes:

  1. Soutien front-end. Quel est le point si le front-end ne peut pas utiliser la configuration?
  2. Support settings-overrides.js - qui a la même apparence mais permet le remplacement de la configuration à settings.js. L'idée ici est de modifier facilement la configuration sans changer le code. Je trouve cela utile pour les saas.

Même si je me soucie moins des environnements de support, cela explique 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 signifie que cette propriété est requise
  • null signifie que c'est optionnel
  • meConf - actuellement le code est ciblé sur un fichier sous app. meConf correspond aux fichiers de substitution ciblés sur conf/dev - qui est ignoré par mes vcs.
  • publicConfiguration - sera visible depuis le début et la fin.
  • privateConfiguration - sera visible uniquement du back-end.
  • sendPublicConfiguration - une route qui exposera la configuration publique et l'attribuera à une variable globale. Par exemple, le code ci-dessous exposera la configuration publique en tant que variable globale myConf dans l'interface frontale. Par défaut, il utilisera le nom de variable globale conf.

    app.get ("/ backend/conf", require ("conf"). sendPublicConfiguration);

Logique des dérogations

  • privateConfiguration est fusionné avec publicConfiguration, puis meConf.
  • publicConfiguration vérifie chaque clé si elle a un remplacement, et utilise ce remplacement. De cette façon, nous n'exposons rien de privé.

Ajout du support de l'environnement

Même si je ne trouve pas un "support environnement" utile, peut-être que quelqu'un le fera.

Pour ajouter la prise en charge de l’environnement, vous devez changer l’instruction need de meConf en quelque chose comme ceci (pseudocode).

if (environment == "production") {meConf = require ("../ conf/dev/meConf"). production; }

if (environment == "development") {meConf = require ("../ conf/dev/meConf"). development; }

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 le même.

3
guy mograbi

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

}
1

En plus du module nconf mentionné dans cette réponse , et node-config mentionné dans cette réponse , il y a aussi node-iniparser et IniReader , qui semblent être des analyseurs syntaxiques de fichiers de configuration .ini plus simples.

1
Wingman4l7

Je viens de publier un petit module pour charger tout type de fichiers de configuration. C'est assez simple, vous pouvez le vérifier à https://github.com/flesler/config-node

1
Ariel Flesler

Pendant longtemps, j'ai utilisé l'approche mentionnée dans la solution ici. La sécurité des secrets en texte clair suscite toutefois des inquiétudes. Vous pouvez utiliser un autre paquet en plus de config pour que les bits de sécurité soient pris en charge.

Découvrez ceci: https://www.attosol.com/secure-application-secrets-using-masterkey-in-Azure-key-vault/

0
Rahul Soni

Pour ceux qui visitent ce vieux fil, voici un paquet que je trouve bon.

https://www.npmjs.org/package/config

0
Venkat Kotra

J'ai essayé quelques-unes des solutions suggérées ici, mais je n'en étais pas satisfait, alors j'ai créé mon propre module. Il s’appelle mikro-config et la principale différence est qu’il respecte la convention sur la configuration, vous pouvez donc simplement demander le module et commencer à l’utiliser.

Vous stockez votre configuration dans des fichiers plain js ou json du dossier /config. Tout d'abord, il charge le fichier default.js, puis tous les autres fichiers du répertoire /config, puis il charge une configuration spécifique à l'environnement basée sur la variable $NODE_ENV.

Cela permet également de remplacer cette configuration pour le développement local avec local.js ou spécifique à l'environnement /config/env/$NODE_ENV.local.js.

Vous pouvez y jeter un coup d'oeil ici:

https://www.npmjs.com/package/mikro-config

https://github.com/B4nan/mikro-config

0
Martin Adámek