Как хранить узел.параметры развертывания js / файлы конфигурации?

Я работал над несколькими приложениями узла, и я искал хороший шаблон хранения параметров, связанных с развертыванием. В мире Джанго (откуда я родом) обычной практикой было бы иметь settings.py файл, содержащий стандартные настройки (часовой пояс и т. д.), а затем local_settings.py для конкретных параметров развертывания, т. е. с какой базой данных говорить, какой сокет memcache, адрес электронной почты для администраторов и так далее.

Я искал аналогичные шаблоны для Node. Просто конфигурационный файл был бы хорош, поэтому его не нужно заклинивать со всем остальным в app.js, но я считаю важным иметь способ иметь конфигурацию сервера в файле, который не находится в системе управления версиями. Одно и то же приложение может быть развернуто на разных серверах с совершенно разными настройками и иметь дело с конфликтами слияния и всем, что не является моим представлением о веселье.

Так есть какая-то структура/инструмент для этого, или все просто взломать что-то вместе себя?

23 ответов


Я использую 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_host, config.db_port, etc... Это позволяет мне использовать жестко закодированные параметры или параметры, хранящиеся в переменных среды, если я не хочу хранить пароли в системе управления версиями.

Я также создать 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 для установки пакетов. Более подробную информацию о том, что здесь.

проект хранится в GitHub с добавлением пультов для моего рабочего сервера.


вам могут потребоваться файлы JSON с узла v0.5.x (ссылка на этот ответ)

конфиг.в JSON:

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

app.js:

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

много позже я нашел довольно хороший узел.модуль 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, а также поддерживается одним из наиболее уважаемых узлов.магазины и JS, Nodejitsu в рамках Flatiron рамочная инициатива, поэтому она должна быть достаточно перспективной.

проверить nconf в Github.


мое решение довольно простое:

загрузите конфигурацию среды ./ config / index.js

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

module.exports = cfg;

определите некоторые значения по умолчанию ./ config / config.глобальный.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.тест.js

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

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

module.exports = config;

используя его ./модели/пользователя.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/


вы также можете посмотреть на dotenv который следует принципам двенадцати факторов приложение.

я использовал node-config, но создал dotenv по этой причине. Он был полностью вдохновлен библиотекой dotenv ruby.

использование довольно простое:

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

затем вы просто создаете .env файл и поместите свои настройки там так:

S3_BUCKET=YOURS3BUCKET
SECRET_KEY=YOURSECRETKEYGOESHERE
OTHER_SECRET_STUFF=my_cats_middle_name

Это dotenv для nodejs.


вы, ребята, используете 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

его описано здесь https://gist.github.com/ericelliott/4152984 Все заслуги Эрика Эллиота


вы также можете посмотреть на node-config который загружает файл конфигурации, в зависимости от $HOST и $переменной NODE_ENV переменная (немного похожая на RoR):документация.

Это может быть весьма полезно для различных параметров развертывания (development, test или production).


просто сделайте простой settings.js С exports:

exports.my_password = 'value'

затем, в вашем скрипте, сделайте require:

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

все настройки теперь будут доступны через settings переменной:

settings.my_password // 'value'

осужденного является еще одним вариантом, который добавляет схему для проверки. Как и nconf, он поддерживает параметры загрузки из любой комбинации переменных среды, аргументов, файлов и объектов json.

пример из 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"
  }
});

начало статьи: Укрощение конфигураций с узлом-convict


можно использовать конфиг для файлов конфигурации конкретной среды. Он автоматически загружает файлы конфигурации JSON или yaml, имеет значение по умолчанию и функции динамической конфигурации.

пример из 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"
    }
}

развитие:

> config.app.port
3000

в производстве предположим, что мы запускаем приложение с $ NODE_ENV=production PORT=4567 node app.js

> config.app.port
4567

больше деталей:https://github.com/vngrs/konfig


Я собираюсь бросить свою шляпу в кольцо здесь, потому что ни один из этих ответов не касается всех критических компонентов, которые в значительной степени нужны любой системе. Соображения:

  • публичная конфигурация (которую можно увидеть на интерфейсе) против частной конфигурации (Гай мограби получил это право). И сделать это отдельно.
  • секреты как ключи
  • значения по умолчанию и переопределения для конкретной среды
  • фронтэнд связки

