现在你已经创建(并测试)了一个不错的 本地图书馆 网站了,你打算把它发布到一个公共网络服务器,这样图书馆职工和网络上的其他成员就可以访问它了。这篇文章总结了你可以怎样找到一台主机部署你的网站,以及你需要为站点准备到生产环境做什么。

预备知识: 完成前面所有的指南主题,包括 Express Tutorial Part 6: Working with forms.
目标: 学习你可以怎样以及在哪里部署一个Express 应用到生产环境。

概览

一旦您的站点完成(或完成“足够”以开始公共测试),您将需要将其托管在比您的个人开发计算机,更公开和可访问的地方。

到目前为止,您一直在开发环境中工作,使用 Express / Node 作为Web服务器,将您的站点共享到本地浏览器/网络,并使用(不安全的)开发设置运行您的网站,以显示调试和其他私人信息。在您可以在外部托管网站之前,您首先必须:

  • 选择托管Express 应用程序的环境。
  • 对项目设置进行一些更改。
  • 设置生产级别的基础架构,以服务您的网站。

本教程提供了,有关选择托管站点的选项的一些指导,简要概述了为使您的Express 应用程序准备好生产,所需执行的操作,以及如何将LocalLibrary 网站安装到 Heroku云托管上的工作示例服务。

请记住,您不必使用Heroku  - 还有其他托管服务可用。我们还提供了一个单独的教程,以展示如何在 PWS/Cloud Foundry 上安装LocalLibrary。

什么是生产环境?

生产环境是服务器计算机提供的环境,您可以在其中运行网站,以供外部使用。环境包括:

  • 网站运行的计算机硬件。
  • 操作系统(例如Linux或Windows)。
  • 编程语言运行库和框架库,在其上编写您的网站。
  • Web 服务器基础结构,可能包含Web服务器,反向代理,负载平衡器等。
  • 您的网站所依赖的数据库。

服务器计算机,可以位于您的场所,并通过快速链接,连接到 Internet,但使用 “托管在云上” 的计算机更为常见。这实际上意味着,您的代码运行在托管公司的数据中心的某台远程计算机(或可能是“虚拟”计算机)。远程服务器,通常会以特定价格提供互联网连接,和一些保证级别的计算资源(例如CPU,RAM,存储器等)。

这种可远程访问的计算/网络硬件,称为基础架构即服务(IaaS)。许多IaaS 供应商,提供预安装特定操作系统的选项,您必须在其上,安装生产环境的其他组件。其他供应商,允许您选择功能更全面的环境,可能包括完整的 node 设置。

注意: 预构建环境,可以使您的网站设置变得非常简单,因为它们会减少配置,但可用选项可能会限制您使用不熟悉的服务器(或其他组件),并且可能基于较旧版本的操作系统。通常最好自己安装组件,以便获得所需的组件,并且当您需要升级系统的某些部分时,您可以知道从哪里开始!

其他托管服务提供商,支持 Express 作为平台即服务(PaaS)产品的一部分。使用此类托管时,您无需担心大多数生产环境(服务器,负载平衡器等),因为主机平台会为您处理这些问题。这使得部署非常简单,因为您只需要专注于 Web 应用程序,而不是任何其他服务器基础结构。

一些开发人员选择 IaaS ,相对于 PaaS ,IaaS 提供更高灵活性,而其他开发人员偏好 PaaS 的降低维护开销,和更轻松的扩展性。当您在一开始使用时,在 PaaS 系统上设置您的网站,要容易得多,因此我们将在本教程中使用 PaaS。

提示: 如果您选择Node/Express友好的托管服务提供商,他们应该提供,有关如何使用Web服务器,应用程序服务器,反向代理等不同配置,来设置 Express 网站的说明。例如,在数字海洋node社区文档中,有许多各种配置的手把手指南。

选择一个主机供应商

众所周知,众多托管服务提供商,都积极支持或与Node(和Express)合作。这些供应商提供不同类型的环境(IaaS,PaaS),以及不同价格的不同级别的计算和网络资源。

