nuxt&pm2:零停机部署

nuxt&pm2:零停机部署

中文版:

nuxt是一个非常棒的vue.js框架,它使得建立ssr站点变得非常简单。nuxt在引擎盖下使用node.js服务器来呈现服务器端的页面。
ssr有很多优点,在许多其他文章中都有深入的介绍,但是对于本文,我们将重点关注nuxt服务器的部署。
对于node.js应用程序来说,pm2是一个很好的进程管理器,它有许多很好的特性,包括通过“cluster mode”实现负载平衡。cluster mode创建node.js进程的多个实例,以便在不修改任何代码的情况下跨多个cpu扩展应用程序。
除了利用多个cpu的性能优势外,集群模式还允许通过一次重新加载一个实例来实现零停机部署。因此,如果您有4个实例在运行,您可以一次重新加载一个实例,而当一个实例正在重新加载时,其他3个实例将使服务器保持活动状态。因此,服务器可以在不离线的情况下更新一秒。
对于大多数节点应用程序来说,设置和使用pm2集群模式非常容易,但是我们在尝试将集群模式与nuxt服务器一起使用时遇到了一些问题。
首先,我们可以尝试使用以下命令启动nuxt服务器的单个实例:

pm2 start npm --name MyAppName -- start

image.png
image.png

但是,当尝试启动多个实例时,我们很快就会遇到问题。
例如,如果我们运行该命令两次,就会遇到错误。


image.png
image.png

现在,虽然默认情况下是在“fork”模式下运行,但即使指定集群模式,也会遇到错误。
如果我们只使用一个实例并尝试重新加载服务器呢?好吧,由于nuxt在幕后的工作方式,如果我们试图在服务器运行时重建它,那么在删除生成文件并为新的生成重新设置灰烬之后,我们将遇到404个错误。如果静态文件夹中的文件发生更改,我们也会遇到问题。
因此,如果我们不能重建和重新加载服务器,并且不能运行多个实例,那么我们如何实现零停机部署?

正确配置PM2集群模式

我们之前遇到问题是因为我们试图以“错误的方式”生成服务器的多个实例。在我们的实例中,我们让pm2执行'npm run start',实际上是启动npm脚本执行的多个实例,而不是直接正确地启动服务器。在启动实例后,我们可以在控制台中看到这一点:

[PM2] Starting /usr/bin/npm in fork_mode (1 instance)

如您所见,我们启动npm,然后通过命令行参数告诉npm启动服务器。相反,我们应该使用pm2直接调用服务器的启动脚本。使用以下命令启动nuxt服务器:

Nuxt start

但是,如果我们试图告诉PM2启动NUXT,它就不会起作用。相反,我们需要直接指向脚本nuxt调用,它位于

./node_modules/nuxt/bin/nuxt-start

现在用node_modules文件夹中的脚本启动pm2会很乏味,必须有更好的方法。谢天谢地,有!pm2允许我们创建一个生态系统文件,它基本上是pm2命令的配置文件。我们可以指定诸如要运行的脚本、工作目录、要生成多少实例以及别名等属性。您可以在这里看到所有可用的属性。

因此,现在我们知道需要运行什么脚本,并且知道需要使用什么设置来执行该脚本,我们可以通过运行以下命令来创建生态系统文件:

pm2 init

然后,我们将按如下方式配置此文件:

module.exports = {
    apps : [{
        name      : 'MyAppName', // App name that shows in `pm2 ls`
        exec_mode : 'cluster', // enables clustering
        instances : 'max', // or an integer
        cwd       : './current', // only if using a subdirectory
        script    : './node_modules/nuxt/bin/nuxt-start', // The magic key
    }]
};

您可能注意到我正在指定一个当前工作目录(CWD)。我这么做是因为这允许我们在幕后交换服务器代码,而不会遇到nuxt造成的限制。
我们通过创建如下文件结构来完成此操作:

/MyAppName
|--/releases
|----/v1.0.0
|----/v1.1.0
|----/v1.2.0
|----/...
|--/current -> /releases/v1.2.0 (symlink)
|--ecosystem.config.js

要启动服务器,只需在/myappname目录中运行以下命令:

pm2 start

现在要部署,我们只需将最新版本的repo克隆到“/releases”下的新文件夹,构建新版本(或者,您可以使用ci/cd服务提前构建该版本,并直接将这些构建文件上载到服务器)。然后我们将符号链接从/releases/v1.2.0更新到/releases/v1.3.0并运行:

pm2 reload MyAppName

image.png
image.png

