用例- #取消发布发生-如何保护你的Node.js投资
文摘:
Igor Soarez /首席工程师/ YLD, 2016年5月:归根结底,npm是一个注册表,它是一个与Node.js捆绑在一起的工具。但它也有一定的权衡。
依赖npm进行构建和部署的利弊是什么?我们如何处理这个问题?最好的指导方针是什么?
您不能依赖社区来支持您的业务,开源开发人员不为您的公司工作,您不能在公共包存储库上支持您的生产环境。
你需要检查一下安全措施。您需要保证部署到生产环境中的版本始终相同。因为注册表是一个外部依赖项,所以需要降低这种风险。该解决方案不能由不提供SLA的第三方维护——您需要能够依赖于用于部署的任何东西。我们的目标是提出一个解决这个问题的架构。
讨论转录:
我是伊戈尔。我做Node已经有四年多了。我帮助过从初创公司到大企业的各种公司采用Node。构建框架,微服务,基本的web开发,所有的工作。
我为YLD工作。YLD是一家总部位于伦敦的咨询公司。我们已经这样做了大约两年半了。YLD是由Nodejitsu的创始人创立的。Nodejitsu是Node应用程序的参考平台服务。他们现在已经被收购了。当时,运行公共NPM注册的是Nodejitsu和YLD的创始人。我们是Node基金会的创始成员。这是一个涵盖Node.js项目的基础。
我们在行业中交付软件的方式已经发生了变化。我们将这一系列变化视为工程的未来。比尔·斯科特是我们公司的顾问,他在贝宝公司做了这些改变。这就是把工作分解成小的、有才华的、独立的团队。并时刻关注客户价值。我们认为Node是促进这种变化的一个很好的工具。
Node社区已经走过了很长的一段路。它的发展速度令人难以置信,从许多方面来看,Node是目前发展最快、最重要的开发语言。它有400万用户,我们看到它的增长每年都翻一番。尤其是在企业领域,自去年以来,该技术的采用率上升了400%。节点无处不在。
就在不久前,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是在一个基金会下管理的,由对它有投资兴趣的公司组成,而公共NPM注册表是由一家名为NPM Inc.的私人公司运行和管理的。因此,每个做Node的人共享他们工作的公共注册中心是由一家私人公司控制的。 It’s not under the control of the foundation.
当你安装Node时,你会得到NPM和一个NPM配置,默认情况下它会使用或指向NPM公司运行的公共注册中心。如果出于某种原因,公共NPM注册表不可用,那么整个团队的开发就会停止。如果您试图在公共注册表不可用的情况下安装旧模块,将会看到这种情况。在这个实例中,我们试图安装joi包。但你得到的不是快乐,而是沮丧。
由于各种各样的原因,公共登记处可能已经关闭。即使它没有下降,它也可能很慢。您最不希望看到的就是您的团队频繁地等待免费的公共注册表。
比构建和部署的开发还要糟糕得多。每次构建被触发时,你都需要运行NPM install。如果NPM安装失败,整个构建也会失败。这将推迟发布周期。如果在部署时运行NPM install,结果可能会更糟。持续部署和集成管道(在部署过程中容量减少)可能会给可用的生产实例带来不必要的压力。
记住,如果你在使用NPM,可怕的事实是你在依赖陌生人。你正在使用他们的软件包。使用公共注册中心会使您受任意数量的包作者的摆布。最近NPM因为破坏了互联网而出现在媒体上。像WordPress。com这样的网站也受到了影响。开发人员决定删除这个小包,因为它是数百个其他包的依赖项,破坏了数千个项目。在此事件之后,公共注册中心现在不允许删除已发布的包。但是开源贡献仍然有很多方式可以影响您的项目。
如果考虑安全性,您只需要一个坏模块。同样,节点的方式是有许多小的依赖关系,做一件事和一件事。但是,如果平均而言,Node模块的特定版本存在安全问题的可能性为0.5%。那么一个有30个依赖项的项目,有15%的机会支持安全漏洞。这很可怕。即使它不是一个安全更新,即使它不是一个安全问题,如果它只是一个错误或不兼容的更新,这已经足够糟糕了。因为有这么多的依赖关系,你不想被困在特定的版本上,不得不手动更新每一个版本。但是由于每天都有如此多的公共NPM包更新,很有可能从你测试和部署它开始,你就会得到不同的软件。更好的工作和更快的软件是很好的,但这也可能是破坏性的变化或错误。不可预测的变化是不可接受的风险。
在旧项目中,依赖项是用范围指定的。有很多方法可以指定这些范围。您可以引用特定的版本。您可以允许高于特定版本的任何版本。如果你使用波浪线,那就允许新的补丁。如果你使用一个插入符号,也允许新的小版本,但不允许大版本,所以有不同的方法。指导方针和默认的指定方式一直备受争议,并且已经改变了很多次。
NPM建议使用semver进行应用程序版本控制。这是一组试图将兼容的更改与不兼容的更改分开的规则。但实际上,这完全取决于包的作者是否遵守这一规则。如果您所依赖的包没有遵循semver,这可能会产生问题。或者,新版本的包有突破性的变化。而且,即使包的作者遵循semver,仍然有可能在兼容版本中引入错误。
选择依赖项已经很困难了。这些都是你需要考虑的事情。比如许可、发布频率、作者是否对开放问题做出了响应、测试覆盖率等等。如果有大量的依赖关系,就会加剧这个问题。
如果你已经看到了所有这些问题,你能做些什么呢?我们从中得到了什么教训?第一条也是最重要的规则是在部署时不要运行NPM install。我们看到这种情况的次数多得惊人。如果注册表不可用,或者由于某种原因NPM安装失败,那么当你需要它们时,你可能没有足够的供应服务器。相反,您应该尝试部署预构建的工件。
您还需要掌握您所依赖的软件。即使在构建这些工件时,也不希望依赖于公共注册中心。
所以解决方案是保留一个缓存,在你的控制下保留每个依赖项的副本。在过去,Node社区一直建议应用程序应该检查它们在源代码控制中的依赖关系。本质上是将依赖项捆绑或提供到应用程序中。
但这可能会很麻烦。由于原生模块的存在,NPM包中包含了C和c++代码和makefile,而不仅仅是JavaScript。安装这些文件时,需要对它们进行编译。这将针对不同开发人员机器的特定架构。它会因目标环境的不同而不同。所以每次你签出项目,你只做NPM重建,你需要对签入源代码控制的文件非常有选择性。这可能是一场噩梦。更不用说diff读起来会令人不愉快。而整个版本控制系统将变成一个难以处理的问题。
更好的解决方案是使用私有包存储库。到公共注册中心的缓存代理。每次添加新的依赖项时,都将它持久地缓存在您的控制之下。Artifactory是我们大多数客户使用的产品。它支持NPM,您可以将其配置为公共注册中心的缓存代理。一旦你开始使用你的依赖项,它就会被缓存,如果NPM不可用,如果一个包被拉出来,如果任何麻烦来了,你都是安全的。您拥有继续开发、构建和部署所需的东西。它还允许您将公共包发布到自己的私有包存储库。这很好。
设置起来真的很简单。您所需要做的就是配置NPM。更改此配置文件并为注册表设置不同的端点。我想做一个演示,但我觉得在飞机上做会更酷。
所以我用手机拍了下来。而且我的笔记本电脑连不上。我在hapi项目,这是一个流行的节点web开发框架。我删除了所有的依赖项。检查注册表的npm配置。我们将看到它指向在Docker上本地运行的Artifactory。然后我们运行NPM install,即使公共注册表不可用,因为所有的模块都缓存在Artifactory下,你仍然可以安装。
这就解决了可用性问题。但是更新呢?在切割和测试之间[…]会对你的依赖项进行更新。即使您不使用版本范围,即使您指定项目依赖于特定的版本,这也只能解决直接依赖的问题。它不能解决瞬态依赖关系的问题。
解决方法就是使用NPM收缩膜。如果你在你的项目上运行npm shrinkwrap,它会创建一个文件,列出当前安装的所有npm模块的名称和特定版本。这个文件,你应该检查到版本控制将被NPM和NPM安装引用。当NPM install再次运行时,它实际上会忽略依赖规范和package json,而是安装这些特定的版本。
这个被Mozilla称为NPM -锁定的模块甚至不仅列出了名称和版本,而且还保存了校验和,当你再次运行NPM install时,它会验证它们。所以即使一个特定的版本被覆盖了,如果有任何变化,npm会大声失败,你会知道包已经改变了。
如果您正在构建容器,那么这些都不是问题。如果构建系统的结果是一个映像,那么所有依赖项都捆绑在该工件中。而且这个工件可以从一个环境传递到另一个环境,没有任何这些变化的问题。
但如果一切都冻结了,如果你锁定了所有依赖项,你如何获得新软件。如何管理对依赖项的更新?运行NPM expired可以帮助你跟踪过时的依赖项。它告诉你你落后了多远。
以黄色显示的包表示该模块有新版本,但依赖项规范不允许升级。红色,不确定你是否能看到,但中间的ejs是红色的,这意味着你应该再次运行NPM install,这样你就能得到一个模块的新兼容版本。
为了尽量减少安全问题的意外,在构建管道上运行snky是一个非常好的主意。Snky是一个免费的开发工具,它可以根据名称和版本收集依赖项,并根据公共漏洞数据库查询列表。所以它会警告你依赖关系的安全问题,让你知道升级或降级到更安全的版本,或者完全摆脱依赖关系。
我们还在研究一个很酷的工具。所谓的披露。我现在就给你们看。好的。
因此,如果你在一个项目上运行披露,它也会查看你的依赖项列表,并尝试给你一个概述,如果它工作。我有网络吗?好的。
我在hapi项目上运行这个,它列出了所有的依赖关系以及你接触到的许可。它可以让您大致了解这些依赖关系的可靠性。它试图查看诸如代码行数,是否有统计信息,包或版本是否已弃用或过时。我们想让它看看其他指标,比如GitHub上的开放问题数量,以及它们被关闭的频率。源更新的频率。它还会告诉你,委托给snky。它会告诉你是否有任何安全问题,并会尝试给你的依赖项评分。我想还有另一个例子。表达。
我们想让它开源。我现在就做。好了。所以我们期待人们使用它并得到贡献。好吧。
总结一下,不要在部署时运行NPM install,保留所有依赖项的副本,知道你暴露了什么,你可以使用公开,运行漏洞扫描,并尝试缩小依赖项的版本。仅此而已。谢谢你!
