如何存储Node.js部署设置/配置文件?

问题描述 投票:602回答:23

我一直在研究一些Node应用程序,我一直在寻找一种存储与部署相关的设置的良好模式。在Django世界(我来自哪里),通常的做法是使用包含标准设置(时区等)的settings.py文件,然后使用local_settings.py进行部署特定设置,即。什么数据库交谈,什么memcache套接字,管理员的电子邮件地址等。

我一直在寻找类似Node的模式。只是一个配置文件会很好,所以它不必与app.js中的其他所有内容一起使用,但我发现在一个不在源代码控制中的文件中有一种特定于服务器的配置很重要。相同的应用程序可以在不同的服务器上部署,具有完全不同的设置,并且必须处理合并冲突以及所有这些不是我的乐趣。

那么是否有某种框架/工具,或者每个人都自己一起破解某些东西?

node.js configuration-files
23个回答
735
投票

我使用package.json作为我的包,使用config.js作为我的配置,看起来像:

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;

我从我的项目加载配置:

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

然后我可以从config.db_hostconfig.db_port等访问我的东西......如果我不想在源代码管理中存储密码,我可以使用硬编码参数或存储在环境变量中的参数。

我还生成一个package.json并插入依赖项部分:

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

当我将项目克隆到我的本地机器时,我运行npm install来安装软件包。关于那个here的更多信息。

该项目存储在GitHub中,为我的生产服务器添加了遥控器。


11
投票

keys/是另一个添加模式进行验证的选项。与nconf一样,它支持从环境变量,参数,文件和json对象的任意组合加载设置。

自述文件中的示例:

Convict

入门文章: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" } });


11
投票

您可以将Taming Configurations with node-convict用于特定于环境的配置文件。它自动加载json或yaml配置文件,它具有默认值和动态配置功能。

Konfig repo的一个例子:

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

在生产中,假设我们开始使用> config.app.port 3000

$ NODE_ENV=production PORT=4567 node app.js

更多细节:> config.app.port 4567


7
投票

我将创建一个文件夹作为配置文件命名为https://github.com/vngrs/konfig,稍后我会在任何需要的地方使用此文件,如下所示

config.js的示例

config.js

然后,如果我想在某处使用此配置文件

我将首先导入如下

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

我可以访问如下的值

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

3
投票

我在游戏中有点晚了,但我找不到我需要的东西 - 或者其他任何地方 - 所以我自己写了一些东西。

我对配置机制的要求如下:

  1. 支持前端。如果前端无法使用配置,有什么意义?
  2. 支持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'); } }); - 看起来相同但允许在settings-overrides.js覆盖配置。这里的想法是在不更改代码的情况下轻松修改配置。我觉得它对saas很有用。

即使我不太关心支持环境 - 这将解释如何将其轻松添加到我的解决方案中

settings.js

说明

  • 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; 意味着这个属性是必需的
  • undefined意味着它是可选的
  • null - 目前代码是meConf下文件的目标。 app是覆盖meConf的覆盖文件 - 我的vcs会忽略它。
  • conf/dev - 将从前端和后端可见。
  • publicConfiguration - 只能从后端看到。
  • privateConfiguration - 将公开公共配置并将其分配给全局变量的路由。例如,下面的代码将公共配置公开为前端的全局变量myConf。默认情况下,它将使用全局变量名称sendPublicConfiguration。 app.get(“/ backend / conf”,require(“conf”)。sendPublicConfiguration);

Logic of overrides

  • privateConfiguration与publicConfiguration合并,然后是meConf。
  • publicConfiguration检查每个键是否具有覆盖,并使用该覆盖。这样我们就不会露出任何私密的东西了。

添加环境支持

即使我没有找到有用的“环境支持”,也许有人会。

要添加环境支持,您需要将meConf require语句更改为此类(伪代码)

if(environment ==“production”){meConf = require(“../ conf / dev / meConf”)。production; }

