【nodejs原理&源碼賞析(9)】用node-ssh實現輕量級自動化部署

来源:https://www.cnblogs.com/dashnowords/archive/2019/08/03/11293667.html
-Advertisement-
Play Games

示例代碼托管在: "http://www.github.com/dashnowords/blogs" 博客園地址: "《大史住在大前端》原創博文目錄" 華為雲社區地址: "【你要的前端打怪升級指南】" [TOC] 一. 需求描述 前端工程出包後實現簡易的自動化部署。 二. 預備知識 網站的建設可以使 ...


目錄

示例代碼托管在:http://www.github.com/dashnowords/blogs

博客園地址:《大史住在大前端》原創博文目錄

華為雲社區地址:【你要的前端打怪升級指南】

一. 需求描述

前端工程出包後實現簡易的自動化部署。

二. 預備知識

網站的建設可以使用任何自己熟悉的框架,三大框架都有自己的官方Cli工具,從代碼編寫到生成可用於生產環境部署的包基本都有自動化命令,各個打包工具也在零配置的追求上做了很多工作。本篇中從得到一個生產環境的包以後開始,對站點部署的相關知識進行一些介紹。

首先你需要一個Web伺服器,常見的有:

  • Nginx
  • Tomcat
  • Apache或相關集成環境
    • XAMMPApache+MySQL+PHP+PERL
    • LAMPLinux+Apache+MySQL+PHP
  • nodejs或相關框架+守護進程
    • Express
    • Koa2

以上任何一種在伺服器上運行起來後都可以擔任Web伺服器的角色,只是具備的擴展功能和應用場景有區別,Nginx基本上是正式環境部署的首選方案。常見的基本部署方案如下:

IP+埠訪問

使用訪問,可直接訪問對應埠的服務,部署方式相對簡單:

功能變數名稱訪問

使用功能變數名稱訪問時,通常會使用A記錄進行解析,它只能映射到80埠(https時映射到443),這時就需要使用反向代理將80埠的請求分發到本地不同的內部埠來訪問對應服務:

本例中使用功能變數名稱+IP的方式進行部署。

三. Nodejs應用的手動部署

Express為例,步驟如下:

  1. 首先通過yarn global add express-generatornpm install express-generator -g全局安裝腳手架
  2. 完成後在工作目錄通過命令行express mydemo --ejs生成一個使用ejs作為模板渲染引擎的express工程
  3. 命令行輸入cd mydemo && yarncd mydemo && npm install安裝依賴
  4. /bin/www文件中修改埠號為期望的埠號(自動生成的是80埠),例如3001
  5. 將前端工程build出的包整體複製粘貼到/public目錄中
  6. 此時在本地工程根目錄下輸入npm start後,在瀏覽器中http://localhost:3001就可以訪問到網站了
  7. 使用FTP工具(如FlashFxpFileZilla Client等)連接到部署機器,將mydemo目錄壓縮為zip包後上傳到伺服器指定目錄。
  8. 使用SSH工具(如XshellMobaXter)登錄遠程機器,假設為linux系統,輸入unzip mydemo.zip解壓壓縮包,然後cd mydemo進入服務端工程,輸入npm start即可在伺服器上開啟Web服務,通過ip地址:3001就可以訪問到網站。
  9. 但是如果此時SSH工具斷開連接,就會發現express應用無法繼續訪問了,所以還需要一個守護進程來維持應用的啟動狀態,在服務端通過npm install pm2 -g來安裝nodejs應用的部署管理模塊,它可以實現多應用管理、Hook更新、自動重啟等等許多常用功能,詳細信息可以訪問 【PM2官方網站】
  10. 最後,在工程根目錄輸入pm2 start ./bin/www即可以後臺模式運行應用。

四. 基於nodejs的自動部署

4.1 package.json中的scripts

瞭解了手動部署的過程後,就可以通過自動化腳本來實現後續的更新和部署。nodejs工程的自動化是依賴於package.json文件中的scripts配置項來實現的,例如使用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這些鍵名),就會執行對應的scripts[key]對應的命令。我們先添加一條用於自動部署的腳本指令:

{
    ...
    "scripts": {
        "build": "vue-cli-service build",
        "deploy" "node ./scripts/deploy/deploy.js"
      },
    ...
}

當輸入npm run deployyarn deploy時,實際上就相當於用node去執行./scripts/deploy/deploy.js這個腳本,其中就編寫了自動化發佈的指令。scripts還提供了生命周期鉤子,比如你對接的是一個測試環境,希望每次build後自動發佈,就可以使用post鉤子來實現:

{
    ...
    "scripts": {
        "build": "vue-cli-service build",
        "postbuild":"npm run deploy",
        "deploy" "node ./scripts/deploy/deploy.js"
      },
    ...
}

這樣每次build執行完畢後,就會自動執行npm run deploy,也就是運行發佈的腳本。

4.2 自動化發佈腳本deploy.js

自動化發佈腳本需要完成這樣幾個任務:

  • 將打包出的dist壓縮為zip
  • 使用SSH連接部署伺服器,將zip包發上去
  • 上傳完畢後,啟動事先寫好後續任務並放在伺服器上的shell腳本來完成剩餘的工作

涉及的幾個模塊包括實現SSH連接的node-ssh模塊(底層是ssh2模塊,這個模塊是一個Promise封裝),用於製作zip壓縮包的archiver模塊。node-ssh提供了上傳本地目錄的方法,但實際使用過程中發現並不穩定,從告警信息來看是node-stream模塊在傳送時將不同格式的文件轉換為流時可能會出現異常,實測大約有一半概率觸發,嘗試修改了一些配置參數並未解決,所以採用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) {
         /*壓縮結束時會觸發close事件,然後才能開始上傳,
           否則會上傳一個內容不全且無法使用的zip包*/
         if (err) {
            console.log('關閉archiver異常:',err);
            return;
         }
         console.log('已生成zip包');
         console.log('開始上傳public.zip至遠程機器...');
         uploadFile();
     });

    archive.pipe(output);//典型的node流用法
    archive.directory(srcPath,'/public');//將srcPach路徑對應的內容添加到zip包中/public路徑
    archive.finalize();
}

