用例- #unpublish Happens -如何保护你的Node.js投资

文摘:

Igor Soarez /首席工程师/ YLD, 2016年5月:归根结底,npm是一个注册表,它是一个与Node.js捆绑在一起的工具。但它也有一定的权衡。
依赖npm进行构建和部署的权衡是什么?我们如何处理这个问题?最好的指导方针是什么?
您不能依赖社区来支持您的业务,开源开发人员不为您的公司工作,您不能在公共包存储库上支持您的生产环境。
你需要检查安全。您需要保证部署到生产环境的版本是一致的。因为注册中心是一个外部依赖,所以您需要降低这种风险。解决方案不能由不提供SLA的第三方来维护——您需要能够依赖于您用来部署的任何东西。我们的目标是提出一种架构来解决这个问题。

讨论转录:

我是伊戈尔。我做Node已经四年多了。我帮助过从初创公司到大企业的各种公司采用Node。构建框架,微服务,基本的web开发,所有的工作。

我在YLD工作。YLD是一家总部位于伦敦的咨询公司。我们已经做了两年半了。YLD是由Nodejitsu的创造者创建的。对于那些不知道Nodejitsu的人来说,它是Node应用程序作为服务的参考平台。他们现在已经被收购了。当时,是Nodejitsu和YLD的创始人在管理公共NPM注册。我们是Node基金会的创始成员。这是一个涵盖Node.js项目的基础。

我们这个行业交付软件的方式一直在改变。我们将这一系列变化视为工程学的未来。Bill Scott是我们公司的顾问,他在PayPal做了这些改变。这一切都是关于将工作分解成小型的,有才能的,独立的团队。并时刻关注客户价值。我们认为Node是促进这种变化的一个很好的工具。

Node社区已经走过了漫长的道路。它的发展速度非常快,从很多方面来看,Node都是目前发展最快、最重要的开发语言。它拥有400万用户,我们看到它的增长速度每年都在翻倍。特别是在企业中,自去年以来,其采用率增长了400%。Node无处不在。

不久之前,Node还只是Ryan Dahl的一个业余项目。这张图片来自Ryan介绍Node作为JSConf Europe的视频。这个聪明的人把JavaScript,一种没有任何I/O的语言,与Livy VC(一个同步I/O库)结合在一起,把JavaScript带到服务器上。他想要一个事件驱动的、非阻塞的I/O。他使Node轻量级且高性能,即使在极端负载下也是如此。这并不是很久以前的事。

如今,它已被许多企业所采用。但是在很多方面,Node仍然被认为是不成熟的。尤其是其他老年社区。我认为一个重要的原因是JavaScript是一种流行的语言。这是RedMonk的编程语言排名。他们是伦敦一家领先的行业分析公司。JavaScript实际上是最流行的语言。

它开始于浏览器,但现在你可以在任何地方运行JavaScript。Node社区的很大一部分是由web开发人员组成的。Node使用JavaScript,浏览器运行JavaScript,但是JavaScript和服务器不同于JavaScript和客户端。而且这些web开发人员通常没有任何工程背景。我们相信工程师和开发人员之间是有区别的。由于我们非常关注工程,YLD希望考虑我们所选择的工具集的所有方面,从安全性到构建管道。在社区中,这一点总是没有得到足够的考虑。

Node降低了新后端开发人员的入门门槛,这是件好事。但这也解释了为什么社区有时似乎有点脱离既定的工程实践。这是我们在YLD非常努力地帮助客户的事情。

但是Node一直在被采用,企业用户也在不断增长,这是有充分理由的。Node是一个简单、强大且灵活的工具。它在不影响性能的情况下简化了I/O。但重要的是要记住,并非所有用例都适合Node。[…]确保您的组织采用Node是为了正确的用例。

我们经常在企业中发现Node的最佳用例之一是我们称之为专用后端。或者通常也称为前端的后端。Node很好地为应用程序开发人员在服务器端提供了一块土地。我的意思是,它为应用程序或客户端团队提供了灵活性,可以为他们所瞄准的平台构建所需的支持,而不必不断地与API或后端团队来回切换。因此,它创造了灵活性和速度,使您能够更快地向客户交付价值。所有这些都不会影响安全性或性能。但这并不意味着采用Node就没有风险。

我们还没有找到一个没有依赖关系的企业Node.js项目。Node拥有一个充满活力的社区。它有一个非常丰富的公共软件包生态系统,自然你想充分利用它。在Node中,开发文化提倡将问题分解成许多只做一件事、只做一件事的小模块。因此,与其他技术相比,Node项目平均会有更多的依赖项。这是Node最大的优势之一,但也可能是它的一个弱点——如果你不小心的话,这也是它的一个弱点。