if(environment ==“development”){meConf = require(“../ conf / dev / meConf”)。development; }

同样,您可以为每个环境提供一个文件

conf

并导入正确的。其余的逻辑保持不变。


3
投票

我刚刚使用的一个alt示例,因为我想要比典型的.json文件更灵活,但是不希望它被抽象到一个需要依赖的库中。基本上,导出一个立即调用的函数,该函数返回一个具有我想要的值的对象。提供了很大的灵活性。

 meConf.development.js
 meConf.production.js

这里有完整的例子,有一个更好的解释。 module.exports = function(){ switch(node_env){ case 'dev': return { var1 = 'development'}; } }();


3
投票

我知道这是一个非常古老的帖子。但我想分享我的模块来配置环境变量,我认为这是非常灵活的解决方案。这是模块Using Config Files in Node.js

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 获取环境的所有变量。


3
投票

只需使用process.env.NODE_ENV模块npm(超过300000次下载)

config

Node-config为您的应用程序部署组织层次结构配置。

它允许您定义一组默认参数,并为不同的部署环境(开发,qa,登台,生产等)扩展它们。

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

2
投票

将“开发”和“生产”配置分开是更好的选择。

我使用以下方式:这是我的config / index.js文件:

$ 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

对于require,配置使用以下内容:

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

你可以使用你的配置对象:

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

1
投票

除了const ip_address = config.ip_address; const port = config.port; 中提到的nconf modulethis answer中提到的node-config之外,还有this answernode-iniparser,它们似乎更简单.ini配置文件解析器。


1
投票

我刚刚发布了一个小模块来加载任何类型的配置文件。这很简单,你可以在IniReader查看


230
投票

从Node v0.5.x(referencing this answer)开始,您可以要求JSON文件

config.json:

{
    "username" : "root",
    "password" : "foot"
}

app.js:

var config = require('./config.json');
log_in(config.username, config.password);


0
投票

对于那些正在访问这个旧线程的人来说,这是一个我认为很好的包。

var Config = require("pconf"); var testConfig = new Config("testConfig"); testConfig.onload = function(){ testConfig.setValue("test", 1); testConfig.getValue("test"); //testConfig.saveConfig(); Not needed }


0
投票

我在这里尝试了一些建议的解决方案,但对它们并不满意,所以我创建了自己的模块。它被称为https://www.npmjs.org/package/config,主要区别在于它尊重约定优于配置,因此您只需要模块并开始使用它。

您可以将配置存储在mikro-config文件夹中的普通js或json文件中。首先,它加载/config文件,然后从default.js目录加载所有其他文件,然后根据/config变量加载特定于环境的配置。

它还允许使用$NODE_ENV或特定于环境的local.js覆盖此配置以进行本地开发。

你可以在这看看它:

/config/env/$NODE_ENV.local.js

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


0
投票

很长一段时间,我曾经使用过解决方案中提到的方法。然而,关于明文的秘密安全性存在担忧。您可以在https://github.com/B4nan/mikro-config之上使用另一个包,以便处理安全位。

看看这个:config


189
投票

很久以后,我找到了一个非常好的Node.js模块来管理配置:nconf

一个简单的例子:

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'));

它还支持在Redis中存储设置,编写配置文件,并且具有相当可靠的API,并且还受到一个备受推崇的Node.js商店Nodejitsu的支持,作为Flatiron框架计划的一部分,因此它应该是相当面向未来。

看看nconf at Github


85
投票

我的解决方案很简单:

在./config/index.js中加载环境配置

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

module.exports = cfg;

在./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';

覆盖./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);

在测试环境中运行您的应用:

NODE_ENV=test node ./app.js

这里有更详细的解释:http://www.chovy.com/node-js/managing-config-variables-inside-a-node-js-application/


31
投票

您也可以选择遵循dotenv原则的twelve-factor app

我曾经使用node-config,但出于这个原因创建了dotenv。它完全受到ruby的dotenv库的启发。