提示: 有很多托管解决方案,他们的服务和定价,可能会随着时间而改变。虽然我们在下面介绍几个选项,但在选择托管服务提供商之前,有必要自己进行互联网搜索。

选择主机时需要考虑的一些事项:

  • 您的网站可能有多忙,以及满足该需求所需的数据,和计算资源的成本。
  • 水平扩展(添加更多机器)和垂直扩展(升级到更强大的机器)的支持级别,以及这样做的成本。
  • 供应商有数据中心的地方,因此访问可能是最快的。
  • 主机正常运行时间和停机时间的历史表现。
  • 用于管理站点的工具 - 易于使用且安全(例如 SFTP 与 FTP)。
  • 用于监控服务器的内置框架。
  • 已知限制。有些主机会故意阻止某些服务(例如电子邮件)。其他在某些价格层中,仅提供一定数小时的 “实时时间”,或者仅提供少量存储空间。
  • 额外的好处。一些提供商将提供免费域名和SSL证书支持,否则您将不得不为此另外支付费用。
  • 您所依赖的“免费”等级,是否会随着时间的推移而过期,以及迁移到更昂贵等级的成本,是否意味着您最好在一开始就使用其他服务!

当你刚开始时,好消息是有很多网站提供“免费”的计算环境,尽管有一些条件。例如, Heroku “永远” 提供免费但资源有限的PaaS 环境,而 Amazon Web Services, Microsoft Azure 和开源选项 PWS/Cloud Foundry 在您第一次加入时,提供免费信用额度。

许多提供商还拥有“基本”层,可提供更多有用的计算能力,和更少的限制。举例来说, Digital Ocean 是一个流行的托管服务提供商,它提供了一个相对便宜的基本计算层(在本教程写作时,是每月5美元的较低范围)。

注意: 请记住,价格不是唯一的选择标准。如果您的网站成功,可能会发现可扩展性是最重要的考虑因素。

准备好发布你的网站

发布网站时,要考虑的主要问题是网络安全性和性能。至少,您需要删除开发期间,错误页面上包含的堆栈跟踪,整理日志记录,并设置适当的标头,以避免许多常见的安全威胁。

在以下小节中,我们概述了您应该对应用进行的、最重要的更改。

提示: Express文档中还有其他有用的提示 - 请参阅“生产最佳实践:性能和可靠性”,以及“生产最佳实践:安全性”。

设置 NODE_ENV 为 'production'

我们可以通过将 NODE_ENV 环境变量,设置为 production ,来删除错误页面中的堆栈跟踪(默认设置为 “development” )。除了生成较为不详细的错误消息之外,还要将变量设置为生产缓存视图模板,和从CSS扩展生成的CSS文件。测试表明,将NODE_ENV设置为生产,可以将应用程序性能提高三倍!

可以使用导出或环境文件,或使用OS初始化系统,以进行此更改。

注意: 这实际上是在环境设置,而不是应用中所做的更改,但重要的是,要注意这里!我们将在下面,展示如何为我们的托管示例设置。

Log appropriately

记录呼叫会对高流量网站产生影响。在生产环境中,您可能需要记录网站活动(例如,跟踪流量,或记录API调用),但您应尝试最小化为调试目的而添加的日志记录量。

在生产环境中,最小化“调试”日志记录的一种方法,是使用类似调试debug 的模块,允许您通过设置环境变量,来控制执行的日志记录。例如,下面的代码片段,显示了如何设置“author”日志记录。调试变量使用名称“author”声明,并且将自动显示,来自此对象的所有日志的前缀“author”。

var debug = require('debug')('author');

// Display Author update form on GET
exports.author_update_get = function(req, res, next) {   
    
    req.sanitize('id').escape().trim();
    Author.findById(req.params.id, function(err, author) {
        if (err) {
            debug('update error:' + err);
            return next(err);
        }
        //On success
        res.render('author_form', { title: 'Update Author', author: author });
    });

};

