部署与监控
阅读本指南后,您将了解
- 在部署 Meteor 应用程序之前需要考虑的事项。
- 如何部署到一些常见的 Meteor 托管环境。
- 如何设计部署流程以确保应用程序的质量得到维护。
- 如何使用分析工具监控用户行为。
- 如何监控您的应用程序。
- 如何确保您的网站被搜索引擎发现。
部署 Meteor 应用程序
构建并测试完 Meteor 应用程序后,您需要将其发布到线上,让全世界都能看到。部署 Meteor 应用程序类似于部署任何其他基于 Websocket 的 Node.js 应用程序,但在某些细节上有所不同。
部署 Web 应用程序从根本上不同于发布大多数其他类型的软件,因为您可以根据需要随时部署。您无需等待用户执行任何操作即可获取软件的新版本,因为服务器会将其直接推送到他们那里。
但是,彻底测试您的更改并进行良好的质量保证 (QA) 流程仍然很重要。尽管修复错误很容易,但这些错误仍然可能给用户造成重大问题,甚至可能导致数据损坏!
切勿使用 `--production` 标志进行部署!
--production
标志纯粹是为了模拟生产环境的代码压缩,但几乎不做其他任何事情。它仍然监视源代码文件,与包服务器交换数据,并且执行的操作远不止运行应用程序,从而导致不必要的计算资源浪费和安全问题。请勿使用--production
标志进行部署!
部署环境
在 Web 应用程序部署中,通常会引用三种运行时环境
- 开发环境。 指您开发新功能和运行本地测试的机器。
- 预发布环境。 一个与生产环境类似的中间环境,但对应用程序用户不可见。可用于测试和质量保证。
- 生产环境。 您客户当前正在使用的应用程序的实际部署。
预发布环境的目的是提供一个非用户可见的测试环境,该环境在基础设施方面尽可能接近生产环境。新代码在生产基础设施上出现的问题在开发环境中通常不会发生。一个非常简单的例子是涉及客户端和服务器之间延迟的问题——连接到具有极小延迟的本地开发服务器,您可能永远不会看到此类问题。
因此,开发人员倾向于使预发布环境尽可能接近生产环境。这意味着下面关于生产部署概述的所有步骤,如果可能,也应该应用于您的预发布服务器。
环境变量和设置
主要有两种方法可以在应用程序代码之外配置应用程序
- 环境变量。 这是在运行进程中设置的一组
ENV_VARS
。 - 设置。 这些设置位于一个 JSON 对象中,可以通过
--settings
Meteor 命令行标志设置,或者将其字符串化到METEOR_SETTINGS
环境变量中。
设置应用于设置特定于环境(例如预发布环境与生产环境)的内容,例如用于连接 Google 的访问令牌和密钥。这些设置在给定环境中运行应用程序的任何给定进程之间都不会更改。
环境变量用于设置特定于进程的内容,这些内容在应用程序进程的不同实例中可能会发生变化。环境变量列表可以在 此处找到。
关于存储这些设置的最后一点说明:将设置存储在与您保存应用程序代码相同的存储库中不是一个好主意。请阅读 安全文章中关于将设置放在何处的信息。
其他注意事项
在将应用程序部署到生产主机之前,您还应该考虑一些其他事项。请记住,如果可能,您应该对生产和预发布环境都执行这些步骤。
域名
用户将使用什么 URL 访问您的网站?您可能需要使用域名注册商注册域名,并设置 DNS 条目以指向该网站(这取决于您的部署方式,请参见下文)。如果您部署到 Galaxy,则在测试应用程序时可以使用 x.meteorapp.com
或 x.eu.meteorapp.com
域名。详细了解 Galaxy 域名 »
SSL 证书
对于 Meteor 应用程序,始终建议使用 SSL(请参阅 安全文章以了解原因)。获得注册域名后,您需要使用证书颁发机构为您的域名生成 SSL 证书。如果您部署到 Galaxy,您可以 一键生成免费的 SSL 证书(由 Let’s Encrypt 提供!)。
CDN
严格来说不是必需的,但通常建议为您的网站设置内容分发网络 (CDN)。CDN 是一组服务器,这些服务器在全球众多位置托管您网站的静态资产(例如 JavaScript、CSS 和图像),并使用最靠近用户的服务器来提供这些文件,以加快其交付速度。例如,如果您的应用程序的实际 Web 服务器位于美国东海岸,而您的用户在澳大利亚,则 CDN 可以托管网站 JavaScript 的副本在澳大利亚境内,甚至在用户所在的城市。这对网站的初始加载时间有巨大的好处。
使用 CDN 的基本方法是将您的文件上传到 CDN 并更改您的 URL 以指向 CDN(例如,如果您的 Meteor 应用程序位于 http://myapp.com
,则将图像 URL 从 <img src="http://myapp.com/cats.gif">
更改为 <img src="http://mycdn.com/cats.gif">
)。但是,对于 Meteor 来说,这很难做到,因为最大的文件——您的 Javascript 包——每次编辑应用程序时都会发生变化。
对于 Meteor,我们建议使用支持“源”的 CDN(例如 CloudFront),这意味着 CDN 不是预先上传您的文件,而是自动从您的服务器获取它们。您将文件放在 public/
中(在本例中为 public/cats.gif
),当您的澳大利亚用户向 CDN 请求 http://mycdn.com/cats.gif
时,CDN 在幕后获取 http://myapp.com/cats.gif
,然后将其传送给用户。虽然这比直接获取 http://myapp.com/cats.gif
稍慢,但它只会发生一次,因为 CDN 会保存该文件,并且所有随后请求该文件的澳大利亚用户都可以快速获得它。
要让 Meteor 使用 CDN 获取您的 Javascript 和 CSS 包,请在服务器上调用 WebAppInternals.setBundledJsCssPrefix("http://mycdn.com")
。这也会处理 CSS 文件中的相对图像 URL。如果需要使用动态前缀,则可以从传递给 WebAppInternals.setBundledJsCssUrlRewriteHook()
的函数中返回前缀。
对于 public/
中的所有文件,请将其 URL 更改为指向 CDN。您可以使用 assetUrl
等助手。
之前
<img src="http://myapp.com/cats.gif">
之后
Template.registerHelper("assetUrl", (asset) => {
return "http://mycdn.com/" + asset
});
<img src="{{assetUrl 'cats.gif'}}">
CDN 和网络字体
如果您将网络字体托管为应用程序的一部分并通过 CDN 提供服务,则可能需要配置为字体提供的标头以允许跨源资源共享(因为网络字体现在来自与您的网站本身不同的来源)。您可以在 Meteor 中通过添加处理程序来实现此目的(您需要确保您的 CDN 传递了标头)
import { WebApp } from 'meteor/webapp';
WebApp.rawConnectHandlers.use(function(req, res, next) {
if (req._parsedUrl.pathname.match(/\.(ttf|ttc|otf|eot|woff|woff2|font\.css|css)$/)) {
res.setHeader('Access-Control-Allow-Origin', /* your hostname, or just '*' */);
}
next();
});
然后例如使用 Cloudfront,您将
- 选择您的分发
- 行为选项卡
- 选择您的应用程序源
- 编辑按钮
- 在“白名单标头”下,向下滚动以选择“Origin”
- 添加按钮
- “是,编辑”按钮
部署选项
Meteor 是一个开源平台,您可以像运行常规 Node.js 应用程序一样在任何地方运行使用 Meteor 制作的应用程序。但是,如果手动管理基础设施,则正确操作 Meteor 应用程序(以便您的应用程序对所有人都有效)可能会很棘手。因此,我们建议在 Galaxy 上运行生产 Meteor 应用程序。
Galaxy(推荐)
最简单、最可靠的运行应用程序方法是使用 Galaxy,这是 Meteor Development Group 特别为运行 Meteor 应用程序而构建的服务。
Galaxy 是一个分布式系统,运行在 Amazon AWS 上。如果您了解正确运行 Meteor 应用程序需要什么以及 Galaxy 的工作原理,您将了解 Galaxy 的价值,并且它将为您节省大量时间和麻烦。如今,大多数大型 Meteor 应用程序都在 Galaxy 上运行,其中许多应用程序已从 Galaxy 发布之前使用的自定义解决方案切换过来。
为了部署到 Galaxy,您需要 注册一个账户,并单独配置一个 MongoDB 数据库(见下文)。
完成这些操作后,就可以轻松地部署到 Galaxy。您需要在设置文件中添加一些环境变量以将其指向您的 MongoDB,然后可以使用以下命令进行部署。
DEPLOY_HOSTNAME=galaxy.meteor.com meteor deploy your-app.com --settings production-settings.json
要部署到欧盟地区,请将 DEPLOY_HOSTNAME 设置为 eu-west-1.galaxy.meteor.com。
为了使 Galaxy 可以与您的自定义域名(在本例中为 your-app.com
)一起使用,您需要设置您的 DNS 以指向 Galaxy。完成此操作后,您应该能够从浏览器访问您的站点。
您还可以登录 https://galaxy.meteor.com 上的 Galaxy UI。登录后,您可以管理您的应用程序、监控连接数和资源使用情况、查看日志以及更改设置。
如果您遵循我们的建议,您可能需要为您的 Galaxy 应用程序设置 SSL,并使用您的域名的证书和密钥。您还应该阅读本指南的安全部分,了解如何强制将 HTTP 重定向到 HTTPS。
设置好 Galaxy 后,部署非常简单(只需重新运行上面的 meteor deploy
命令),扩展也一样——登录 galaxy.meteor.com,即可立即进行扩展。
Meteor Up
Meteor Up,通常称为“mup”,是一个第三方开源工具,可用于通过 SSH 将 Meteor 应用程序部署到任何在线服务器。它本质上是一种自动化使用 meteor build
并将该包放在服务器上的手动步骤的方法。它还负责设置服务器,包括安装任何依赖项以及设置负载均衡和 SSL。尽管它处理了许多细节,但它可能比使用托管服务更费力。
您可以从许多通用托管服务提供商处获取运行 Ubuntu 或 Debian 的服务器,并且 Meteor Up 可以使用您在配置中提供的密钥通过 SSH 连接到您的服务器。您可以从教程开始。
它的一个插件mup-aws-beanstalk 将 Meteor 应用程序部署到AWS Elastic Beanstalk 而不是服务器。它支持自动扩展、负载均衡和零停机时间部署,同时处理使用 Meteor 和 Elastic Beanstalk 的许多挑战。
Docker
为了编排您自己的基于容器的部署,在进行自定义部署之前,有一些现有的基础镜像需要考虑。
- tozd/docker-meteor,包含 Mongo 和 Nginx 镜像
- jshimko/meteor-launchpad
- disney/meteor-base
以上建议主要基于当前的维护状态,以解决上游安全漏洞。请查看 Dockerfile 和构建脚本,以进行自己的评估。
自定义部署
如果您想从头开始确定您的托管解决方案,Meteor 工具有一个命令 meteor build
可以创建包含普通 Node.js 应用程序的部署包。在发出 meteor build
命令之前必须安装任何 npm 依赖项才能包含在包中。您可以将此应用程序托管在任何您喜欢的地方,并且在如何设置和配置它方面有很多选择。
注意 务必为正确的架构构建您的包。如果您在开发机器上构建,则很有可能要部署到不同的服务器架构。您需要使用 --architecture
指定正确的架构。
# for example if deploying to a Ubuntu linux server:
npm install --production
meteor build /path/to/build --architecture os.linux.x86_64
这将为您提供一个打包的应用程序 .tar.gz
,您可以提取并运行它,而无需 meteor
工具。您选择的环境将需要正确的 Node.js 版本以及与 MongoDB 服务器的连接。
根据您使用的 Meteor 版本,您应该使用适合您平台的安装过程安装正确的 node
版本。要找出您应该使用哪个版本的 node
,请在开发环境中运行 meteor node -v
,或检查 meteor build
生成的包中的 .node_version.txt
文件。例如,如果您使用的是 Meteor 1.6,则您应该使用的 node
版本是 8.8.1。
如果您在部署应用程序时使用了不匹配的 Node 版本,将会遇到错误!
然后,您可以通过使用 ROOT_URL
、PORT
和 MONGO_URL
调用 node
来运行应用程序。这些说明也可在您上面构建的包的根目录中找到的 README
文件中找到。
cd my_build_bundle_directory
(cd programs/server && npm install)
MONGO_URL=mongodb://127.0.0.1:27017/myapp ROOT_URL=http://my-app.com PORT=3000 node main.js
ROOT_URL
是 Meteor 项目的基本 URLPORT
是应用程序运行的端口MONGO_URL
是 MongoDB 提供程序提供的Mongo 连接字符串 URI。
除非您有特别需要自行构建托管环境,否则此处提供的其他选项绝对更容易,并且可能比从头开始做所有事情提供更好的设置。以正确的方式为所有人运行 Meteor 应用程序可能很复杂,而Galaxy 处理了许多细节,例如将客户端路由到正确的容器以及为您处理协调的版本更新。
MongoDB 选项
部署 Meteor 服务器时,需要一个指向 MongoDB 数据库的 MONGO_URL
。您可以使用托管的 MongoDB 服务,也可以设置和运行您自己的 MongoDB 服务器。我们建议使用托管服务,因为节省的时间和安心感通常值得更高的月度成本。无论哪种情况,数据库都应托管在与 Meteor 服务器相同的区域(以降低延迟)。例如,如果您的应用程序托管在 us-east-1
(在 AWS 上)的 Galaxy 上,则可以在Compose 的 AWS us-east-1
或Amazon Lightsail 的 us-east-1
中创建一个数据库。
托管服务(推荐)
有很多服务可供选择,我们建议您根据您的需求选择以下服务之一
为生产环境选择托管 MongoDB 服务时,务必评估服务提供的功能。以下是在选择服务时需要考虑的功能的非详尽列表
- 支持您希望运行的 MongoDB 版本
- 存储引擎支持 (MMAPv1 或 WiredTiger) – 自 Meteor 1.4 以来,WiredTiger 是默认的存储引擎
- 支持副本集和 Oplog 尾随
- 监控和自动警报
- 持续备份和自动快照
- 访问控制、IP 白名单和 AWS VPC 对等互连
- 传输中和静止状态下的数据加密
- 成本和定价粒度
- 实例大小和选项
- 实例可配置性 – 独立配置您的 CPU、内存、存储和磁盘 I/O 速度。
您可以阅读 OK GROW! 编写的这篇详细指南,了解在 MongoDB Atlas 上部署生产就绪 MongoDB 数据库的分步说明。
自己的服务器
您可以在您自己的服务器上安装 MongoDB——您拥有、租用或 VPS(推荐)如DigitalOcean 或Lightsail。从上一节可以看出,数据库设置和维护的许多方面都需要您来处理。例如,为了获得最佳性能,您应该选择一个具有足够大的SSD以容纳您的数据,并具有足够的 RAM 以将工作集(索引 + 活动文档)存储在内存中的服务器。
部署流程
尽管部署 Web 应用程序比发布大多数其他类型的软件要容易得多,但这并不意味着您应该对部署掉以轻心。在将发布版本推送到生产环境之前,正确地进行 QA 和测试非常重要,以确保用户不会遇到不良体验,或者更糟糕的是,数据损坏。
最好有一个发布流程,以便在发布应用程序时遵循该流程。通常,该流程如下所示
- 将新版本的应用程序部署到您的暂存服务器。
- 在暂存服务器上对应用程序进行 QA。
- 修复步骤 2 中发现的任何错误,然后重复。
- 一旦您对暂存发布版本满意,就将完全相同的版本发布到生产环境。
- 在生产环境中运行最终 QA。
步骤 2 和 5 可能非常耗时,尤其是在您希望在应用程序中保持高水平质量的情况下。这就是为什么开发一套验收测试是一个好主意(有关更多信息,请参阅我们的测试文章)。为了更进一步,您可以在每次发布时对暂存服务器运行负载/压力测试。
持续部署
持续部署是指通过持续集成工具部署应用程序的过程,通常在满足某些条件时(例如,将 git 推送到 master
分支)。您可以使用 CD 部署到 Galaxy,正如 Nate Strauser 在一篇关于此主题的博文中所解释的那样。
滚动部署和数据版本
了解部署过程中发生的事情非常重要,尤其是在您的部署涉及数据格式更改(以及潜在的数据迁移,请参阅集合文章)时。
当您在多台服务器或容器上运行应用程序时,最好不要一次关闭所有服务器,然后再次全部启动它们。这会导致比必要更多的停机时间,并且当所有客户端同时重新连接时,会导致 CPU 使用率大幅飙升。为了缓解这种情况,Galaxy 在部署过程中会逐个停止并重新启动容器。在一段时间内,一些容器将运行旧版本,而一些容器将运行新版本,因为用户会逐渐迁移到新版本的应用程序。
如果新版本涉及数据库中不同的数据格式,那么您需要更加小心地逐步完成版本,以确保所有同时运行的版本都可以协同工作。您可以在集合文章中阅读有关如何执行此操作的更多信息。
通过分析监控用户
通常希望了解应用程序中哪些页面访问次数最多以及用户来自哪里。以下设置将帮助您使用 Google Analytics 进行 URL 跟踪。我们将使用okgrow:analytics
包。
meteor add okgrow:analytics
现在,我们需要使用我们的 Google Analytics 密钥配置包(该包还支持各种其他提供商,请查看Atmosphere 上的文档)。将其作为 Meteor 设置 的一部分传递。
{
"public": {
"analyticsSettings": {
// Add your analytics tracking id's here
"Google Analytics" : {"trackingId": "Your tracking ID"}
}
}
}
分析包挂接到 Flow Router(有关更多信息,请参阅路由文章)并为您记录所有页面事件。
您可能还想跟踪与页面更改无关的事件(例如发布订阅或方法调用)。为此,您可以使用自定义事件跟踪功能。
export const updateText = new ValidatedMethod({
...
run({ todoId, newText }) {
// We use `isClient` here because we only want to track
// attempted method calls from the client, not server to
// server method calls
if (Meteor.isClient) {
analytics.track('todos.updateText', { todoId, newText });
}
// ...
}
});
要为订阅/发布实现类似的抽象,您可能希望为Meteor.subscribe()
编写一个包装器。
监控您的应用程序
当您在生产环境中运行应用程序时,务必密切关注应用程序的性能并确保其平稳运行。
了解 Meteor 性能
尽管存在大量工具可以监控 HTTP、基于请求-响应的应用程序的性能,但它们提供的见解不一定对像 Meteor 应用程序这样的连接客户端系统有用。虽然 HTTP 响应时间缓慢确实会成为您应用程序的问题,因此使用像Pingdom这样的工具可以发挥作用,但您的应用程序存在许多此类工具无法发现的问题。
使用 Galaxy 监控
Galaxy 提供了交钥匙的 Meteor 托管服务,并提供了有助于调试应用程序当前状态和过去状态的工具。CPU 和内存负载图表结合连接的用户数量对于确定您的设置是否能够处理当前负载(或者您是否需要更多容器)或是否存在导致不成比例负载的特定用户操作至关重要(如果它们似乎没有相关性)
Galaxy 的 UI 提供了一个详细的日志记录系统,这对于确定导致额外负载的操作或通常调试其他应用程序问题非常有价值。
APM
如果您真的想了解运行 Meteor 应用程序的来龙去脉,则应使用应用程序性能监控 (APM) 服务。有多种服务专为 Meteor 应用程序设计。
这些 APM 通过定期对应用程序在执行各种活动时的客户端和服务器端性能进行观察并将结果报告回主服务器来运行。
当您访问 APM 时,您可以查看应用程序在各种有用指标上的当前和过去行为。APM 有关于如何充分利用数据来改进您的应用程序的文档,但我们将在本文中讨论一些关键领域。屏幕截图类似于您在 Meteor APM 或 Monti APM 中看到的屏幕截图。
方法和发布延迟
在 Meteor 应用程序中,与其监控 HTTP 响应时间,不如考虑 DDP 响应时间更有意义。客户端将等待的两个 DDP 操作是方法调用和发布订阅。APM 包括可帮助您发现哪些方法和发布缓慢且资源密集型。
在上面的屏幕截图中,您可以看到 Atmosphere 应用程序通常调用的各种方法的响应时间细分。56 毫秒的中值时间和 200 毫秒的第 99 个百分位数时间似乎相当合理,并且似乎没有太多值得关注的地方。
您还可以使用“跟踪”部分来发现方法调用的特定案例,这些案例特别缓慢。
在上面的屏幕截图中,我们正在查看方法调用的一个较慢的示例(需要 214 毫秒),当我们进一步深入研究时,我们发现它主要用于等待用户连接上的其他操作(主要是等待searches/top
和counts
发布)。因此,我们可以考虑加快这些订阅的初始时间,因为在某些情况下,它们会稍微减慢搜索速度。
Livequery 监控
Meteor 的一个关键性能特征是由 livequery 的行为驱动的,livequery 是一项关键技术,它允许您的发布自动实时推送更改数据。为了实现这一点,livequery 需要监控您的 MongoDB 实例以进行更改(通过跟踪操作日志)并确定给定更改是否与给定发布相关。
如果发布被大量用户使用,或者有很多更改需要比较,那么这些 livequery 观察者可以完成很多工作。因此,Kadira 可以告诉您有关 livequery 用法的一些统计信息,这一点非常有用。
在此屏幕截图中,我们可以看到观察者相当稳定地创建和销毁,随着时间的推移重用量非常低,尽管总的来说它们不会持续太长时间。这与我们正在查看 Atmosphere 的package
发布相一致,该发布在用户每次访问特定包的页面时都会启动。行为或多或少是我们预期的,因此我们可能不会太担心这些信息。
启用 SEO
如果您的应用程序包含大量公开可访问的内容,那么您可能希望它在 Google 和其他搜索引擎的索引中排名靠前。由于大多数网络爬虫不支持客户端渲染(或者如果它们支持,则对 Websocket 的支持参差不齐),因此在这种特殊情况下,最好在服务器端渲染站点并将其作为 HTML 提供。
如果您使用Galaxy 托管您的 Meteor 应用程序,则可以利用内置的自动Prerender.io 集成。将mdg:seo
添加到您的应用程序中,Galaxy 将负责其余工作:加载代码并使用 Galaxy 提供的凭据对其进行配置。
如果您不使用 Galaxy,您仍然可以使用mdg:seo
。您需要注册自己的 Prerender.io 帐户并将您的令牌提供给Meteor.settings
中的mdg:seo
包。如果您使用 Galaxy 但希望使用自己的 Prerender.io 帐户并更频繁地更改缓存,也可以执行此操作。您也可以直接使用prerender-node
NPM 包,模仿 Atmosphere 包中少量客户端和服务器代码;如果您需要使用比mdg:seo
中的版本更新的 NPM 包,请执行此操作。
您可能还想设置<title>
标签和其他<head>
内容,以使您的网站在搜索结果中显示得更漂亮。最好的方法是使用kadira:dochead
包。从页面级组件的onCreated
回调中调用DocHead
是明智之举。