部落格的部署方法論

peterjxl發表於2024-07-05

10.部署

部落格寫完後,當然是要釋出到網路上的。如果想要部署到伺服器上,則需編譯構建成靜態檔案,然後將其上傳到伺服器上的路徑(該路徑由我們自己決定),然後在 web 伺服器(Nginx 等)上配置訪問路徑即可

這裡說的是有自己伺服器的情況,如果嫌麻煩和沒預算可以使用 GitHub Pages 服務

構建靜態檔案

VuePress 提供了 vuepress build docs ​命令來構建,也就是我們之前在 package.json 裡配置的 docs:build​:

"scripts": {
    "docs:dev": "vuepress dev docs --temp .temp",
    "docs:build": "vuepress build docs",
  },

我們在命令列裡執行,結果如下:

> npm run docs:build

> vuepress-learn@1.0.0 docs:build
> vuepress build docs

wait Extracting site metadata...
tip Apply theme @vuepress/theme-default ...
tip Apply plugin container (i.e. "vuepress-plugin-container") ...
tip Apply plugin @vuepress/register-components (i.e. "@vuepress/plugin-register-components") ...
tip Apply plugin @vuepress/active-header-links (i.e. "@vuepress/plugin-active-header-links") ...
tip Apply plugin @vuepress/search (i.e. "@vuepress/plugin-search") ...
tip Apply plugin @vuepress/nprogress (i.e. "@vuepress/plugin-nprogress") ...

√ Client
  Compiled successfully in 14.78s

√ Server
  Compiled successfully in 4.35s

wait Rendering static HTML...
success Generated static files in docs\.vuepress\dist.

我們觀察最後一行,VuePress 告訴我們成功生成了靜態檔案在這個目錄:docs.vuepress\dist​。我們無需關心裡面的內容,只需將整個目錄上傳到伺服器上即可(FTP 或者壓縮後上傳)

Nginx 配置

這裡已經假設讀者有了伺服器和安裝了 Nginx。如果不知道什麼是 Nginx,可以參考我的部落格:伺服器軟體

以筆者部署的過程為例:

  1. 將 dist 資料夾裡的內容上傳到/opt/myblog 目錄下(可以壓縮 dist 目錄為壓縮包,然後上傳再解壓)

  2. 配置 Nginx:

    location / {
        root   /opt/myblog;
        index  index.html index.htm;
    }
    
  3. 重啟 Nginx

訪問伺服器 IP,即可看到部落格內容,並且可以正常跳轉等,和本地執行的效果一致:

GitHub Pages

一個伺服器後續的續費高達幾千元一年;如果不想要購買伺服器和配置域名等等,可以使用 GitHub Pages,也是不少人在使用的方式。

GitHub 是什麼就不多解釋了。簡單來說 GitHub 就是一個 Git 專案的託管服務平臺,上面有很多知名專案。其中,每個專案都有一個主頁,列出專案的原始檔,例如 Linux

但是對於一個新手來說,看到一大堆原始碼,只會讓人頭暈腦漲,不知何處入手。他希望看到的是,一個簡明易懂的網頁,說明每一步應該怎麼做。

因此,Github 就設計了 Pages 功能,允許使用者自定義專案首頁,用來替代預設的原始碼列表。所以,Github Pages 可以被認為是使用者編寫的、託管在 Github 上的靜態網頁。

博主沒有用過該功能,因此不展開來講,感興趣的讀者可參考:

  • 一篇帶你用 VuePress + Github Pages 搭建部落格_JavaScript_冴羽_InfoQ 寫作社群
  • 搭建一個免費的,無限流量的 Blog----github Pages 和 Jekyll 入門 - 阮一峰的網路日誌

自動化部署

