相信不少前端同窗对 vue 或 react 的开发很熟悉了,也知道如何去打包生成一个生产环境的包,但对于生产环境的部署可能有些同窗了解比较少。小公司可能都是后端帮忙部署了,大公司会有专门的运维同窗部署,对于生产环境的部署工做有些同窗接触的很少,因此此次来分享和总结下前端项目部署相关的实战经验:从静态站点的部署,到 node 项目的部署,再到负载均衡的部署,顺便也会分享一下提升部署效率的脚本和方法。javascript
静态站点的部署指的是前端的 html/css/js 资源的部署,如 vue 或 react 打包后生成的 html,css 和 js 文件,咱们将这些文件上传到服务器后,经过 Nginx 将这些资源暴露到公网上。css
就是将文件人工将打包后的文件拷贝到服务器上,这个很简单,但若是每次都是人工拷贝,部署效率未免会低了一些,因此建议使用一些脚本或工具。在大公司,通常对服务器权限控制得很严格,可能须要各类跳板机或动态密码等,而大公司通常都有专门的运维人员或者 CI/CD 工具。html
小公司可能相对自由一些,能够容许我的直接 ssh 链接服务器,此时能够配合使用rsync
或scp
命令(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 用户是无法跑这个命令的。
上传文件到服务器后,就能够着手配置 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 reload
nginx
若是上一步配置的域名是已经解析到服务器 ip 了的,就能够直接在公网上经过访问域名来访问你的站点了。若是不是,能够修改一下本机的 host 文件,使得配置的域名能够在本机访问;或者经过http://localhost
来访问。
node 项目在开发时能够用node app.js
这样的命令来启动服务,但在服务器上若是使用这个命令,退出服务器后 node 进程就中止了,因此须要借助可让 node 进程 keep alive 的工具。如今通常都是用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
通常来讲,咱们能够直接使用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
。
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 创建四个虚拟机来模拟四个服务器(固然条件确实限制时能够用同一个服务器的四个端口来代替)。
笔者新建了四个 Centos8 系统的虚拟机,用以假设 4 台服务器,对外都有独立 ip(假设分别是 192.168.0.1
,2
,3
,4
)。如前面的架构图所示,Centos1 将会是做为Nginx Server
,充当最前端的负载均衡服务器,而其他的Centos2
,Centos3
,Centos4
做为应用服务器,为用户提供真正的服务。接下来我们一步一步去搭建这个系统。
万丈高楼平地起,我们首先得先搭建一个能对外的服务,这个服务能够是一个网站也能够是一个接口。为了简单起见,咱们就直接起一个koa
的Hello World
,同时为了后面验证负载均衡的效果,每台机器上部署的代码都稍微改一下文案,如:Hello Centos2
,Hello Centos3
,Hello Centos4
,这样方便后面验证用户的请求是被分发到了哪一台服务器。
koa 的 demo 站点已经为你们准备好了:koa-loadbalance。
咱们这里以Centos2(192.168.0.2)
(ip 是虚构的)这台虚拟机为例,将会用pm2
部署 koa 站点在该虚拟机上。
还记得上面的deploy.sh
脚本吗?若是你添加了脚本在项目中,就能够npm run deploy
直接部署到服务器上了。demo 源码中有这个脚本,你们能够改一下里面实际的 ip,再执行命令哈。
ssh root@192.168.0.2
curl -sL https://rpm.nodesource.com/setup_13.x | sudo bash - sudo yum install nodejs
能够在这里看当前 node 有哪些版本,选最新的就行,如今是 13。
npm i pm2 -g
在项目根目录执行:
pm2 start pm2.json
pm2 list
检查一下项目启动状况 ,同时用curl localhost:3000
看返回值:
同理,按上面步骤给Centos3
和Centos4
服务器都将服务部署起来。(记得改一下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 进行代理或转发了。
nginx 的安装方法:Nginx Install。
在Centos1
安装好 nginx 就能够了。
一开始还没了解过负载均衡时可能会以为很难彻底不知道是怎么配的,而后接下来你会发现超级简单,由于只须要 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
重启一下,这样就完成负载均衡的配置了。
若是你的域名是真实的且已经解析到 nginx 服务器,则此时能够直接经过域名访问了。因为笔者这里用的是虚拟机,公网不可访问,因此这里配置一下宿主机的 host,使得www.a.com
指向centos1
服务器,而后在浏览器打开www.a.com
就能够测试咱们的负载均衡网站啦。Mac 系统上是sudo vi /etc/hosts
,在最后面添加一行:
# IP是Centos1的ip 192.168.0.1 www.a.com
咱们在浏览器访问www.a.com
,能够看到随着不断刷新,服务器返回了不一样的Hello CentosX
,说明咱们的请求被分发到三台服务器上了,负载均衡的配置生效啦。
nginx 的 upstream 能够设置不少种负载均衡的策略,如下介绍几个经常使用的策略。
upstream test { server 192.168.0.2:3000; server 192.168.0.3:3000; server 192.168.0.4:3000; }
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; }
upstream test { ip_hash; server 192.168.0.2:3000; server 192.168.0.3:3000; server 192.168.0.4:3000; }
upstream test { server 192.168.0.2:3000; server 192.168.0.3:3000; server 192.168.0.4:3000; fair; }
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 上去就自动构建和部署了。若是你的公司还在用最原始的部署方式,不妨加把劲多探索一些这些更爽更溜的操做啦。