因此,处理越来越多的依赖关系可能是一场斗争。这就是强大的工程实践将保护您和您的投资的地方。

所有这些公共包都在NPM上共享。NPM是一个公共注册中心。任何人都可以发布,并且可以免费使用。NPM是Node的官方包管理器。它也是公共登记处。它也是一家初创公司。NPM客户端与Node捆绑在一起。所以当你安装Node时,你会得到NPM。但是,虽然Node由一个基金会管理,该基金会由对Node有投资兴趣的公司组成,但公共NPM注册表由一家名为NPM Inc的私人公司运营和管理。因此,每个做Node的人分享工作的公共注册中心是由一家私人公司控制的。 It’s not under the control of the foundation.

当你安装Node时,你会得到NPM和一个NPM配置,默认情况下它会使用或指向NPM Inc.运行的公共注册表。如果由于某种原因,公共NPM注册表不可用,这可能会中断整个团队的开发。如果您试图在公共注册表不可用的情况下安装旧模块,您将看到这一点。在这个实例中,我们试图安装joi包。但你得到的不是快乐,而是沮丧。

由于各种原因,公共注册表可能已经关闭。即使它没有下降,它也可能很慢。您最不希望看到的就是您的团队经常空闲等待免费的公共注册表。

比开发更糟糕的是构建和部署。每次构建被触发时,你都需要运行NPM install。如果NPM安装失败,整个构建也会失败。这将推迟发布周期。如果在部署时运行NPM install,结果可能会糟糕得多。在部署期间容量减少的持续部署和/或集成管道可能会给可用的生产实例带来不必要的压力。

记住,如果你使用NPM,可怕的事实是你是在依赖陌生人。你在用他们的包。使用公共注册表可能会使您受任意数量的包作者的摆布。最近,NPM因破坏互联网而被媒体报道。像WordPress。com这样的网站受到了影响。这个开发人员决定删除这个小包,它是数百个其他包的依赖,并破坏了数千个项目。现在,在此事件之后,公共注册中心现在不允许删除已发布的包。但是,开源贡献仍然可以通过许多方式影响您的项目。

如果您考虑安全性,那么您所需要的只是一个坏模块。同样,Node的方式是拥有许多小的依赖项,这些依赖项只做一件事,只做好一件事。但是平均而言,某个特定版本的Node模块存在安全问题的可能性是0.5%。那么一个有30个依赖项的项目,有15%的可能性您的项目支持安全漏洞。这是相当可怕的。即使它不是安全更新,即使它不是安全问题,如果它只是一个错误或不兼容的更新,那就够糟糕的了。因为有这么多的依赖关系,你不想被困在特定的版本上,不得不手动更新每一个版本。但是,每天都有如此多的公共NPM包更新,从你测试和部署它开始,你很有可能会得到不同的软件。更好的工作和更快的软件是伟大的,但这也可能是破坏性的变化或错误。不可预测的变化是不可接受的风险。

在旧项目中,依赖关系是用范围指定的。有很多方法可以指定这些范围。你可以参考一个特定的版本。您可以允许高于某个版本的任何版本。如果你使用波浪,那就允许新的补丁。如果你使用插入符号,它也允许新的次要版本,但不允许主要版本,所以有不同的方法。指导方针和默认的指定方式一直是争论的焦点,它已经改变了很多次。

NPM建议使用semver进行应用程序版本控制。这是一组规则,试图将兼容的更改与不兼容的更改分开。但实际情况是,遵守这一规则完全取决于包的作者。如果您所依赖的包不遵循semver,这可能会出现问题。或者——并且包的新版本有突破性的变化。即使包作者遵循semver,在兼容版本中仍然有可能引入错误。

选择依赖项已经够难的了。这些都是你需要考虑的。比如许可证、发布频率、作者是否对开放问题、测试覆盖率等做出了响应。如果有大量的依赖项,就会加剧这个问题。

所以,如果你看到了所有这些问题,你能做些什么呢?这里的教训是什么?第一个也是最重要的规则是,在部署时不要运行NPM install。我们看到这种情况的次数多得惊人。如果注册表不可用,或者由于任何原因导致NPM安装失败,那么在需要时可能没有足够的供应服务器。相反,您应该尝试部署预构建的构件。

您还需要掌握您所依赖的软件。即使在构建这些构件时,您也不希望依赖于公共注册中心。

所以解决方案是保存一个缓存,在你的控制下保存每个依赖项的副本。在过去,Node社区一直建议应用程序将它们的依赖项检入到源代码控制中。本质上是将依赖捆绑或出售到您的应用程序中。

