【问题标题】:Correct usage of ENV in distributed Node system分布式Node系统中ENV的正确使用
【发布时间】:2021-07-19 00:20:09
【问题描述】:

我正在构建一个相对复杂的分布式节点系统。假设有两个进程(节点应用程序),A 和 B。它们在不同的项目中定义。

此外,还有几个定制的节点模块,在A和B中都使用。我们称它们为M和N。另外,M使用N。

我应该如何正确处理环境变量?

我想我应该为两个主要进程(A 和 B)定义 .env,从那里处理所有 ENV 变量,然后简单地将所需的 env 变量从那里传递到 M 和 N。这样,M 和 N(以及其他内部模块)将在创建时接收作为参数传递的自己的 ENV 变量。

这种方法正确吗?

【问题讨论】:

  • 我会说是的 - 定制的节点模块是纯粹供内部使用的,它们可以使用process.env,或者它们可以使用来自其环境变量的 A 和 B 的参数进行初始化.
  • 在单体架构中不存在这些挑战。新的网络、技术、用户需求迫使我们像您的设计一样设计分布式系统。 #1 您的问题只是针对您的本地主机和图书馆级别的吗? #2 你是在使用 npm 模块还是 A & B 是 nodejs Web 应用程序? #3 您打算如何在暂存或生产环境中部署您的应用程序?我有一个从基础架构角度管理分布式环境中变量的策略。
  • 这是一个分布式系统,A 和 B 可以在不同的实例(docker、EC2 等)上运行。两者都创建和使用 M 和 N,它们被实现为 NPM 模块。我不确定 M 和 N 是否应该拥有自己的 .env 或者 env vars 是否应该在 A 或 B 创建时“注入”。

标签: node.js environment-variables distributed-system


【解决方案1】:

让模块直接访问process.env 不是一个好主意,而拥有自己的.env 文件的模块是一个更糟糕的主意。

  • .env 文件不应添加到源代码管理(即 git),因为它们会随环境而变化(dev,prod,pre-prod) 并且有时包含敏感信息(如 AWS 密钥)。因此,每次安装 node_modules 时都需要粘贴 .env 文件,从而使部署过程更加复杂。

  • 在您的模块中加载的.env 文件可能会以意想不到的方式与您的根应用的.env 合并(记住只有一个process.env)。

  • 想象一个情况,您的模块需要在应用程序的两个部分中表现不同。您将如何仅在一处覆盖通过.env 文件加载的数据?

所以在我看来,你的猜测是正确的:不要将.env 放入node_modules。

// This is better...
nModule.someMethod(process.env.PARAM1, process.env.PARAM2);

// ...than this
process.env.PARAM1 = '';
process.env.PARAM2 = '';

nModule.someMethod();

【讨论】:

    【解决方案2】:

    我强烈认为环境变量是为环境保留的。这对我来说意味着一些事情:

    • 在代码内部,这些变量应该是全局变量,即只能通过 process.env 访问。
    • 它们不会传递给其他模块。当然,使用可以传递给它们导出的函数的参数来自定义依赖项是一个好主意。但不应该为此使用环境。
    • 如何将值加载到process.env 实际上是一个关于如何启动程序A 和B 的问题。我个人更喜欢systemd 服务,因为它具有出色 支持定义运行时环境。 dotenv 包看起来更像是一个拐杖,但从程序的角度来看它很好。

    【讨论】:

      【解决方案3】:

      您的方法听起来是正确的,它应该有效。当您定义.env 文件并使用dotenv 包时,您将能够访问代码中.env 中的所有变量。这意味着定制的节点模块也将能够访问它,并且您不必向它们传递任何东西(您可以直接使用 process.env.NAME_OF_ENVIRONMENT_VARIABLE 访问它们)。

      SUMERIZE:在A和B都创建.env文件,使用dotenv包,然后就可以直接在代码里面用process.env.NAME_OF_ENVIRONMENT_VARIABLE访问环境变量了(在自定义节点模块中也可以) )。您可以在模块 A 和 B 中创建构造函数(用于自定义模块),并将 process.env.ENV_WHATEVER 作为参数传递。这是更好的方法,因为您的自定义模块的逻辑将独立于应用程序的其余部分(它将仅取决于输入)。

      注意:不要将您的 .env 提交给 Git,因为 .env 通常包含一些机密信息。最佳做法是创建一个.gitignore 文件并在其中添加.env。

      建议您可以将所有.env 文件集中在一个位置以便更好地管理。您可以查看一些密码管理工具,例如https://www.dashlane.com/ 或https://www.lastpass.com/。

      【讨论】:

      • 谢谢@Nenad。我认为这样就更少了。我只是不想直接从模块调用 config() ,并避免直接从模块中调用 process.env.ENV_WHATEVER。我觉得最好只从 A 和 B 直接访问 process.env,通过构造函数将 ENV_WHATEVER 传递给模块,并使模块更加隔离和可重用。
      • 但你也可以这样做。您可以在模块 A 和 B 中创建构造函数,并将 process.env.ENV_WHATEVER 作为参数传递。这是更好的方法,因为您的自定义模块逻辑将独立于应用程序的其余部分(它仅取决于输入)。如果你问我,那是很好的方法。让我补充一下。
      【解决方案4】:

      您提到了复杂的分布式系统。分发也可以与集线器/集中式密钥/变量管理系统相关联。我假设有许多 env 变量在您的多个应用程序之间共享。

      如果您创建一个包含所有必需变量并通过身份验证保护它们的集中式节点,这不是一个优点吗?

      所有节点(无论应用程序)只维护一个密码字符串,以便通过集中式节点进行身份验证,并从单个 .env 文件加载所有必需的变量。

      您也可以使用像vault这样的系统

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-22
        • 1970-01-01
        • 2023-01-05
        • 2013-04-02
        • 1970-01-01
        • 2011-11-05
        • 1970-01-01
        相关资源
        最近更新 更多