如果每次修改了部落格內容,都要重新構建、然後上傳到伺服器上,未免也太麻煩了。為此,我們可以用一些第三方工具,自動將打包後的檔案上傳到伺服器上:

  • scp2:是一個純 js 編寫的 ssh2 協議的 Linux 遠端檔案複製實現
  • ora:是一個優雅的用於命令列 Loading 的 spinner,簡單來說就是用來實現命令列環境的 loading 效果,和顯示各種狀態的圖示等,美觀一點。

安裝依賴:

npm i scp2 ora@5.0

ora6.0 以上版本不支援 require 方式引入,因為在 node 中使用,使用 5.0 版本

在專案裡新建兩個檔案:

  • deploy.js:用於編寫部署命令
  • serverInfo.json:用於存放伺服器資訊(由於本部落格是開源的,不方便將伺服器 IP 和密碼等敏感資訊公開)

deploy.js 的內容:

const fs = require('fs')
const scpClient = require('scp2')
const ora = require('ora')

const serverInfo = JSON.parse(fs.readFileSync('serverInfo.json'))
const loading = ora('正在部署至 ' + serverInfo.host )
loading.start()
scpClient.scp('./docs/.vuepress/dist/', serverInfo ,(err)=>{ 
loading.stop()
    if(err) { 
        console.log('部署失敗')
        throw err
    }else { 
        console.log('部署成功')
    }
})

serverInfo.json:存放伺服器資訊,注意在 .gitignore 檔案裡新增 serverInfo.json,不要將敏感資訊公開了。讀者需按需修改這些資訊

{
  "host":"替換成你的IP",
  "port":"22",
  "username":"替換成你的使用者名稱",
  "password":"替換成你的密碼",
  "path":"/opt/myblog"
}

在 package.json 中的 script 中新增 deploy 命令:

"scripts": {
    ...
    "deploy": "npm run docs:build && node ./deploy.js",
    ...
},

測試:可以刪除之前的/opt/myblog 目錄裡的檔案

$ cd /opt
$ rm -r myblog/

然後在命令列裡執行 npm run deploy​ ,觀察是否正常部署了。

> node .\deploy.js
部署成功

注意:

  1. 後續想要部署,直接執行命令即可,會覆蓋之前的部落格內容。
  2. 使用 GitHub Pages 也可以實現自動化部署,這裡不展開,可參考:GET 新技能!自己的網站突然就不香了 第 3.2 節。
  3. 讀者也可以在伺服器上,使用 git clone 拉取專案,然後 npm run docs:build 來執行,不過這樣也很麻煩。

使用 GitHub Action

什麼是 GitHub Action?這裡引用阮一峰大佬的說明:GitHub Actions 入門教程 - 阮一峰的網路日誌

大家知道,持續整合由很多操作組成,比如抓取程式碼、執行測試、登入遠端伺服器,釋出到第三方服務等等。GitHub 把這些操作就稱為 actions。

很多操作在不同專案裡面是類似的,完全可以共享。GitHub 注意到了這一點,想出了一個很妙的點子,允許開發者把每個操作寫成獨立的指令碼檔案,存放到程式碼倉庫,使得其他開發者可以引用。

如果你需要某個 action,不必自己寫複雜的指令碼,直接引用他人寫好的 action 即可,整個持續整合過程,就變成了一個 actions 的組合。這就是 GitHub Actions 最特別的地方。

希望讀者看完阮一峰大大的部落格後再往下看。

簡單來說,就是我們可以使用別人寫好的功能,在每次程式碼推送到 Git 後,GitHub 會自動幫助我們完成編譯構建,自動上傳到伺服器上,重啟服務等等操作

一句話:可以實現提交程式碼到伺服器上後,自動更新部落格。俗稱持續整合、自動化部署。讀者也可使用 Gitee Action。接下來我們來實踐下。

伺服器準備

首先是伺服器得準備下環境,安裝 rsync,讀者使用的 Centos,root 使用者,安裝命令如下:

yum install rsync

然後在伺服器上生成公鑰和私鑰,用來授權