вот как я делаю свою конфигурацию:

  • config.default.private.js - в управлении версиями это параметры конфигурации по умолчанию, которые могут быть видны только на вашем бэкэнде.
  • config.default.public.js - в системе управления версиями это параметры конфигурации по умолчанию, которые можно увидеть в backend и frontend
  • config.dev.private.js - Если вам нужны разные частные значения по умолчанию для dev.
  • config.dev.public.js - Если вам нужна другая публика по умолчанию для Дев.
  • config.private.js - не в контроле версий, это параметры конкретной среды, которые переопределяют config.default.private.js
  • config.public.js - не в управлении версиями, это параметры среды, которые переопределяют config.default.public.js
  • keys/ - папка, в которой каждый файл хранит какой-то секрет. Это также не находится под контролем версий (ключи никогда не должны находиться под контролем версий).

Я использую простые старые файлы javascript для конфигурация, поэтому у меня есть полная мощность javascript langauge (включая комментарии и возможность делать такие вещи, как загрузка файла конфигурации по умолчанию в файле среды, чтобы их можно было переопределить). Если вы хотите использовать переменные среды, вы можете загрузить их внутри этих файлов конфигурации (tho я рекомендую не использовать env vars по той же причине, по которой я не рекомендую использовать файлы json - у вас нет возможности языка программирования для создания вашей конфигурации).

в причина, по которой каждый ключ находится в отдельном файле, предназначена для использования установщиком. Это позволяет иметь установщик, который создает ключи на компьютере и сохраняет их в папке keys. Без этого программа установки может завершиться ошибкой при загрузке файла конфигурации,который не может получить доступ к ключам. Таким образом, вы можете пересечь каталог и загрузить любые ключевые файлы, которые находятся в этой папке, не беспокоясь о том, что существует, а что нет в любой версии вашего кода.

так как у вас, вероятно, есть ключи загружено в вашей частной конфигурации, вы наверняка не хочу загружать вашу личную конфигурацию в любом интерфейсном коде. Хотя его, вероятно, строго более идеально, чтобы полностью отделить вашу интерфейсную кодовую базу от вашего бэкэнда, много раз, что Пита является достаточно большим барьером, чтобы помешать людям делать это, таким образом, частная vs public config. Но есть две вещи, которые я делаю, чтобы предотвратить загрузку частной конфигурации в интерфейсе:

  1. у меня есть unit-тест, который обеспечивает моя пакеты frontend не содержат один из секретных ключей, которые у меня есть в частной конфигурации.
  2. у меня есть код интерфейса в другой папке, чем мой бэкэнд-код, и у меня есть два разных файла с именем "config.js" - по одному для каждого конца. Для серверной части, конфигурации.js загружает частную конфигурацию, для frontend, он загружает общедоступную конфигурацию. Тогда вам всегда просто требуется ('config') и не беспокойтесь о том, откуда он берется.

последнее: ваша конфигурация должна быть загружена в браузер через полностью отдельный файл, чем любой другой код интерфейса. Если вы связываете свой интерфейсный код, общедоступная конфигурация должна быть построена как полностью отдельный пакет. В противном случае ваша конфигурация больше не является конфигурацией - это просто часть вашего кода. Config должен иметь возможность отличаться на разных машинах.


Я создам папку как config имя файла как config.js и позже я буду использовать этот файл везде, где это необходимо, как показано ниже

пример конфига.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');

и я могу получить доступ к значениям, как показано ниже

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

я немного опоздал в игре, но я не мог найти то, что мне нужно здесь - или где - либо еще-поэтому я написал что-то сам.

мои требования к механизму конфигурации следующие:

  1. поддержка front-end. Какой смысл, если front-end не может использовать конфигурацию?
  2. поддержка settings-overrides.js - который выглядит одинаково, но позволяет переопределять конфигурацию в settings.js. Идея здесь состоит в том, чтобы легко изменить конфигурацию без изменение кода. Я считаю, что это полезно для saas.

