目錄
* 一. 需求描述 <https://www.cnblogs.com/dashnowords/p/11293667.html#一.-需求描述>
* 二. 預(yù)備知識 <https://www.cnblogs.com/dashnowords/p/11293667.html#二.-預(yù)備知識>
* IP+端口訪問 <https://www.cnblogs.com/dashnowords/p/11293667.html#ip端口訪問>
* 域名訪問 <https://www.cnblogs.com/dashnowords/p/11293667.html#域名訪問>
* 三. Nodejs應(yīng)用的手動部署
<https://www.cnblogs.com/dashnowords/p/11293667.html#三.-nodejs應(yīng)用的手動部署>
* 四. 基于nodejs的自動部署
<https://www.cnblogs.com/dashnowords/p/11293667.html#四.-基于nodejs的自動部署>
* 4.1 package.json中的scripts
<https://www.cnblogs.com/dashnowords/p/11293667.html#package.json中的scripts>
* 4.2 自動化發(fā)布腳本deploy.js
<https://www.cnblogs.com/dashnowords/p/11293667.html#自動化發(fā)布腳本deploy.js>
* 4.3 遠端腳本deploy.sh
<https://www.cnblogs.com/dashnowords/p/11293667.html#遠端腳本deploy.sh>
* 五. 小結(jié) <https://www.cnblogs.com/dashnowords/p/11293667.html#五.-小結(jié)>
示例代碼托管在:http://www.github.com/dashnowords/blogs
<http://www.github.com/dashnowords/blogs>
博客園地址:《大史住在大前端》原創(chuàng)博文目錄 <https://www.cnblogs.com/dashnowords/p/10127926.html>
華為云社區(qū)地址:【你要的前端打怪升級指南】
<https://bbs.huaweicloud.com/blogs/8ae7e6420a4611e9bd5a7ca23e93a891>
一. 需求描述
前端工程出包后實現(xiàn)簡易的自動化部署。
二. 預(yù)備知識
網(wǎng)站的建設(shè)可以使用任何自己熟悉的框架,三大框架都有自己的官方Cli工具,從代碼編寫到生成可用于生產(chǎn)環(huán)境部署的包基本都有自動化命令,各個打包工具也在零配置
的追求上做了很多工作。本篇中從得到一個生產(chǎn)環(huán)境的包以后開始,對站點部署的相關(guān)知識進行一些介紹。
首先你需要一個Web服務(wù)器,常見的有:
* Nginx
* Tomcat
* Apache或相關(guān)集成環(huán)境
* XAMMP【Apache+MySQL+PHP+PERL 】
* LAMP【Linux+Apache+MySQL+PHP】
* nodejs或相關(guān)框架+守護進程
* Express
* Koa2
以上任何一種在服務(wù)器上運行起來后都可以擔任Web服務(wù)器的角色,只是具備的擴展功能和應(yīng)用場景有區(qū)別,Nginx
基本上是正式環(huán)境部署的首選方案。常見的基本部署方案如下:
IP+端口訪問
使用訪問,可直接訪問對應(yīng)端口的服務(wù),部署方式相對簡單:
域名訪問
使用域名訪問時,通常會使用A記錄進行解析,它只能映射到80端口(https時映射到443),這時就需要使用反向代理將80
端口的請求分發(fā)到本地不同的內(nèi)部端口來訪問對應(yīng)服務(wù):
本例中使用域名+IP的方式進行部署。
三. Nodejs應(yīng)用的手動部署
以Express為例,步驟如下:
* 首先通過yarn global add express-generator或npm install express-generator -g
全局安裝腳手架
* 完成后在工作目錄通過命令行express mydemo --ejs生成一個使用ejs作為模板渲染引擎的express工程
* 命令行輸入cd mydemo && yarn或cd mydemo && npm install安裝依賴
* 在/bin/www文件中修改端口號為期望的端口號(自動生成的是80端口),例如3001
* 將前端工程build出的包整體復(fù)制粘貼到/public目錄中
* 此時在本地工程根目錄下輸入npm start后,在瀏覽器中http://localhost:3001就可以訪問到網(wǎng)站了
* 使用FTP工具(如FlashFxp或FileZilla Client等)連接到部署機器,將mydemo目錄壓縮為zip包后上傳到服務(wù)器指定目錄。
* 使用SSH工具(如Xshell或MobaXter)登錄遠程機器,假設(shè)為linux系統(tǒng),輸入unzip mydemo.zip解壓壓縮包,然后cd
mydemo進入服務(wù)端工程,輸入npm start即可在服務(wù)器上開啟Web服務(wù),通過ip地址:3001就可以訪問到網(wǎng)站。
* 但是如果此時SSH工具斷開連接,就會發(fā)現(xiàn)express應(yīng)用無法繼續(xù)訪問了,所以還需要一個守護進程來維持應(yīng)用的啟動狀態(tài),在服務(wù)端通過npm
install pm2 -g來安裝nodejs應(yīng)用的部署管理模塊,它可以實現(xiàn)多應(yīng)用管理、Hook更新、自動重啟等等許多常用功能,詳細信息可以訪問
【PM2官方網(wǎng)站】 <http://pm2.keymetrics.io/>。
* 最后,在工程根目錄輸入pm2 start ./bin/www即可以后臺模式運行應(yīng)用。
四. 基于nodejs的自動部署
4.1 package.json中的scripts
了解了手動部署的過程后,就可以通過自動化腳本來實現(xiàn)后續(xù)的更新和部署。nodejs工程的自動化是依賴于package.json文件中的scripts
配置項來實現(xiàn)的,例如使用vue-cli搭建的工程中就會帶有:
{ ... "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service
build", "lint": "vue-cli-service lint" }, ... }
在項目根目錄下打開命令行,輸入npm run [script-key]或者yarn [script-key]([script-key]
指上面示例中的serve,build,lint這些鍵名),就會執(zhí)行對應(yīng)的scripts[key]對應(yīng)的命令。我們先添加一條用于自動部署的腳本指令:
{ ... "scripts": { "build": "vue-cli-service build", "deploy" "node
./scripts/deploy/deploy.js" }, ... }
當輸入npm run deploy或yarn deploy時,實際上就相當于用node去執(zhí)行./scripts/deploy/deploy.js
這個腳本,其中就編寫了自動化發(fā)布的指令。scripts還提供了生命周期鉤子,比如你對接的是一個測試環(huán)境,希望每次build后自動發(fā)布,就可以使用post
鉤子來實現(xiàn):
{ ... "scripts": { "build": "vue-cli-service build", "postbuild":"npm run
deploy", "deploy" "node ./scripts/deploy/deploy.js" }, ... }
這樣每次build執(zhí)行完畢后,就會自動執(zhí)行npm run deploy,也就是運行發(fā)布的腳本。
4.2 自動化發(fā)布腳本deploy.js
自動化發(fā)布腳本需要完成這樣幾個任務(wù):
* 將打包出的dist壓縮為zip包
* 使用SSH連接部署服務(wù)器,將zip包發(fā)上去
* 上傳完畢后,啟動事先寫好后續(xù)任務(wù)并放在服務(wù)器上的shell腳本來完成剩余的工作
涉及的幾個模塊包括實現(xiàn)SSH連接的node-ssh模塊(底層是ssh2模塊,這個模塊是一個Promise封裝),用于制作zip壓縮包的archiver模塊。
node-ssh提供了上傳本地目錄的方法,但實際使用過程中發(fā)現(xiàn)并不穩(wěn)定,從告警信息來看是node-stream
模塊在傳送時將不同格式的文件轉(zhuǎn)換為流時可能會出現(xiàn)異常,實測大約有一半概率觸發(fā),嘗試修改了一些配置參數(shù)并未解決,所以采用archiver
模塊先壓縮為單個文件后再進行上傳。
參考代碼如下:
const path = require('path'); const archiver =require('archiver'); const fs =
require('fs'); const node_ssh = require('node-ssh'); const ssh = new
node_ssh(); const srcPath = path.resolve(__dirname,'../../dist'); const configs
= require('./config'); console.log('開始壓縮dist目錄...'); startZip();
//壓縮dist目錄為public.zip function startZip() { var archive = archiver('zip', {
zlib: { level: 5 } //遞歸掃描最多5層 }).on('error', function(err) { throw
err;//壓縮過程中如果有錯誤則拋出 }); var output = fs.createWriteStream(__dirname +
'/public.zip') .on('close', function(err) { /*壓縮結(jié)束時會觸發(fā)close事件,然后才能開始上傳,
否則會上傳一個內(nèi)容不全且無法使用的zip包*/ if (err) { console.log('關(guān)閉archiver異常:',err); return; }
console.log('已生成zip包'); console.log('開始上傳public.zip至遠程機器...'); uploadFile();
}); archive.pipe(output);//典型的node流用法
archive.directory(srcPath,'/public');//將srcPach路徑對應(yīng)的內(nèi)容添加到zip包中/public路徑
archive.finalize(); } //將dist目錄上傳至正式環(huán)境 function uploadFile() { ssh.connect({
//configs存放的是連接遠程機器的信息 host: configs.host, username: configs.user, password:
configs.password, port:22 //SSH連接默認在22端口 }).then(function () {
//上傳網(wǎng)站的發(fā)布包至configs中配置的遠程服務(wù)器的指定地址 ssh.putFile(__dirname + '/public.zip',
configs.path).then(function(status) { console.log('上傳文件成功');
console.log('開始執(zhí)行遠端腳本'); startRemoteShell();//上傳成功后觸發(fā)遠端腳本 }).catch(err=>{
console.log('文件傳輸異常:',err); process.exit(0); }); }).catch(err=>{
console.log('ssh連接失敗:',err); process.exit(0); }); } //執(zhí)行遠端部署腳本 function
startRemoteShell() { //在服務(wù)器上cwd配置的路徑下執(zhí)行sh deploy.sh腳本來實現(xiàn)發(fā)布 ssh.execCommand('sh
deploy.sh', { cwd:'/usr/bin/XXXXX' }).then(function(result) {
console.log('遠程STDOUT輸出: ' + result.stdout) console.log('遠程STDERR輸出: ' +
result.stderr) if (!result.stderr){ console.log('發(fā)布成功!'); process.exit(0); }
}); }
4.3 遠端腳本deploy.sh
當發(fā)布包上傳至遠程服務(wù)器后,剩余的工作在遠端來完成就可以了,你只需要將后續(xù)的工作寫進shell腳本并放在對應(yīng)的目錄里就可以了,本例中deploy.sh
放在了服務(wù)端項目目錄/mydemo中。示例如下(由于是自用系統(tǒng),不考慮灰度發(fā)布等,直接暴力刪除靜態(tài)目錄public,然后替換為新的包):
#!/bin/bash cd /usr1/AAA/mydemo #刪除原靜態(tài)資源目錄 rm -rf public cd /usr1/AAA #解壓新的包
unzip public.zip #將解壓出的public目錄移動到服務(wù)端程序目錄BBB中 mv public ./mydemo
提示:
如果腳本文件是在windows下編寫的,請注意將編輯器中的回車換行改為LF,windows下通常默認是CRLF
,這可能會導(dǎo)致腳本在linux機器上無法正常執(zhí)行。
至此,一個簡易的自動化部署就做完了。你只需要在本地輸入npm run deploy,后續(xù)的工作就會自動執(zhí)行。
五. 小結(jié)
本篇只是一個簡易的自動化部署流程,由于部署環(huán)境沒有外網(wǎng)所以暫時無法借助通用的自動化流水線實現(xiàn)全自動的DevOps流程。PM2
實際上還有非常多實用的功能,可以管理多個不同的應(yīng)用實例,以集群模式運行實例,或者預(yù)設(shè)發(fā)布流程,可以直接響應(yīng)Web Hook并對接指定的代碼倉,在根目錄下建立
ecosystem.config.js配置文件就可以添加更多配置來指定pm2的表現(xiàn),感興趣的讀者可以研究一下。
熱門工具 換一換