$ ssh-keygen -t rsa -C "peterjxl@qq.com"

然後一直回車即可,執行情況:

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Pt6bEV/LpmNU5ibmsyJjEstK4DHL2kjAaQvNbz8urok peterjxl@qq.com
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|                 |
|.o.           o  |
|o+*     S .  +.  |
|+o.*  ..   o+oo. |
| o+ +. oo .+.o+  |
|.= +..=.+o.o=o   |
|E +oo+o+.o++o+   |
+----[SHA256]-----+

可以看到公鑰和私鑰的位置。id_rsa 就是私鑰,id_rsa.pub 是公鑰。我們需要用到私鑰的內容:

cat /root/.ssh/id_rsa

筆者這裡就不貼出來了,也算是一種敏感資訊

然後修改本機關於 ssh 的一些配置:如此便完成了公鑰的安裝。

$ cd /root/.ssh
$ cat id_rsa.pub >> authorized_keys

開啟金鑰登入功能:編輯 /etc/ssh/sshd_config 檔案,在檔案末尾新增如下幾行:

$ RSAAuthentication yes
$ PubkeyAuthentication yes
$ PermitRootLogin yes

最後,重啟 SSH 服務:

$ service sshd restart

GitHub 準備

在專案所在的倉庫中配置: 開啟 Settings->Secrets->New secret

然後將上一步的私鑰內容新增進去:

​​​

我們再新建一個 secret,名字為 MY_SERVER_IP​,值為我們的伺服器的 IP,IP 也是一種敏感欄位。

流水線配置

接下來我們就可以配置流水線了。新建 .github/workflows 資料夾,然後再新建 main.yml,內容如下:

name: Deploy My Server

on:
  push:
    branches:
      - master # 只在master上push觸發部署
    
jobs:
  deploy:
    runs-on: ubuntu-latest # 使用ubuntu系統映象執行自動化指令碼

    steps: # 自動化步驟
      #下載程式碼倉庫
      - uses: actions/checkout@v1 
      # 使用action庫,安裝node
      - name: use Node.js  # 使用action庫  actions/setup-node安裝node
        uses: actions/setup-node@v3
        with:
          node-version: 16
      # 安裝依賴
      - name: npm install 
        run: npm install 
    
      #打包專案
      - name: Build
        run: npm run docs:build

      #部署到伺服器
      - name: Deploy to Staging My server
        uses: easingthemes/ssh-deploy@v2.1.6
        env:
          # 使用GitHub倉庫裡的secret設定的值
          SSH_PRIVATE_KEY: ${{ secrets.MY_SERVER_PRIVATE_KEY }} 
          # 源目錄,編譯後生成的檔案目錄
          SOURCE: './docs/.vuepress/dist/'
          #伺服器公網地址
          REMOTE_HOST: ${{ secrets.MY_SERVER_IP }}
          #伺服器使用者名稱-一般預設root
          REMOTE_USER: 'root'
          #伺服器中,程式碼部署的位置
          TARGET: '/opt/myblog'
          #去除的檔案
          EXCLUDE: "/dist/, /node_modules/" 

這裡簡單說明下檔案的內容

  • 第一行:本次流水線的名字,可自行更換
  • 第 3~6 行:說明只有當 master 分支有提交到遠端庫(push)的時候,才更新(也就是執行本次流水線)
  • 第 8 行:jobs,本次我們只用了一個 job,也就是第 9 行的 job
  • 第 10 行:指定要在哪個作業系統的環境下編譯出包(一般是 Linux)
  • 接下來就是 deploy 這個 job 的 steps,每個 step 做了不同的事情,例如安裝 node,然後安裝依賴和執行構建命令
  • 第 31 行開始就是一些環境變數的設定,例如讀取我們上一小節設定的 IP 和私鑰資訊

測試流水線

每次提交程式碼到遠端倉庫,這條流水線就會執行:可以在 GitHub 專案的 Actions 選項卡里檢視