хотя я меньше забочусь о поддержке сред - объяснит, как легко добавить его в мое решение

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 является переопределяет файлы, которые предназначены для conf/dev - который игнорируется моими vcs.
  • publicConfiguration - будет видно с переднего и заднего концов.
  • privateConfiguration - будет видно только с задней панели.
  • sendPublicConfiguration - маршрут, который будет предоставлять общедоступную конфигурацию и назначать ее глобальной переменной. Например, приведенный ниже код будет предоставлять общедоступную конфигурацию как глобальную переменную myConf в интерфейсе. По умолчанию используется глобальная переменная name conf.

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

логика переопределяет

  • privateConfiguration объединяется с publicConfiguration, а затем meConf.
  • publicConfiguration проверяет каждый ключ, если он имеет переопределение, и использует это переопределение. Таким образом, мы не раскрываем ничего личного.

добавлена поддержка среды

даже хотя я не нахожу "поддержку окружающей среды" полезной, возможно, кто-то будет.

чтобы добавить поддержку среды, вам нужно изменить оператор meconf require на что-то вроде этого (псевдокод)

if (environment = = " production" ) { meConf = require("../conf/dev / meConf").производство; }

if (environment = = " development" ) { meConf = require("../conf/dev / meConf").развитие; }

аналогично вы можете иметь файл per environment

 meConf.development.js
 meConf.production.js

импорт и правильный. Остальная логика остается прежней.


пример alt я просто использовал, потому что хотел больше гибкости, чем типичный .файл json, но не хотел, чтобы он абстрагировался в библиотеку, которая потребует зависимости, что-то вроде этого. В принципе, экспорт функции, вызванной немедленно, которая вернула объект со значениями, которые я хотел установить. Дает много гибкости.

     module.exports = function(){
       switch(node_env){
         case 'dev':
           return
           { var1 = 'development'};
         }
    }();

здесь есть гораздо лучшее объяснение с полным примером. использование конфигурационных файлов в узле.js


Я знаю, что это очень старый пост. Но я хочу поделиться своим модулем для настройки переменных среды, я думаю, что это очень гибкое решение. Вот модуль в JSON-конфигуратор

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 

затем вы можете использовать process.env.NODE_ENV чтобы получить все переменные для вашей среды.


кроме модуль nconf упомянутые в ответ и node-config упомянутые в ответ, есть еще узел-iniparser и IniReader, которые кажутся проще .Парсеры файлов конфигурации ini.


недавно я выпустил небольшой модуль для загрузки файлов конфигурации любого типа. Это довольно прямолинейно, вы можете проверить это на https://github.com/flesler/config-node


вы можете использовать pconf: https://www.npmjs.com/package/pconf

пример:

var Config = require("pconf");
var testConfig = new Config("testConfig");
testConfig.onload = function(){

  testConfig.setValue("test", 1);
  testConfig.getValue("test");
  //testConfig.saveConfig(); Not needed

}

лучше отделить '' и '' конфиги.

Я использую следующий способ: Вот мой 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 : ""
        }
    }
} 

для требуемой конфигурации используйте следующее:

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

чем вы можете использовать свой объект config:

const ip_address = config.ip_address;
const port = config.port;

для тех, кто посещает этот старый поток, вот пакет, который я считаю хорошим.

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


я попробовал некоторые из предложенных решений здесь, но не был sattisfied с ними, поэтому я создал свой собственный модуль. Она называется mikro-config и главное отличие в том, что он чтит Соглашение над конфигурацией, поэтому вы можете просто потребовать модуль и начать его использовать.

вы храните свою конфигурацию в простых JS или JSON-файлах из /config папка. Сначала он загружает default.js файл, затем все остальные файлы из /config каталог, затем он загружает конфигурацию конкретной среды на основе on $NODE_ENV переменной.

это также позволяет переопределить эту конфигурацию для локальной разработки с local.js или окружающей среды /config/env/$NODE_ENV.local.js.

вы можете посмотреть на это здесь:

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

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


долгое время я использовал подход, упомянутый в решении здесь. Однако существует озабоченность по поводу безопасности секретов в ясном тексте. Вы можете использовать другой пакет поверх config Так что биты безопасности позаботятся.

проверьте это: https://www.attosol.com/secure-application-secrets-using-masterkey-in-azure-key-vault/


просто использовать npm модуль config (более 300000 загрузок)

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

Node-config организует иерархические конфигурации для развертывания приложений.

Он позволяет определить набор параметров по умолчанию и расширить их для различных сред развертывания (разработка, qa, постановка, производство и т. д.).

$ 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