用法很简单:

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

然后你只需创建一个.env文件并将设置放在那里:

S3_BUCKET=YOURS3BUCKET
SECRET_KEY=YOURSECRETKEYGOESHERE
OTHER_SECRET_STUFF=my_cats_middle_name

这是nodejs的dotenv


29
投票

你们是否使用npm来启动脚本(env等)?

如果您使用.env文件,您可以将它们包含在package.json中并使用npm来源/启动它们。

例:

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

然后运行npm脚本:

$ npm start-dev

它在这里描述qazxsw poi所有归功于Eric Elliott


22
投票

您也可以查看https://gist.github.com/ericelliott/4152984,它根据$ HOST和$ NODE_ENV变量(有点像RoR)加载配置文件:node-config

这对于不同的部署设置(documentationdevelopmenttest)非常有用。


20
投票

只需用production做一个简单的settings.js

exports

然后,在你的脚本中,做一个exports.my_password = 'value'

require

您现在可以通过var settings = require('./settings.js'); 变量获取所有设置:

settings

12
投票

我要把帽子放到戒指上,因为这些答案都没有解决任何系统所需的所有关键组件。注意事项:

  • 公共配置(可以通过前端看到)与私人配置(家伙mograbi得到这个权利)。并确保这些是分开的。
  • 像钥匙一样的秘密
  • 默认值与特定于环境的覆盖
  • 前端捆绑

这是我如何配置:

  • settings.my_password // 'value' - 在版本控制中,这些是默认配置选项,只能由后端查看。
  • config.default.private.js - 在版本控制中,这些是后端和前端可以看到的默认配置选项
  • config.default.public.js - 如果您需要dev的不同私有默认值。
  • config.dev.private.js - 如果你需要dev的不同公共默认值。
  • config.dev.public.js - 不在版本控制中,这些是覆盖config.private.js的特定于环境的选项
  • config.default.private.js - 不在版本控制中,这些是覆盖config.public.js的特定于环境的选项
  • config.default.public.js - 每个文件存储某种不同秘密的文件夹。这也不受版本控制(键不应该受版本控制)。

我使用普通的javascript文件进行配置,因此我拥有javascript语言的全部功能(包括注释和执行操作的能力,例如在环境特定的文件中加载默认配置文件,以便可以覆盖它们)。如果你想使用环境变量,你可以在这些配置文件中加载它们(因为我不建议使用json文件,我建议不要使用env变种 - 你没有编译语言的强大功能来构建你的配置)。

每个密钥位于单独文件中的原因是供安装程序使用。这允许您拥有一个在机器上创建密钥的安装程序,并将它们存储在密钥文件夹中。如果没有这个,加载无法访问密钥的配置文件时,安装程​​序可能会失败。通过这种方式,您可以遍历目录并加载该文件夹中的所有密钥文件,而无需担心代码的任何给定版本中存在的内容和不存在的内容。

由于您可能在私有配置中加载了密钥,因此您绝对不希望在任何前端代码中加载私有配置。虽然将前端代码库与后端完全分离可能非常理想,但很多时候PITA是阻止人们进行操作的一大屏障,因此私有vs公共配置。但我做了两件事来防止在前端加载私有配置:

  1. 我有一个单元测试,确保我的前端捆绑包不包含私有配置中的一个密钥。
  2. 我的前端代码位于与后端代码不同的文件夹中,我有两个不同的文件名为“config.js” - 每个文件对应一端。对于后端,config.js加载私有配置,对于前端,它加载公共配置。然后你总是只需要('config')并且不用担心它来自哪里。

最后一件事:您的配置应该通过一个完全独立的文件加载到浏览器中,而不是任何其他前端代码。如果捆绑前端代码,则应将公共配置构建为完全独立的捆绑包。否则,您的配置不再是真正的配置 - 它只是代码的一部分。配置需要能够在不同的机器上不同。

© www.soinside.com 2019 - 2024. All rights reserved.