​​

我們點選本次執行的 workflow,可以看到目前正在執行的 job:

再點進去,就可以看到這個 job 裡的 step 執行情況:打勾的說明已完成,黃色的轉圈圈的表示還在執行中

如果流水線執行失敗了,會有郵件告知,並且可以在 Action 裡檢視失敗的原因。

還可以重跑失敗的 jobs:

部署失敗:​babel-preset-app

如果你遇到了 GitHub Action 部署失敗了,報錯資訊類似這樣的:

2023-02-18T12:11:00.0564591Z [BABEL] Note: The code generator has deoptimised the styling of /home/runner/work/vuepress-learn/vuepress-learn/node_modules/lodash/lodash.js as it exceeds the max of 500KB.
2023-02-18T12:11:18.4372148Z [success] [webpackbar] Server: Compiled successfully in 31.22s
2023-02-18T12:11:27.6215689Z [success] [webpackbar] Client: Compiled with some errors in 40.43s
2023-02-18T12:11:27.8557348Z (undefined) ./node_modules/@vuepress/core/.temp/style.styl
2023-02-18T12:11:27.8558854Z Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):

這是因為 @vue/babel-preset-app ​的版本問題,解決方法:

npm i @vue/babel-preset-app@4.5.18

更多參考:fresh new 1.x project fails to build (but dev works OK) · Issue #3065 · vuejs/vuepress

部署失敗:JavaScript heap out of memory

當你的部落格數量越來越多,那麼構建時需要的記憶體也越來越多,最後你可能會發現記憶體不夠:

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb090e0 node::Abort() [node]
 2: 0xa1b70e  [node]
 3: 0xce19d0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xce1d77 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xe993e5  [node]
.....

解決方法:構建前設定記憶體引數,例如在 package.json 中新增:

"scripts": {
    "build": "node --max_old_space_size=8192 ./node_modules/vuepress/cli.js build docs"
  }

注:方法來自二丫講梵的部落格專案

其他部署方式

如果你生成金鑰的時候,輸入了密碼進行保護:

$ ssh-keygen
...
Enter passphrase (empty for no passphrase):     # In here I input a password

那麼部署的時候可能會報錯(因為沒密碼),目前暫無找到其他方法;一般是用沒有密碼保護的金鑰來部署。

如果你不想用金鑰登入,而是用密碼登入,可以用這個 action:appleboy/scp-action: GitHub Action that copy files and artifacts via SSH.

使用思源筆記外掛

如果你有使用思源筆記,還可以使用 terwer 開發的思源筆記外掛:sy-post-publisher

獲取原始碼

本文介紹了幾種部署方式,最推薦的是使用 GitHub Action,非常方便,一勞永逸。

為了寫本系列的部落格,博主特地新建了一個專案用於演示,相關程式碼已放到 GiteeGitHub 上。

並且,不同功能建立了不同分支,想要獲取本篇文章演示的原始碼只需切換分支即可!

例如,你想執行本篇文章所建立的部落格,可以這樣做:

  1. 開啟命令列
  2. 拉取程式碼:git clone git@gitee.com:peterjxl/vuepress-learn.git​ (也可拉取 GitHub 的)
  3. 跳轉目錄:cd vuepress-learn
  4. 切換分支:git switch -c VuePressDemo6Deploy origin/VuePressDemo6Deploy
  5. 安裝依賴:npm i
  6. 執行部落格:npm run docs:dev

參考

  • 前端專案自動化部署_前端自動化部署_眾生皆苦唯有我甜的部落格-CSDN 部落格
  • 透過 GitHub Actions 自動部署 vuepresss 專案到雲伺服器_居無何的部落格-CSDN 部落格_vuepress 部署在伺服器上
  • rsync exited with code 255.Load key “...“: invalid format Permission denied, please try again._rsync 255_滄州刺史的部落格-CSDN 部落格

相關文章