前端部署和提效:从静态到node再到负载均衡

前言

相信不少前端同窗对 vue 或 react 的开发很熟悉了,也知道如何去打包生成一个生产环境的包,但对于生产环境的部署可能有些同窗了解比较少。小公司可能都是后端帮忙部署了,大公司会有专门的运维同窗部署,对于生产环境的部署工做有些同窗接触的很少,因此此次来分享和总结下前端项目部署相关的实战经验:从静态站点的部署,到 node 项目的部署,再到负载均衡的部署,顺便也会分享一下提升部署效率的脚本和方法。javascript

准备工做

  1. 一台或多台服务器或虚拟机。
  2. 一份 vue 或 react 项目的打包后的文件。
  3. 一份 node 项目的源码。

静态站点的部署

静态站点的部署指的是前端的 html/css/js 资源的部署,如 vue 或 react 打包后生成的 html,css 和 js 文件,咱们将这些文件上传到服务器后,经过 Nginx 将这些资源暴露到公网上。css

  1. 上传文件到服务器

就是将文件人工将打包后的文件拷贝到服务器上,这个很简单,但若是每次都是人工拷贝,部署效率未免会低了一些,因此建议使用一些脚本或工具。在大公司,通常对服务器权限控制得很严格,可能须要各类跳板机或动态密码等,而大公司通常都有专门的运维人员或者 CI/CD 工具。html

小公司可能相对自由一些,能够容许我的直接 ssh 链接服务器,此时能够配合使用rsyncscp命令(Linux 或 Mac 系统)来一键上传文件到服务器上,给部署提效。在这里分享一下之前使用过的部署脚本,在前端项目根目录新建一个名为deploy.sh的文件:前端

#!/bin/bash

function deploy() {
  # 测试服务器
  test_host="root@test_server_ip"
  # 生产服务器
  prod_host="root@prod_server_ip"
  project_path="/srv/YourProject"

  if [ "$1" == "prod" ]; then
    target="$prod_host:$project_path"
  else
    target="$test_host:$project_path"
  fi

  rsync -azcuP ./dist/ --exclude node_modules --exclude coverage --exclude .env --exclude .nyc_output --exclude .git "$target"
  echo "deploy to $target"
}

deploy $@

以上脚本的意思是将/dist目录下的全部文件,上传到对应服务器的/srv/YourProject目录下。测试环境的部署是直接在根目录运行./deploy.sh,该命令会将/dist目录直接上传到root@test_server_ip服务器上;vue

生产环境的部署是在后面加一个参数./deploy.sh prod,这样能够实现多环境部署。更进一步的作法是将运行脚本的命令直接写进package.json中,如:java

"scripts": {
    "build": "vue-cli-service build --mode staging",
    "deploy": "npm run build && ./deploy.sh",
    "deploy:prod": "npm run build && ./deploy.sh prod"
  },

这样,经过npm run deploy命令就能够实现直接打包并部署到测试环境了。若是你的公司目前还在用人工拷贝或 FTP 工具这种低效的部署方式,不妨试一下用上面的脚原本提效哦。node

PS:因为 rsync 命令只在 Linux 或 Mac 才有,因此只有开发环境是 Linux 或 Mac 的用户才能够运行哦,Windows 用户是无法跑这个命令的。
  1. 编写网站的 conf

上传文件到服务器后,就能够着手配置 nginx 了。通常 nginx 的配置都会放在/etc/nginx/conf.d目录下,咱们在该目录新建一个test.conf做为该项目的配置:react

server {
    listen       80;
    server_name your-domain.com; # 域名
    location / {
        root   /srv/YourProject; # 网站源码根目录
        index index.html;
    }
    location /api {
        proxy_pass http://localhost:8080; # 反向代理后端接口地址
    }
}

通常来讲,静态站点只需配置以上几个就能够了,linux

  • server_name表示域名,须要先解析到服务器的公网 ip;
  • root表示服务器中代码所在的位置,
  • index指明了默认的处理文件是index.html
  • location /api是反向代理后端服务(这里假设了后端服务部署在本地 8080 端口),即your-domain.com/api的请求都会转发到http://localhost:8080上,通常用该方法能够完美解决前端跨域的问题。