然后,您可以通过在DEBUG环境变量中,将它们指定为逗号分隔列表,来启用特定日志集。您可以设置显示作者和书籍日志的变量,如图所示(也支持通配符)。

#Windows
set DEBUG=author,book

#Linux
export DEBUG="author,book" 

挑战: 调用debug可以替换您以前使用console.log()console.error()执行的日志记录。通过调试模块debug进行日志记录,替换代码中的所有console.log()调用。通过设置 DEBUG 变量,并在其中记录对日志记录的影响,在开发环境中,打开和关闭日志记录。

如果您需要记录网站活动,可以使用 Winston 或 Bunyan 等日志库。有关此主题的更多信息,请参阅:生产最佳实践:性能和可靠性

使用 gzip/deflate 压缩响应文件

Web服务器,通常可以压缩发送回客户端的 HTTP 响应,从而显着减少客户端获取和加载页面所需的时间。使用的压缩方法,取决于客户端在请求中支持的解压缩方法(如果不支持压缩方法,则响应将以未压缩的方式发送)。

您可以使用压缩中间件 compression,将其添加到您的站点。通过在项目的根目录下,运行以下命令,将其安装到项目中。

npm install compression

打开./app.js,并导入压缩库,如图所示。使用use()方法,将压缩库添加到中间件链(这应该出现在您想要压缩的任何路由之前 - 在本教程这种情况下,全部都是!)

var catalogRouter = require('./routes/catalog'); //Import routes for "catalog" area of site
var compression = require('compression');

// Create the Express application object
var app = express();

...

app.use(compression()); //Compress all routes

app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/catalog', catalogRouter);  // Add catalog routes to middleware chain.

...

注意: 对于生产中流量较大的网站,您不会使用此中间件。相反,你会使用像 Nginx 这样的反向代理。

使用 Helmet 避免被常见漏洞侵袭

Helmet 是一个中间件包,可以通过设置适当的 HTTP 标头,来帮助保护您的应用,免受一些众所周知的 Web 漏洞的影响(有关它设置的标头/防护漏洞的详细信息,请参阅文档)。

通过在项目的根目录下,运行以下命令,将其安装到项目中。

npm install helmet

打开./app.js,并导入如图所示的 helmet 库。然后使用use()方法将模块添加到中间件链。

var compression = require('compression');
var helmet = require('helmet');

// Create the Express application object
var app = express();

app.use(helmet());
...

注意: 上面的命令,添加了对大多数站点有意义的可用标头子集。您可以按照npm上的说明,根据需要添加/禁用特定标头。

例子:在 Heroku 上安装一个本地图书馆

本节提供了如何在Heroku PaaS cloud云上安装LocalLibrary的实际演示。

为什么选择 Heroku?

Heroku 是运行时间最长,且最受欢迎的基于云的 PaaS 服务之一。它最初只支持 Ruby 应用程序,但现在可用于托管来自许多编程环境的应用程序,包括Node(以及Express)!

我们选择使用 Heroku 有以下几个原因:   

  • Heroku 有一个免费套餐(尽管有一些限制)。
  • 作为PaaS,Heroku为我们提供了大量的 Web 基础架构。这使得入门更加容易,因为您不必担心服务器,负载平衡器,反向代理,崩溃时重新启动网站,或者 Heroku 为我们提供的任何其他 Web 基础结构。
  • 虽然它确实有一些限制,但这些不会影响这个特定的应用程序。例如:
    • Heroku只提供短期存储,因此用户上传的文件无法安全地存储在Heroku本身。
    • 如果半小时内没有请求,免费套餐将使不活动的网络应用程序进入睡眠。然后,该网站可能需要几秒钟才能被唤醒。
    • 免费套餐将您网站运行的时间,限制为每月一定的小时数(不包括网站“睡着”的时间)。这对于低使用/演示站点来说很好,但如果需要100%的正常运行时间,则不适用。
    • Heroku 官方文档中列出的其他限制。
  • 大多数情况下它只是可以工作,如果你最终喜欢它,并希望升级,那么扩展你的应用程序非常容易。

