管理 NodeJS 配置标志的更好方法?

A better way to manage NodeJS configuration flags?

我有一个 NodeJS 应用程序,我需要为其提供各种标志以自定义环境。

我已经在使用 dotenv 处理环境文件,并且我也在从 CLI 将其预加载到应用程序:

"scripts": {
  "hello": "DOTENV_CONFIG_PATH=/my/path/dev.env node --max_semi_space_size 64 --inspect=0.0.0.0 dist/index.js"
}

我的问题是:我开始遇到在某些情况下需要添加越来越多的 nodejs 标志的情况 - 有更好的方法吗?我无法想象将来将 20 个 cli args(即 --max_semi_space_size ... 传递给节点。

我 thought/heard 的一些选项是:

但这感觉很奇怪 - 我确信有一种方法可以处理不是那么棘手的问题。你会如何解决这个问题?我也在 docker,如果这对你的建议有任何影响的话。

ta!

最佳做法是创建一种可重用且可在多个级别上更改的机制。许多旨在广泛使用的 docker 容器都遵循这种方法。

分层配置

模块需要支持hierarchical configuration。这意味着将有不止一种设置变量的方法,并且将有一个严格的层次结构,基于优先级,哪个值将是最终值。层次结构的最佳实践如下:

  1. 将值设置为默认值
  2. 检查配置文件中是否有新值,如果有则覆盖该值
  3. 检查环境变量是否有新值,如果有则覆盖该值
  4. 检查启动标志中是否有新值,如果有则覆盖该值。

此方法适用于 node CLI 参数,但层次结构较浅且在环境变量设置处停止。

经过这一系列检查后,您将获得变量的最终值。

应用程序配置变量

Node.js 有一个名为 nconf 的好库,您可以在 github 上找到它。该库允许您进行分层配置。这是一个简单的示例(取自库中的示例,针对 space 进行了修剪)

var nconf = require('nconf');

  // 1. any overrides
  nconf.overrides({
    'always': 'be this value'
  });

  // 2. `process.env`
  // 3. `process.argv`
  nconf.env().argv();

  // 4. Values in `config.json`
  nconf.file('/path/to/config.json');

  // 5. Any default values
  nconf.defaults({
    'if nothing else': 'use this value'
  });

将其包装在您自己的模块中,并添加处理配置所需的额外逻辑

var myConfig = require('nconf');
..
...
..
module.exports = myConfig;

然后使用您代码中的配置,如下所示

var config = require('./myConfig');
config.get('hello');

这将允许您在映像中设置默认配置并在后续映像中覆盖它们。这是一个示例,第一个图像 base 将在构建期间从文件中设置 hello 标志,第二个图像将使用 ENV 覆盖设置:

FROM debian:latest as base

COPY ./hello_config.json /path/to/config.json
...
...

FROM base AS second

ENV hello="Hello world from second image!"
...
...

现在,当您创建容器时,您可以通过传递新的环境文件 (--env-file) 或单个标志(-e--env)来覆盖更改

docker run --env hello="Hi from container!" --env-file ./new_conf.list secod

Note that the environment file should be in a shell format FLAG=VALUE and not in json format.

节点 CLI 参数

Node CLI 参数也可以用这种方法处理(唯一的区别是层次结构停止在 CLI 处)。容器应在 Dockerfile 中使用所需标志定义 NODE_OPTIONS 环境变量,如下所示:

...
ENV NODE_OPTIONS="--max_semi_space_size 64 --inspect=0.0.0.0"
...

这可以增强以接受构建选项以及逐渐构建变量

...
ARG NODE_OPTIONS=""
ENV NODE_OPTIONS="${NODE_OPTIONS} --max_semi_space_size 64"
ENV NODE_OPTIONS="${NODE_OPTIONS} --inspect=0.0.0.0"
...

现在,在构建过程中我们可以指定额外的选项如下

docker build --build-arg NODE_OPTIONS="--cpu-prof --heapsnapshot-near-heap-limit=3" .

与应用程序配置相同,您可以使用-env--env-file文件来针对特定容器进行修改。

在我看来,package.json 文件应该尽可能干净。 通常对于这种情况,我会创建 scriptsshell 目录,然后将所有脚本放入单独的 bash 或 shell 文件中。最后只需从 npm 命令调用这些文件。

像这样:

我不确定在这种情况下使用 nconf 是个不错的选择..

我认为这可以满足您的需求: https://nodejs.org/api/cli.html#cli_node_options_options

NODE_OPTIONS=options...

A space-separated list of command line options.

...

NODE_OPTIONS='--require "./a.js"' node --require "./b.js"
# is equivalent to:
node --require "./a.js" --require "./b.js"

...除了:

Node.js will exit with an error if an option that is not allowed in the environment is used

--max_semi_space_size 未在允许的选项中列出...但您可以尝试。

但无论如何

"scripts": {
  "hello": "./run_node_with_options.sh"
}
# run_node_with_options.sh
DOTENV_CONFIG_PATH=/my/path/dev.env node --max_semi_space_size 64 --inspect=0.0.0.0 dist/index.js"

似乎是一个更可靠的解决方案。