修改 nginx 的 conf 后须要 reload 一下 nginx 服务:nginx -s reloadnginx

  1. 测试

若是上一步配置的域名是已经解析到服务器 ip 了的,就能够直接在公网上经过访问域名来访问你的站点了。若是不是,能够修改一下本机的 host 文件,使得配置的域名能够在本机访问;或者经过http://localhost来访问。

node 项目的部署

node 项目在开发时能够用node app.js这样的命令来启动服务,但在服务器上若是使用这个命令,退出服务器后 node 进程就中止了,因此须要借助可让 node 进程 keep alive 的工具。如今通常都是用pm2

  1. 安装 pm2
npm install -g pm2

pm2 的一些经常使用命令:

pm2 start app.js              # 启动app.js应用程序
pm2 start app.js -i 4         # cluster mode 模式启动4个app.js的应用实例     # 4个应用程序会自动进行负载均衡
pm2 start app.js --name="api" # 启动应用程序并命名为 "api"
pm2 start app.js --watch      # 当文件变化时自动重启应用
pm2 start script.sh           # 启动 bash 脚本
pm2 list                      # 列表 PM2 启动的全部的应用程序
pm2 monit                     # 显示每一个应用程序的CPU和内存占用状况
pm2 show [app-name]           # 显示应用程序的全部信息
pm2 logs                      # 显示全部应用程序的日志
pm2 logs [app-name]           # 显示指定应用程序的日志
pm2 flush
pm2 stop all                  # 中止全部的应用程序
pm2 stop 0                    # 中止 id为 0的指定应用程序
pm2 restart all               # 重启全部应用
pm2 reload all                # 重启 cluster mode下的全部应用
pm2 gracefulReload all        # Graceful reload all apps in cluster mode
pm2 delete all                # 关闭并删除全部应用
pm2 delete 0                  # 删除指定应用 id 0
pm2 scale api 10              # 把名字叫api的应用扩展到10个实例
pm2 reset [app-name]          # 重置重启数量
pm2 startup                   # 建立开机自启动命令
pm2 save                      # 保存当前应用列表
pm2 resurrect                 # 从新加载保存的应用列表
pm2 update                    # Save processes, kill PM2 and restore processes
pm2 generate                  # Generate a sample json configuration file
pm2 deploy app.json prod setup    # Setup "prod" remote server
pm2 deploy app.json prod          # Update "prod" remote server
pm2 deploy app.json prod revert 2 # Revert "prod" remote server by 2
pm2 module:generate [name]    # Generate sample module with name [name]
pm2 install pm2-logrotate     # Install module (here a log rotation system)
pm2 uninstall pm2-logrotate   # Uninstall module
pm2 publish                   # Increment version, git push and npm publish
  1. 用 pm2 启动项目

通常来讲,咱们能够直接使用pm2 start app.js --name="my-project"这样的命令来启动 node 项目,可是这样手打的命令会很差管理,因此咱们通常会在 node 项目的根目录下新建一个pm2.json文件来指定 pm2 启动时的参数,如:

{
  "name": "my-project",
  "script": "./server/index.js",
  "instances": 2,
  "cwd": ".",
  "exec_mode" : "cluster"
}

name 表示 pm2 进程的名称,script 表示启动的文件入口,instances 表示启动的示例数量(通常建议数值不大于服务器处理器的核数),cmd 表示应用程序所在的目录。

咱们在服务器启动 node 项目时就能够直接pm2 start pm2.json

  1. nginx 代理绑定域名

node 项目使用 pm2 运行后,只是运行在服务器的某个端口,如http://server_ip:3000,若是该服务须要经过域名直接访问,则还须要用 nginx 代理到 80 端口。在/etc/nginx/conf.d新建一个my-project.conf(文件命名随意哈,通常能够用网站域名.conf):

server {
    listen       80;
    server_name  your-domain.com;
    location / {
        proxy_pass http://localhost:3000;
    }
}

这是最简单的一个配置了,能够根据实际状况加一些参数哈。作完以上的步骤就完成了一个 node 项目的部署啦。

前端负载均衡部署

