Как хранить настройки/конфигурационные файлы для развертывания Node.js?
Я работаю с несколькими приложениями на Node.js и ищу хороший способ хранения настроек, связанных с развертыванием. В мире Django, откуда я пришел, общепринятой практикой является наличие файла settings.py
, содержащего стандартные настройки (часовой пояс и т.д.), и отдельного файла local_settings.py
для настроек, специфичных для развертывания, таких как база данных, сокет memcache, адреса электронной почты для администраторов и т.д.
Я искал аналогичные паттерны для Node.js. Просто наличие конфигурационного файла было бы неплохо, чтобы не смешивать всё с остальным кодом в app.js
, но для меня важно иметь способ дохраниения специфичных для сервера конфигураций в файле, который не находится под контролем версий. Одно и то же приложение может быть развернуто на разных серверах с совершенно разными настройками, и сталкиваться с конфликтами при слиянии — это не то, что мне хотелось бы.
Существует ли какой-либо фреймворк или инструмент для этой задачи, или все просто придумывают что-то на ходу?
5 ответ(ов)
Мое решение довольно простое:
Загрузите конфигурацию окружения в файле ./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';
// MongoDB
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
Таким образом, вы сможете легко переключаться между различными конфигурациями окружения, что удобно для тестирования и разработки.
Если вы используете файлы .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 run start-dev
Дополнительную информацию можно найти здесь: https://gist.github.com/ericelliott/4152984. Все кредиты Эрику Эллиоту.
Просто создайте простой файл settings.js
с использованием exports
:
exports.my_password = 'value';
Затем в вашем скрипте выполните require
:
var settings = require('./settings.js');
Теперь все ваши настройки будут доступны через переменную settings
:
settings.my_password; // 'value'
Я внесу свои соображения по этому вопросу, потому что ни один из этих ответов не охватывает все критические компоненты, которые нужны практически любой системе. Вот некоторые моменты, которые стоит учитывать:
- Публичная конфигурация (видимая с фронтенда) против приватной конфигурации (где-то прав был guy mograbi). Нужно обеспечить их разделение.
- Секреты, такие как ключи.
- Значения по умолчанию против переопределений для конкретной среды.
- Пакеты для фронтенда.
Вот как я организую свою конфигурацию:
config.default.private.js
— в системе контроля версий, это параметры конфигурации по умолчанию, которые могут видеть только ваш бэкенд.config.default.public.js
— в системе контроля версий, это параметры конфигурации по умолчанию, которые могут видеть как бэкенд, так и фронтенд.config.dev.private.js
— если вам нужны отличные частные параметры по умолчанию для разработки.config.dev.public.js
— если вам нужны отличные публичные параметры по умолчанию для разработки.config.private.js
— не в системе контроля версий, это параметры конкретной среды, которые переопределяютconfig.default.private.js
.config.public.js
— не в системе контроля версий, это параметры конкретной среды, которые переопределяютconfig.default.public.js
.keys/
— папка, где каждый файл хранит разные секреты. Это также не подлежит контролю версий (секреты никогда не должны находиться под контролем версий).
Я использую обычные JavaScript-файлы для конфигурации, чтобы иметь полную мощность языка JavaScript (включая комментарии и возможность загружать файл конфигурации по умолчанию в файл для конкретной среды, чтобы затем его переопределить). Если вы хотите использовать переменные окружения, их можно загрузить внутри этих файлов конфигурации (хотя я не рекомендую использовать переменные окружения по тем же причинам, по которым я не рекомендую использовать JSON-файлы — у вас нет мощи языков программирования для построения вашей конфигурации).
Причина, по которой каждый ключ находится в отдельном файле, заключается в необходимости использования установщика. Это позволяет создать установщик, который создает ключи на машине и сохраняет их в папке с ключами. Без этого ваш установщик может не сработать, когда вы загружаете конфигурационный файл, который не может получить доступ к вашим ключам. Таким образом, вы можете проходить по директории и загружать любые файлы ключей, которые находятся в этой папке, не беспокоясь о том, что существует, а что нет в любой данный версии вашего кода.
Поскольку у вас, вероятно, есть загруженные ключи в вашей приватной конфигурации, вы определенно не хотите загружать свою приватную конфигурацию в любой код фронтенда. Хотя было бы идеально полностью разделить код фронтенда и бэкенда, зачастую такая сложность является достаточно большим барьером, чтобы люди этого не сделали, поэтому и появляется необходимость в разделении конфигурации на приватную и публичную. Но я делаю две вещи, чтобы предотвратить загрузку приватной конфигурации во фронтенд:
- У меня есть юнит-тест, который проверяет, что мои фронтенд-пакеты не содержат ни одного секретного ключа, который есть в приватной конфигурации.
- У меня код фронтенда находится в другой папке, чем код бэкенда, и есть два разных файла с именем "config.js" — один для каждого конца. Для бэкенда
config.js
загружает приватную конфигурацию, для фронтенда — публичную. Затем вы просто вызываетеrequire('config')
и не беспокоитесь о том, откуда она пришла.
И еще одно: ваша конфигурация должна загружаться в браузер через совершенно отдельный файл, отличающийся от кода фронтенда. Если вы собираете код фронтенда, публичная конфигурация должна быть создана как совершенно отдельный пакет. В противном случае ваша конфигурация уже не будет конфигурацией — она станет просто частью вашего кода. Конфигурация должна иметь возможность различаться на разных машинах.
Вы можете создать папку для конфигурационных файлов и создать файл с именем config.js
, который затем будете использовать в своем проекте. Вот пример того, как может выглядеть файл config.js
:
module.exports = {
proxyURL: 'http://url:port',
TWITTER: {
consumerkey: 'вашconsumerkey',
consumerSecrete: 'вашconsumersecrete'
},
GOOGLE: {
consumerkey: 'вашconsumerkey',
consumerSecrete: 'вашconsumersecrete'
},
FACEBOOK: {
consumerkey: 'вашconsumerkey',
consumerSecrete: 'вашconsumersecrete'
}
}
Если вам нужно использовать этот конфигурационный файл в другом месте вашего приложения, вы сначала импортируете его следующим образом:
var config = require('./config');
После этого вы сможете получить доступ к значениям из файла config.js
, как показано ниже:
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');
}
});
Таким образом, вы можете удобно управлять конфигурациями вашего приложения, сохраняя их в одном месте.
Как в Node.js "подключить" функции из других файлов?
Node / Express: EADDRINUSE, адрес уже занят - как остановить процесс, использующий порт?
Как задать переменные окружения из файла package.json?
Как указать необходимую версию Node.js в файле package.json?
Разница между "require(x)" и "import x"