虽然 Heroku 非常适合举办此演示,但它可能并不适合您的真实网站。 Heroku可以轻松设置和扩展,但代价是灵活性较低,而且一旦退​​出免费套餐,可能会花费更多。

 Heroku 如何工作?

Heroku在一个或多个“Dynos”中运行网站,这些“Dynos”是独立的虚拟化Unix容器,提供运行应用程序所需的环境。 Dynos 是完全隔离的,并且有一个短暂的文件系统(一个短暂的文件系统,每次dyno重新启动时都会清理/清空)。 dynos 默认共享的唯一内容,是应用程序配置变量。 Heroku内部使用负载均衡器,将Web流量分配给所有“web”dynos。由于它们之间没有任何共享,Heroku可以通过添加更多dynos,来水平扩展应用程序(当然,您可能还需要扩展数据库,以接受其他连接)。

由于文件系统是短暂的,因此无法直接安装应用程序所需的服务(例如数据库,队列,缓存系统,存储,电子邮件服务等)。相反,Heroku Web应用程序使用 Heroku 或第三方作为独立“附加组件”提供的支持服务。连接到Web应用程序后,可以通过环境变量,在Web应用程序中访问附加服务。

为了执行您的应用程序,Heroku需要能够设置适当的环境和依赖关系,并了解它是如何启动的。对于Node应用程序,它所需的所有信息都是从package.json文件中获取的。

开发人员使用特殊的客户端应用程序/终端,与Heroku交互,这很像Unix bash脚本。这允许您上传存储在git存储库中的代码,检查正在运行的进程,查看日志,设置配置变量等等!

为了让我们的应用程序在Heroku上工作,我们需要将我们的Express Web应用程序放入git存储库,并对 package.json 进行一些小的更改。完成后,我们可以设置Heroku帐户,获取Heroku客户端,并使用它来安装我们的网站。

这是您开始教程所需的全部概述(有关更全面的指南,请参阅带有Node.js的Heroku入门)。

在 Github 上创建一个应用仓库

Heroku 与 git 源代码版本控制系统紧密集成,使用它来上传/同步您对实时运行系统所做的任何更改。它通过添加一个名为 heroku 的新 Heroku“远程”存储库,来指向您在Heroku云上的源存储库。在开发期间,您使用 git 在“主”存储库 master 中存储更改。如果要部署站点,请将更改同步到 Heroku 存储库。

注意: 如果您习惯于遵循良好的软件开发实践,那么您可能已经在使用git或其他一些SCM系统。如果您已有git存储库,则可以跳过此步骤。