//將dist目錄上傳至正式環境
function uploadFile() {
    ssh.connect({ //configs存放的是連接遠程機器的信息
        host: configs.host,
        username: configs.user,
        password: configs.password,
        port:22 //SSH連接預設在22埠
    }).then(function () {
        //上傳網站的發佈包至configs中配置的遠程伺服器的指定地址
        ssh.putFile(__dirname + '/public.zip', configs.path).then(function(status) {
                console.log('上傳文件成功');
                console.log('開始執行遠端腳本');
                startRemoteShell();//上傳成功後觸發遠端腳本
          }).catch(err=>{
             console.log('文件傳輸異常:',err);
             process.exit(0);
          });
    }).catch(err=>{
        console.log('ssh連接失敗:',err);
        process.exit(0);
    });
}

//執行遠端部署腳本
function startRemoteShell() {
    //在伺服器上cwd配置的路徑下執行sh deploy.sh腳本來實現發佈
    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('發佈成功!');
            process.exit(0);
        }
    });
}

4.3 遠端腳本deploy.sh

當發佈包上傳至遠程伺服器後,剩餘的工作在遠端來完成就可以了,你只需要將後續的工作寫進shell腳本並放在對應的目錄里就可以了,本例中deploy.sh放在了服務端項目目錄/mydemo中。示例如下(由於是自用系統,不考慮灰度發佈等,直接暴力刪除靜態目錄public,然後替換為新的包):

#!/bin/bash
cd /usr1/AAA/mydemo
#刪除原靜態資源目錄
rm -rf public
cd /usr1/AAA
#解壓新的包
unzip public.zip
#將解壓出的public目錄移動到服務端程式目錄BBB中
mv public ./mydemo

提示:

如果腳本文件是在windows下編寫的,請註意將編輯器中的回車換行改為LF,windows下通常預設是CRLF,這可能會導致腳本在linux機器上無法正常執行。

至此,一個簡易的自動化部署就做完了。你只需要在本地輸入npm run deploy,後續的工作就會自動執行。

五. 小結

本篇只是一個簡易的自動化部署流程,由於部署環境沒有外網所以暫時無法藉助通用的自動化流水線實現全自動的DevOps流程。PM2實際上還有非常多實用的功能,可以管理多個不同的應用實例,以集群模式運行實例,或者預設發佈流程,可以直接響應Web Hook並對接指定的代碼倉,在根目錄下建立ecosystem.config.js配置文件就可以添加更多配置來指定pm2的表現,感興趣的讀者可以研究一下。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • #0x00 前言 安卓應用加固技術是伴隨安卓應用破解技術一同發展起來的。加固技術分為加殼保護和反反彙編保護技術。市面上成熟的加固廠商一般會使用加殼保護技術配合反反彙編技術對安卓應用進行加固。 安卓反反彙編技術的總結在我另一篇博客中將進行詳細探討,鏈接: http://................ ...
  • 記錄一下我前段時間封裝的一個vue組件吧。技術需要積累,有時間我把我之前寫的還不錯的組件都開源出來。並嘗試vue和react 兩種方式的組件封裝。今天簡單寫下滑鼠框選div選中效果的封裝吧。 div框選實現 div框選效果,其實沒有什麼好的方法,就是獲取滑鼠事件,根據滑鼠的位置,動態創建一個跟隨滑鼠 ...
  • 說起網站調試,pc頁面和h5頁面,假如電腦上能夠重現的,都不在話下,調試起來都蠻簡單。僅僅需要fiddler一個抓包工具,把線上壓縮代碼替換成本地無壓縮代碼就可以了。具體步驟我後面可以詳細介紹。但是,僅僅是某款手機重現,其他手機沒有問題的情況下如何調試?hybrid頁面如何調試呢?這篇文章簡單總結下 ...
  • 特色:寫法更加優雅,更加像面像對象的編程,其思想和 ES5 是一致的。 箭頭函數、this ES6中可以使用 => 作為函數表達形式,極簡風格,參數+ => +函數體。 var foo = function(){return 1;}; //等價於 let foo = () => 1; let num ...
  • HTML屬性 屬性 描述 class 為html元素定義一個或多個類名(classname)(類名從樣式文件引入) id 定義元素的唯一id style 規定元素的行內樣式(inline style) title 描述了元素的額外信息 (作為工具條使用) HTML <head> 元素 <head> ...
  • 首先來瞄一下background-clip,這個屬性是幹嘛的? 顧名思義,背景裁剪... 按照我自己的理解就是背景的顯示區域 此處粘上MDN的示例鏈接(嫌麻煩的,後面我也貼上截圖)https://developer.mozilla.org/zh-CN/docs/Web/CSS/background- ...
  • 變數的作用域在函數之外聲明的變數,叫做全局變數,因為它可被當前文檔中的任何其他代碼所訪問。在函數內部聲明的變數,叫做局部變數,因為它只能在當前函數的內部訪問。 ECMAScript 6 之前的 JavaScript 沒有 語句塊作用域;相反,語句塊中聲明的變數將成為語句塊所在函數(或全局作用域)的局 ...
  • 在 jQuery 中可以使用 hide() 和 show() 方法來隱藏和顯示 HTML 元素 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...