成功!现在,您可以生成多个nuxt服务器实例以获得更好的性能(在多线程系统上),并利用零停机部署在更新期间保持网站

希望这能帮助你充分利用你的项目!

英文版:

Nuxt & PM2: Zero Downtime Deployment

Nuxt is an awesome framework for Vue.js that makes setting up an SSR site super simple. Nuxt uses a Node.js server under the hood in order to render pages server side.
There are many advantages to SSR, which are covered in depth in many other posts, but for this post we are going to be focusing on the deployment of a Nuxt server.
PM2 is a great process manager for Node.js applications, with many great features including load balancing through “cluster mode.” Cluster mode creates multiple instances of a Node.js process in order to allow applications to be scaled across multiple CPUs without any code modifications.
Besides the performance advantage of utilizing multiple CPUs, cluster mode also allows for a zero downtime deployment by reloading the server process one instance at a time. Thus if you have 4 instances running, you can reload the server one instance at a time, and while one instance is reloading, the other 3 instances will keep the server alive. Thus a server can be updated without being taken offline for even a second.
Setting up and using PM2 cluster mode is extremely easy for most node applications, however we run into some issues attempting to use cluster mode with a Nuxt server.
First we can try starting a single instance of our nuxt server with the following command:
$ pm2 start npm --name MyAppName -- start

image.png
image.png

But we quickly run into issues when trying to start multiple instances.
For example, if we run that command twice, we’ll run into errors.


image.png
image.png

Now while that is by default running in “fork” mode, even if we specify cluster mode, we run into errors.
What if we only use 1 instance and attempt to reload the server? Well due to how Nuxt works under the hood, if we attempt to rebuild the server while it’s running, we’ll hit 404 errors after the build files are removed and rehashed for the new build. We also run into issues if files in our static folder are changed.
So if we can’t just rebuild and reload a server, and we can’t run multiple instances, then how do we achieve a zero downtime deployment?

Properly Configure PM2 Cluster Mode

We were running into issues previously because we were attempting to spawn multiple instances of our server in the “wrong way”. In our instance we are having PM2 execute npm run start which essentially is starting multiple instances of npm script executions, and not properly launching our server directly. We can see this in our console after starting an instance:

[PM2] Starting /usr/bin/npm in fork_mode (1 instance)

As you can see, we’re starting npm and then telling npm to start our server through it’s command line arguments. Instead of this, we should be using PM2 to call the server’s start script directly. Starting a Nuxt server is done with the following command:

Nuxt start

However, if we try to tell PM2 to start Nuxt, it won’t work. Instead, we need to point directly to the script Nuxt calls, which is located in

./node_modules/nuxt/bin/nuxt-start

Now starting PM2 with a script from the node_modules folder is going to be tedious, there has to be a better way. Thankfully, there is! PM2 allows us to create an Ecosystem File, which is basically a configuration file for our PM2 commands. We can specify properties such as the script to run, the working directory, how many instances to spawn, and an alias name. You can see all available properties here.
So now that we know what script we need to run, and we know what settings we need to execute that script with, we can create the ecosystem file by running the following command:

pm2 init

We’ll then configure this file as such:

module.exports = {
    apps : [{
        name      : 'MyAppName', // App name that shows in `pm2 ls`
        exec_mode : 'cluster', // enables clustering
        instances : 'max', // or an integer
        cwd       : './current', // only if using a subdirectory
        script    : './node_modules/nuxt/bin/nuxt-start', // The magic key
    }]
};

You may notice I’m specifying a current working directory (cwd). I’m doing this because this is what allows us to swap our server code behind the scenes without running into the limitations caused by Nuxt.
We do this by creating a file structure like this:

/MyAppName
|--/releases
|----/v1.0.0
|----/v1.1.0
|----/v1.2.0
|----/...
|--/current -> /releases/v1.2.0 (symlink)
|--ecosystem.config.js

To start our server, we just need to run the following command from within the /MyAppName directory:

pm2 start

Now to deploy we just clone the latest version of our repo to a new folder under ‘/releases’, build our new version (or alternatively, you can use a CI/CD service to build that version ahead of time, and directly upload those build files to the server). Then we just update the symlink from /releases/v1.2.0 to /releases/v1.3.0 and run:

pm2 reload MyAppName

image.png
image.png

Success! You’re now able to spawn multiple instances of your Nuxt server for better performance (on multi threaded systems), AND take advantage of zero downtime deployments to keep your website online during updates.
Hopefully this helps you make the most out of your project!

参考:

Zero Downtime Deployment

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容