有很多方法可以使用git,但最简单的方法之一,是首先在GitHub上建立一个帐户,在那里创建存储库,然后在本地同步它:

  1. 访问 https://github.com/ 并创建一个帐户。
  2. 登录后,单击顶部工具栏中的 + 号链接,然后选择新建存储库New repository
  3. 填写此表单上的所有字段。虽然这些不是强制性的,但强烈建议使用它们。
    • 输入新的存储库名称(例如,express-locallibrary-tutorial)和描述(例如 “以Express(node)编写的本地图书馆网站”)。
    • 在 Add .gitignore 选择列表中选择 Node
    • 在添加许可证 Add license 选择列表中,选择您偏好的许可证。
    • 点选 使用自述文件初始化此存储库 Initialize this repository with a README
  4. Create repository.
  5. 单击新仓库页面上的绿色“克隆或下载”按钮 "Clone or download"。
  6. 从显示的对话框的文本字段,复制URL值(它应该类似于:https://github.com/<your_git_user_id>/express-locallibrary-tutorial.git)。

现在创建了存储库(“repo”),我们将要在本地计算机上克隆它:

  1. 为您的本地计算机安装git(您可以在此处找到不同平台的版本)。
  2. 打开命令提示符/终端,并使用您在上面复制的 URL ,克隆clone存储库:
    git clone https://github.com/<your_git_user_id>/express-locallibrary-tutorial.git
    
    这将在当前时间点之后,创建存储库。
  3. 到新的仓库。
    cd express-locallibrary-tutorial

最后一步,是复制你的应用程序,然后使用 git ,将文件添加到你的仓库:

  1. 将Express应用程序,复制到此文件夹中(不包括/node_modules,其中包含您应根据需要,从NPM获取的依赖项文件)。
  2. 打开命令提示符/终端,并使用add命令,将所有文件添加到 git。
  3. git add -A
    
  4. 使用 status 命令,检查要添加的所有文件是否正确(您希望包含源文件,而不是二进制文件,临时文件等)。它应该看起来有点像下面的列表。
    > git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    Changes to be committed:
      (use "git reset HEAD <file>..." to unstage)
    
            new file:   ...
  5. 如果您满意,请将文件提交到本地存储库:
    git commit -m "First version of application moved into github"
  6. 然后使用以下内容,将本地存储库同步到Github网站:
    git push origin master

完成此操作后,您应该可以返回创建存储库的Github上的页面,刷新页面,并查看您的整个应用程序现已上传。使用此添加/提交/推送循环,您可以在文件更改时,继续更新存储库。

提示: 这是备份你的“vanilla”项目的好时机 - 虽然我们将在以下部分中进行的一些更改,可能对任何平台(或开发)上的部署有用,而一些其他的更改可能没有用。

执行此操作的最佳方法,是使用git来管理您的修订。使用git,您不仅可以回到特定的旧版本,而且可以在生产变更的单独“分支”中进行维护,并选择在生产和开发分支之间移动的任何更改。学习Git非常值得,但超出了本主题的范围。

最简单的方法,是将文件复制到另一个位置。使用最符合您对 git 了解的方法!

更新Heroku的应用程序

本节介绍了您需要对 LocalLibrary 应用程序进行的更改,以使其在Heroku上运行。

设置 node 版本

package.json包含解决应用程序依赖项所需的所有内容,以及启动站点时,应启动的文件。 Heroku检测到此文件的存在,并将使用它来配置您的应用程序环境。

我们当前的package.json中,缺少的唯一有用信息,是 node 的版本。我们可以通过输入命令,找到我们用于开发的 node 版本:

>node --version
v8.9.1

打开package.json,并将此信息添加为engines > node 部分,如图所示(使用系统的版本号)。

{
  "name": "express-locallibrary-tutorial",
  "version": "0.0.0",
  "engines": {
    "node": "8.9.1"
  },
  "private": true,
  ...

数据库配置

到目前为止,在本教程中,我们使用了一个硬编码到app.js的单个数据库。通常我们希望,能够为生产和开发创建不同的数据库,接下来我们将修改 LocalLibrary 网站,以从OS环境获取数据库URI(如果已定义),否则使用我们的开发数据库。

打开app.js,并找到设置mongoDB连接变量的行。它看起来像这样:

var mongoDB = 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';

使用以下代码替换该行,该代码使用process.env.MONGODB_URI从名为MONGODB_URI的环境变量中,获取连接字符串(如果已设置)(使用您自己的数据库URL,而不是下面的占位符。)

var mongoDB = process.env.MONGODB_URI || 'mongodb://your_user_id:your_password@ds119748.mlab.com:19748/local_library';

安装依赖并重新测试

在我们继续之前,让我们再次测试该网站,并确保它不受我们的任何更改的影响。

首先,我们需要获取我们的依赖项(你会记得,我们没有将 node_modules文件夹,复制到我们的 git 树中)。您可以通过在项目根目录的终端中,运行以下命令来执行此操作:

npm install

现在运行该站点(请参阅测试路由的相关命令),并检查该站点,是否仍按预期运行。

将更改保存到 Github

接下来,让我们将所有更改保存到 Github。在终端中(在我们的存储库中),输入以下命令:

git add -A
git commit -m "Added files and changes required for deployment to heroku"
git push origin master

我们现在应该准备开始在 Heroku 上,部署 LocalLibrary。

获取一个 Heroku 账户

要开始使用Heroku,您首先需要创建一个帐户(如果您已经拥有一个帐户,并安装了Heroku客户端,请跳过创建并上传网站):

  • 访问 www.heroku.com ,并单击免费注册按钮 SIGN UP FOR FREE
  • 输入您的详细信息,然后按CREATE FREE ACCOUNT。系统会要求您,检查帐户中是否有注册电子邮件。
  • 单击注册电子邮件中的帐户激活链接。您将在网络浏览器上收回您的帐户。
  • 输入您的密码,然后单击 SET PASSWORD AND LOGIN.
  • 然后,您将登录并进入Heroku仪表板:https://dashboard.heroku.com/apps.

安装客户端

按照 Heroku上的说明,下载并安装Heroku客户端。

安装客户端后,您将能够运行命令。例如,要获得客户端的帮助说明:

heroku help

创建并上传网站

要创建应用程序,我们在存储库的根目录中,运行“create”命令。这将在我们的本地git环境中,创建一个名为 heroku 的 git remote(“指向远程存储库的指针”)。

heroku create

注意: 如果您愿意,可以在“创建”create 之后指定远程存储库的命名。如果你不这样做,你会得到一个随机的名字。该名称用于默认URL。

然后,我们可以将我们的应用程序,推送到Heroku存储库,如下所示。这将上传应用程序,获取所有依赖项,将其打包到dyno中,然后启动该站点。

git push heroku master

如果我们很幸运,该应用程序现在正在网站上“运行”。要打开浏览器并运行新网站,请使用以下命令:

heroku open

注意: 该站点将使用我们的开发数据库运行。创建一些书本和其他对象,并检查该网站是否按预期运行。在下一节中,我们将其设置为使用我们的新数据库。

设定配置变量

您将从前一节回忆起,我们需要将NODE_ENV设置为'production',以便提高性能,并生成更简洁的错误消息。我们通过输入以下命令,来完成此操作:

>heroku config:set NODE_ENV='production'
Setting NODE_ENV and restarting limitless-tor-18923... done, v13
NODE_ENV: production

我们还应该使用单独的数据库进行生产,在MONGODB_URI环境变量中,设置其URI。您可以完全按照我们原来的方式,设置新数据库和数据库用户,并获取其URI。您可以如下图所示设置URI(显然,要使用您自己的URI!)

>heroku config:set MONGODB_URI='mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production'
Setting MONGODB_URI and restarting limitless-tor-18923... done, v13
MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production

您可以使用heroku config命令,随时检查配置变量 - 立即尝试:

>heroku config
=== limitless-tor-18923 Config Vars
MONGODB_URI: mongodb://your_user:your_password@ds139278.mlab.com:39278/local_library_production
NODE_ENV:    production

Heroku会在更新变量时,重新启动应用程序。如果您现在检查主页,它应该显示对象计数的零值,因为上面的更改,意味着我们现在正在使用新的(空)数据库。

管理附加组件

Heroku 使用独立的附加组件,为应用程序提供支持服务 - 例如电子邮件或数据库服务。我们不在本网站中使用任何插件,但它们是使用Heroku的重要部分,因此您可能需要查看主题管理插件(Heroku docs)。

调试

Heroku客户端提供了一些调试工具:

heroku logs  # Show current logs
heroku logs --tail # Show current logs and keep updating with any new results
heroku ps   #Display dyno status

总结

本教程介绍在生产环境中,如何配置Express 应用。是Express系列教程的最后一个。我们希望你觉得这些教程有用。你可以在Github上取得完整的源码

相关链接

 

本教程链接

 

文档标签和贡献者

此页面的贡献者: edgar-chen, codeofjackie
最后编辑者: edgar-chen,