前端部署和提效:從靜態到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 上去就自動構建和部署了。若是你的公司還在用最原始的部署方式,不妨加把勁多探索一些這些更爽更溜的操做啦。

相關文章
相關標籤/搜索