【问题标题】:Dockering a nodejs application with external dependencies使用外部依赖项 Dockering 一个 nodejs 应用程序
【发布时间】:2017-08-12 19:00:48
【问题描述】:

我们正在构建 Node.js 微服务。对于一些可重用的组件,我们创建了一个 utils 文件夹。此文件夹位于实际的微服务包之外。当我们运行微服务时,我们可以使用 require(../../utils/logger) 引用该代码,它就像一个魅力。 但是,当尝试为我的微服务创建 docker 映像时

project the container gives me an error saying:
Error: Cannot find module '../../Utils/logger

这很有意义,因为我们正在微服务项目中构建 docker 映像。 这里需要做出的架构决策很少:

  1. 我们根据需要将 utils 代码移动到每个微服务中。

    • 优点:微服务完全保持自我维持,不依赖任何其他包。
    • 缺点:维护横切关注点和更改会很麻烦。

2.创建一个私有的npm模块并将依赖注入到微服务的package.json文件中。不确定这是否可行。

对此的任何建议都非常感谢。

最好, - 维巴夫

【问题讨论】:

    标签: node.js docker containers microservices


    【解决方案1】:

    不要使用require(../../utils/logger),使用 npm 包

    您应该避免将相同的文件用于带有符号链接的微服务或要求来自一个文件夹,因为它会破坏 Loose coupling

    Loose coupling 是一个旨在减少 系统组件之间的相互依赖关系,其目标是 降低一个组件的更改需要更改的风险 在任何其他组件中。松散耦合是一个更通用的概念 旨在增加系统的灵活性,使其更 可维护,并使整个框架更加“稳定”。

    简单地说,你不能拥有不同版本的记录器文件,但你可以拥有不同版本的记录器 npm 包。

    使用 npm 模块作为 Node.js 微服务的可重用组件的实现细节

    1. 选择包的命名约定。我的建议是scoped packages。示例:@vaibhav/logger
    2. 选择 npm 注册表。有这样的选择:

      • 2.1。 npmjs.com 和公共包。它是免费的,但你的包应该只有通用代码,没有任何商业价值的细节。
      • 2.2 npmjs.com 带有私有包。它很快,但不是免费的。
      • 2.3 verdaccio 你自己的 npm 注册服务器。它是免费的简单 Node.js 解决方案,应作为服务器安装在您的基础架构中。
      • 2.4nexus。具有 npm 和 docker 支持的通用私有注册表。
    3. 如果您使用 2.3 或 2.4 解决方案,则需要为您的服务器选择 ip 或链接。我的建议是使用链接。示例https://your-registry.com

    4. 如果您使用 2.3 或 2.4 解决方案,您需要在微服务内的 .npmrc file 中选择安装方法。有两种选择:
      • 从您的注册表安装所有必需的软件包。 .npmrc 文件看起来像registry=https://your-registry.com。您的注册表应该能够缓存公共包。
      • 仅从您的注册表安装您的软件包,从公共注册表安装其他软件包。 .npmrc 文件看起来像 @vaibhav:registry=https://mycustomregistry.example.org
    5. 在微服务package-lock.json 文件中定义包开发、发布和更新包版本的流程。在我们的项目中,我们以这种方式定义流程:
      • 我们使用GitHub flow 进行包开发。只有主分支用于发布和功能分支用于开发。只能使用来自开发人员的拉取请求或来自 CI 服务器的提交来更新主分支。
      • 我们使用 Jenkins 作为继续集成服务器,用于在合并拉取请求后自动更新版本并发布。 Jenkins 运行 npm version 命令更新版本,然后将新提交发布到 master 分支,然后发布到 npm 注册表。 Jenkins 检查我们的一些规则并将npm versionpatchminor 参数一起使用。更新主要版本是一项重大更改,我们手动进行。
      • 我们在微服务中没有 100% 自动化的更新软件包版本的流程。我们仅在 package-lock.json 文件中自动打开带有新包版本的拉取请求。开发者应检查构建状态并手动按下合并按钮。

    【讨论】:

      【解决方案2】:

      详细说明如何处理微服务生态系统中的共享库以及应该避免什么,这不是您的问题的一部分,但是如果您愿意,您应该阅读此内容以至少获得一份“分享”。

      除此之外,您还可以创建一个库容器,它只提供要挂载的库。

      version: "2"
      
      services:
        shared:
          image: me/mysharelib
        m1:
          volume_from:
            - shared:ro
        m2:
          volume_from:
            - shared:ro
      

      而您的 mysharedlib 图像看起来或多或少像这样

      FROM busybox
      
      COPY bin/busyscript.sh /usr/local/bin/busyscript
      
      WORKDIR /your/lib/folder
      VOLUME /your/lib/folder
      
      CMD ["busyscript"]
      

      而你的busyscript只是一个像这样的假人

      #!/bin/sh
      #set -x
      
      pid=0
      
      # SIGTERM-handler
      term_handler() {
        if [ $pid -ne 0 ]; then
          kill -SIGTERM "$pid"
          wait "$pid"
        fi
        exit 143; # 128 + 15 -- SIGTERM
      }
      
      # setup handlers
      # on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handler
      trap 'kill ${!}; term_handler' SIGTERM
      
      echo "Started DW php code"
      # wait forever
      while true
      do
        tail -f /dev/null & wait ${!}
      done
      

      如您所见,m1/m2 ... m10 挂载了真正在所有微服务之间共享的库。

      替代方案: 您可以肯定地使用私有 NPM 包,或者在映像构建期间将共享库简单地打包到微服务 m1..m10 中。

      当您希望以很少的开销替换堆栈中的共享库并希望确保该库与所有容器实例同步时,上述内容特别适合您

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-17
        • 1970-01-01
        • 2017-03-18
        • 2022-08-18
        • 1970-01-01
        • 2017-11-23
        • 2019-05-27
        • 1970-01-01
        相关资源
        最近更新 更多