但这可能会变得相当混乱。因为有原生模块,所以NPM包中有C和c++代码和makefile文件,而不仅仅是JavaScript。在安装这些文件时,需要对它们进行编译。这将针对不同开发人员机器的特定架构。它会根据你的目标环境而有所不同。所以每次检出项目时,你只需要进行NPM重建,而且你需要对检入源代码控制的文件进行相当的选择。这可能是一场噩梦。更不用说读起来会很不舒服。而整个版本控制系统将变成一个难以处理的问题。

更好的解决方案是使用私有包存储库。公共注册中心的缓存代理。每次添加新的依赖项时,都要将其持久地缓存到您的控制之下。Artifactory是我们大多数客户使用的产品。它支持NPM,您可以将其配置为公共注册中心的缓存代理。一旦你开始使用依赖项,它就会被缓存,如果NPM不可用,如果一个包被拉出,如果出现任何问题,你都是安全的。你拥有继续开发、构建和部署所需的一切。它还允许您将公共包发布到您自己的私有包存储库。这很好。

设置起来真的很简单。你需要做的就是配置NPM。更改此配置文件并为注册中心设置不同的端点。我想做一个演示,但我觉得在这里的飞机上做会更酷。

所以我用手机拍了下来。我的笔记本电脑没有网络连接。我在hapi项目,这是一个流行的web开发框架的节点。我去掉了所有的依赖项。并检查注册表的npm配置。我们将看到它指向在Docker上本地运行的Artifactory。然后我们运行NPM install,即使公共注册表不可用,因为所有模块都缓存在Artifactory下,你仍然可以安装。

这样就解决了可用性问题。但是更新呢?在切割和测试之间[…]会对你的依赖项进行更新。即使您不使用版本范围,即使您将项目依赖项指定为特定版本,也只能解决直接依赖项的问题。它不能解决瞬态依赖关系的问题。

解决这个问题的一个方法是使用NPM shrinkwrap。如果你在项目上运行npm shrinkwrap,它会创建一个文件,其中列出了当前安装的所有npm模块的名称和特定版本。这个你应该签入版本控制的文件将被NPM引用,并用于NPM安装。当NPM install再次运行时,它实际上会忽略依赖规范和package json,而是安装这些特定的版本。

Mozilla的NPM - locked模块甚至不仅列出了名称和版本,还保存了校验和,并在你再次运行NPM install时进行验证。所以即使一个特定的版本被覆盖了,如果有任何变化,npm会大声地失败,你会知道——你会知道包已经改变了。

如果您正在构建容器,则更容易,这些都不是问题。如果构建系统的结果是一个映像,那么所有的依赖项都被捆绑在该工件中。这个工件可以从一个环境传递到另一个环境,而不会有任何这些变化的问题。

但如果一切都被冻结了,如果你锁定了所有的依赖,你怎么能得到新的软件。如何管理对依赖项的更新?运行NPM obsolete可以帮助你跟踪过时的依赖项。它告诉你你落后了多远。

包以黄色列出,意味着该模块有一个新版本,但你的依赖规范不允许升级。红色,不确定你是否能看到它,但中间的ejs是红色的,这意味着你应该再次运行NPM install,这样你就可以得到一个新的兼容版本的模块。

为了尽量减少安全问题的意外,在构建管道上运行snky是一个非常好的主意。Snky是一个免费的开发工具,它根据名称和版本收集您的依赖项,并根据公共漏洞数据库查询该列表。所以它会警告你关于依赖的安全问题,这样你就知道要升级或降级到一个更安全的版本,或者只是完全离开那个依赖。

我们还在开发一个很酷的工具。所谓的披露。现在我想给大家展示一下。好吧。

因此,如果你在一个项目上运行disclosure,它也会查看你的依赖项列表,并尝试给你一个概述,如果它有效。我有网络吗?好吧。

所以我在hapi项目上运行这个,它列出了所有依赖项以及您所接触到的许可证。它让你对这些依赖的可靠性有了一个大致的了解。它试图查看诸如代码行数、是否有统计信息、软件包或版本是否已被弃用或过时等信息。我们想让它看看其他指标,比如GitHub上开放问题的数量以及它们被关闭的频率。源更新的频率。它还会告诉你,委托给snky。它将告诉您是否存在任何安全问题,并将尝试对您的依赖项进行评分。我想还有另一个例子。表达。

我们想让它开源。我现在就做。好了。所以我们期待人们使用它并得到贡献。好吧。

总而言之,不要在部署时运行NPM install,保留所有依赖项的副本,了解暴露的内容,可以使用disclosure,运行漏洞扫描,并尝试缩小依赖项的版本。就这些。谢谢你!

要么释放,要么死亡