相信不多同窗能够接触到负载均衡的部署了,当一个项目的访问量已经大到须要使用负载均衡的时候,通常都会有专门的运维同窗去搞了。负载均衡说白了就是将大量的并发请求分担到多个服务器上。

负载均衡的架构有不少种,项目的架构是一个不断演进的过程,采用哪一种负载均衡的架构须要具体问题具体分析,因此本文不会讲何时适合用哪一种架构(笔者也不会,笑),接下来将会分享实战如何用 Nginx 从零搭建一个经典的负载均衡架构案例。


Nginx Server是直接暴露在最前端的机器,当用户发起请求,首先到达的是Nginx服务器,而后Nginx服务器再将请求经过某种算法分发到各个二级服务器上(图中的Centos2,Centos3,Centos4),此时Nginx Server充当的就是一个负载均衡的机器(Load Balancer)。

笔者手上没有这么多的服务器,为了更完整地演示,因此如今借助 VirtualBox 创建四个虚拟机来模拟四个服务器(固然条件确实限制时能够用同一个服务器的四个端口来代替)。

WechatIMG160.png
笔者新建了四个 Centos8 系统的虚拟机,用以假设 4 台服务器,对外都有独立 ip(假设分别是 192.168.0.1,2,3,4)。如前面的架构图所示,Centos1 将会是做为Nginx Server,充当最前端的负载均衡服务器,而其他的Centos2,Centos3,Centos4做为应用服务器,为用户提供真正的服务。接下来我们一步一步去搭建这个系统。

1、应用服务器搭建服务站点

万丈高楼平地起,我们首先得先搭建一个能对外的服务,这个服务能够是一个网站也能够是一个接口。为了简单起见,咱们就直接起一个koaHello World,同时为了后面验证负载均衡的效果,每台机器上部署的代码都稍微改一下文案,如:Hello Centos2,Hello Centos3,Hello Centos4,这样方便后面验证用户的请求是被分发到了哪一台服务器。

koa 的 demo 站点已经为你们准备好了:koa-loadbalance

咱们这里以Centos2(192.168.0.2)(ip 是虚构的)这台虚拟机为例,将会用pm2部署 koa 站点在该虚拟机上。

  1. 经过 scp 或 rsync 命令将源码上传到 Centos2 服务器

还记得上面的deploy.sh脚本吗?若是你添加了脚本在项目中,就能够npm run deploy直接部署到服务器上了。demo 源码中有这个脚本,你们能够改一下里面实际的 ip,再执行命令哈。

  1. ssh 进入 Centos2 服务器
ssh root@192.168.0.2
  1. 安装 node 环境
curl -sL https://rpm.nodesource.com/setup_13.x | sudo bash -
sudo yum install nodejs

能够在这里看当前 node 有哪些版本,选最新的就行,如今是 13。

  1. 安装 pm2
npm i pm2 -g
  1. pm2 启动站点

在项目根目录执行:

pm2 start pm2.json

pm2 list检查一下项目启动状况 ,同时用curl localhost:3000看返回值:

WechatIMG165.png

同理,按上面步骤给Centos3Centos4服务器都将服务部署起来。(记得改一下index.js中的Hello XXX方便后面验证)。不出意外的话,咱们的网站就分别运行在三台服务器的 3000 端口了:

  • 192.168.0.2:3000 ==> Hello Centos2
  • 192.168.0.3:3000 ==> Hello Centos3
  • 192.168.0.4:3000 ==> Hello Centos4
有同窗可能会问,为何 Centos2,Centos3,Centos4 不用装 Nginx 的?在实际操做中,应用服务器实际上是不用暴露在公网上的,它们与负载均衡服务器只需经过内网直接链接就能够了,这样更安全;而咱们的站点又是 Node 项目,自己就能够提供 Web 服务,因此不用再装一个 Nginx 进行代理或转发了。

2、搭建 Nginx Server

nginx 的安装方法:Nginx Install

Centos1安装好 nginx 就能够了。

3、实现负载均衡

一开始还没了解过负载均衡时可能会以为很难彻底不知道是怎么配的,而后接下来你会发现超级简单,由于只须要 nginx 一个配置就能够了:upstream

  • 集群全部节点

咱们将上面已经部署好的Centos2,Centos3,Centos4集群起来,nginx 配置相似下面这样:

upstream APPNAME {
    server host1:port;
    server host2:port;
}

APPNAME能够自定义,通常是项目名。在/etc/nginx/conf.d新建一个upstream.conf

upstream koa-loadbalance {
    server 192.168.0.2:3000;
    server 192.168.0.3:3000;
    server 192.168.0.4:3000;
}

这样,咱们已经将三台服务器集成为了http://koa-loadbalance的一个集群,下一步会使用它。

  • 配置对外的站点

接下来是配置一个面向用户的网站了,咱们假设网站会使用www.a.com这个域名,在/etc/nginx/conf.d下新建a.com.conf:

server {
    listen 80;
    server_name www.a.com;
    charset utf-8;
    location / {
        proxy_pass http://koa-loadbalance; # 这里是上面集群的名称
    }
}

配置结束后记得nginx -s reload重启一下,这样就完成负载均衡的配置了。

4、测试

若是你的域名是真实的且已经解析到 nginx 服务器,则此时能够直接经过域名访问了。因为笔者这里用的是虚拟机,公网不可访问,因此这里配置一下宿主机的 host,使得www.a.com指向centos1服务器,而后在浏览器打开www.a.com就能够测试咱们的负载均衡网站啦。Mac 系统上是sudo vi /etc/hosts,在最后面添加一行:

# IP是Centos1的ip
192.168.0.1 www.a.com

image

咱们在浏览器访问www.a.com,能够看到随着不断刷新,服务器返回了不一样的Hello CentosX,说明咱们的请求被分发到三台服务器上了,负载均衡的配置生效啦。

5、负载均衡的几种策略

nginx 的 upstream 能够设置不少种负载均衡的策略,如下介绍几个经常使用的策略。

  1. 轮询(默认):每一个请求按时间顺序逐一分配到不一样的后端服务器,若是后端服务器 down 掉,能自动剔除。
upstream test {
    server 192.168.0.2:3000;
    server 192.168.0.3:3000;
    server 192.168.0.4:3000;
}
  1. 指定权重 weight:指定轮询概率,weight 和访问比率成正比,用于后端服务器性能不均的状况。
upstream test {
    server 192.168.0.2:3000 weight=5;
    server 192.168.0.3:3000 weight=10;
    server 192.168.0.4:3000 weight=20;
}
  1. ip_hash:每一个请求按访问 ip 的 hash 结果分配,这样每一个访客固定访问一个后端服务器,能够解决 session 的问题。
upstream test {
    ip_hash;
    server 192.168.0.2:3000;
    server 192.168.0.3:3000;
    server 192.168.0.4:3000;
}
  1. fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream test {
    server 192.168.0.2:3000;
    server 192.168.0.3:3000;
    server 192.168.0.4:3000;
    fair;
}
  1. url_hash(第三方):按访问 url 的 hash 结果来分配请求,使每一个 url 定向到同一个(对应的)后端服务器,后端服务器为缓存时比较有效。
upstream test {
    server 192.168.0.2:3000;
    server 192.168.0.3:3000;
    server 192.168.0.4:3000;
    hash $request_uri;
    hash_method crc32;
}

更多的策略请参考:ngx_http_upstream_module,根据实际状况使用上面的这些策略,没有特别需求就使用默认的轮询方式也能够。

最后

从静态站点到 node 站点,再到负载均衡,相信看完本文你们对整个前端的部署体系都有了一个比较全面的了解。特别是负载均衡,平时接触得少总以为特别复杂,其实看完了会以为很简单。更高级一些的部署可能会用上 Docker 或 k8s 的集群了,这个就留待后面再说啦。

对于部署方式的提效,本文也分享了一个使用rsync命令的脚步,配合package.json的 script,能够作到一个命令就完成部署的动做。

固然,该作法也仍是有很大的优化空间的,真正好用的部署方式应该是持续集成,经过 Jenkins 或其余工具实现自动化部署,代码 push 上去就自动构建和部署了。若是你的公司还在用最原始的部署方式,不妨加把劲多探索一些这些更爽更溜的操做啦。

相关文章
相关标签/搜索