如果將 vuepress build 之後的靜態網站部署在自己的服務器上,這裏有一個自動化方案,思路如下:
- 在 linux 服務器上安裝 node、yarn、git、nginx 軟件
- 編寫一個腳本:用於更新 git 倉庫項目,然後 build,再複製到 nginx 配置訪問的文件位置
- 使用 nginx 來作爲靜態網站的容器
- 使用 nginx lua 模塊提供一個調用腳本的入口
- 在 github 上填寫 webhook 地址爲,調用腳本的入口地址
- 達到:上傳到 github 後,觸發 webhook 事件,服務器自動構建併發布新筆記內容的功能
#安裝 OpenResty + lua 相關依賴包
安裝 OpenResty 和 lua 入門請參考本文章(opens new window)
請按該文章完成安裝後,並完成 hello world lua 的測試,再繼續下面的步驟
#nginx 執行 shell 腳本
要在 nginx 下執行 shell 腳本,主要使用以下兩個軟件:
- lua-resty-shell 模塊
- sockproc
lua-resty-shell 通過 sockproc 去執行 shell 命令,並返回執行結果
#安裝 sockproc
隨意把 sockproc 安裝在哪裏,按你自己的習慣,只要能運行上就行
git clone https://github.com/juce/sockproc
cd sockproc
make
./sockproc /tmp/shell.sock
chmod 0666 /tmp/shell.sock
2
3
4
5
sockproc 是一個服務器程序,偵測 unix socket 或者 tcp socket , 並把收到的命令,傳遞給子進程執行,執行完畢後,把結果返回給客戶端,,我們就讓 sockproc 偵測 /tmp/shell.sock
的套接口有沒有數據到來。
#安裝 lua-resty-shell 模塊
它是一個很小的庫,配合 openresty 使用,目的是提供類似於 os.execute 或 io.popen 的功能, 唯一區別它是非阻塞的,也就是說即使需要耗時很久的命令,你也可以使用它
# 同樣,在任意目錄下,這裏我們需要拿到倉庫裏面的 shell.lua 文件而已
git clone https://github.com/juce/lua-resty-shell
cd lua-resty-shell
# 把 shell.lua 文件複製到 openResty 中配置的 lualib 目錄中
# 如果是按照上面教程安裝的,那麼我們的 lualib路徑就如下
mkdir /usr/servers/lualib/resty/
cp lib/resty/shell.lua /usr/servers/lualib/resty/
2
3
4
5
6
7
#測試執行 shell 腳本
創建一個 lua 腳本文件
vim /usr/servers/nginx/conf/test.lua
local shell = require "resty.shell"
local args = {
socket = "unix:/tmp/shell.sock", -- 這是第一步的 unxi socket
}
local status, out, err = shell.execute("ls", args) -- ls 是想調用的命令,
ngx.header.content_type = "text/plain"
ngx.say("Result:\n" .. out) -- 命令輸出結果
2
3
4
5
6
7
8
9
修改 nginx 配置
vim /usr/servers/nginx/conf/lua.conf
server {
listen 9300;
server_name _;
location /lua {
default_type 'text/html';
# content_by_lua 'ngx.say("hello world")';
content_by_lua_file /usr/servers/nginx/conf/test.lua;
}
}
2
3
4
5
6
7
8
9
10
11
12
重新加載 nginx 配置文件後,訪問 9300 端口,就可以看到 ls 命令執行後輸出的內容了
#編寫接受 webhook 的邏輯 lua 腳本
我們的這裏的思路簡單一點:
- 提供一個訪問地址,接受 webhook 請求,請求的時候需要攜帶一個 token 參數
- 在 lua 腳本中獲取這個 token 參數,並校驗是否自己設置的,如果不是,則直接丟棄這個請求
- 執行筆記構建部署腳本
-- 拿一個地址來說明:http://eshop-cache03/lua?method=hello&productId=1
-- 獲取問號後面的參數列表
local uri_args = ngx.req.get_uri_args()
-- 獲取參數
local token = uri_args["token"]
local checkToken = "123456xxx"
-- 如果沒有提供 token 則輸出一個 err 信息
if not token then
ngx.say("request error :", err)
return
end
-- 判斷是否與 token 相等
if( token != checkToken ) then
ngx.say("request error :", err)
return
end
-- 校驗通過後,執行腳本
local shell = require "resty.shell"
local args = {
socket = "unix:/tmp/shell.sock",
}
local status, out, err = shell.execute("sh /xx/build.sh", args)
ngx.header.content_type = "text/plain"
ngx.say("Result:\n" .. out)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
那麼這個 /xx/build.sh
內容經過測試有如下的特性
#!/bin/bash
ll
touch /usr/servers/nginx/conf/testxxxxxxxxx
echo "Hello World !"
2
3
4
命令會正常執行,但是隻會輸出 echo 打印的信息給調用處。
前面驗證了我們方案中的關鍵部分 lua 執行 sh 腳本,下面就開始真正實現自動構建
#vuepress 自動構建
步驟如下:
- 安裝 vuepress build 的軟件環境:yarn (opens new window)和 node(opens new window)
- 安裝 git 軟件 (opens new window):用於克隆一個項目到本地,進行拉取最新的筆記內容
- 編寫構建腳本
- 配置 nginx 訪問構建好的靜態網站
- 在 Github 對應項目配置 webhook 地址到我們提供的 lua 入口
#clone 項目
把要自動部署構建的項目 clone 下來。我們的構建和發佈目錄都在 /usr/servers/notework/
目錄下展開
mkdir -p /usr/servers/notework/gitrepo
cd /usr/servers/notework/gitrepo
## 在該路徑下存放我們的筆記項目
git clone https://github.com/zq99299/mysql-tutorial.git
git clone https://github.com/zq99299/note-book.git
git clone https://github.com/zq99299/java-tutorial.git
git clone https://github.com/zq99299/linux-tutorial.git
git clone https://github.com/zq99299/mq-tutorial.git
git clone https://github.com/zq99299/dsalg-tutorial.git
2
3
4
5
6
7
8
9
#編寫構建腳本
這是一個公共的構建腳本,在調用該腳本的時候,需要把項目名傳遞進來
/usr/servers/notework/build.sh
#!/bin/sh
# 一個工作目錄,用於存放倉庫、打包後部署目錄
noteworkDir=/usr/servers/notework
# 筆記倉庫名稱,每個筆記一個,調用腳本時,將項目名傳遞進來
noteName=$1
# 更新項目,並構建
cd $noteworkDir/gitrepo/$noteName
git pull
yarn install
yarn docs:build
# 刪除構建好的包,並用新的覆蓋
rm -rf $noteworkDir/release/$noteName
mkdir -p $noteworkDir/release/$noteName
mv build/.vuepress/dist/* $noteworkDir/release/$noteName
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
配置 nginx 訪問構建好的靜態網站
server {
listen 80;
server_name localhost;
charset utf-8;
#access_log logs/host.access.log main;
location ^~ /linux-tutorial {
# root /usr/servers/notework/release/linux-tutorial/;
alias /usr/servers/notework/release/linux-tutorial/;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
需要說明下的是:這裏的 location 的配置,這個需要看你的 docs/.vuepress/config.js
中 bash 的設置,由於要部署到 githubio,這裏使用了一個前綴路徑。
現在,可以通過 http://你的主機 IP/linux-tutorial/
訪問到這個項目了。
#編寫 lua 腳本自動構建邏輯
前面寫了一部分,這裏做一點修改
/usr/servers/nginx/conf/noteBuild.lua
-- 拿一個地址來說明:http://eshop-cache03/lua?method=hello&productId=1
-- 獲取問號後面的參數列表
local uri_args = ngx.req.get_uri_args()
-- 獲取參數
local token = uri_args["token"]
-- 這裏增加一個 noteName 的參數值,需要 webhook 中回調,來構建不同的項目
local noteName = uri_args["noteName"]
local checkToken = "123456xxx"
-- 如果沒有提供 token 則輸出一個 err 信息
if not token then
ngx.say("request error token is null:", err)
return
end
-- 判斷是否與 token 相等
if( token ~= checkToken ) then
ngx.say("request error token mismatching:", err)
return
end
-- 檢查當前筆記是否支持自動構建
if not noteName then
ngx.say("request error noteName is null:", err)
return
end
local supportNotes = {"linux-tutorial","mysql-tutorial"}
function isInTable(value,list)
if not list then
return false
end
for k, v in pairs(list) do
if v == value then
return true
end
end
end
if( not isInTable(noteName,supportNotes) ) then
ngx.say("request error noteName mismatching:", err)
return
end
-- 校驗通過後,執行腳本
local shell = require "resty.shell"
local args = {
socket = "unix:/tmp/shell.sock",
timeout = 120000
}
-- 不加 nohub 15秒回執行超時,加了之後,貌似受上面的 timeout 控制,不明白這一塊是啥原因
local exeStr = "nohub sh /usr/servers/notework/build.sh "..noteName
local status, out, err = shell.execute(exeStr, args)
ngx.header.content_type = "text/plain"
if out then
ngx.say("Result:\n" .. out)
return
end
if err then
ngx.say("Result:\n" .. err)
return
end
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/usr/servers/nginx/conf/noteBuild.conf
server {
listen 80;
server_name _;
charset utf-8; # 中文不亂碼
location /lua {
default_type 'text/html';
# content_by_lua 'ngx.say("hello world")';
content_by_lua_file /usr/servers/nginx/conf/noteBuild.lua;
}
}
2
3
4
5
6
7
8
9
10
11
同樣需要在 nginx.conf 中引用這個 noteBuild.conf 文件
注意: 這裏的 conf 中的監聽端口不能與前面配置訪問靜態文件的端口一致,一致的話,前面的配置將被覆蓋,同樣可以將調用腳本的這代碼與前面訪問靜態文件的配置在同一個 server 中,就不會出現這種問題了
配置完成之後可以簡單測試下,訪問地址 http://你的 ip/lua?token=123456xxx¬eName=linux-tutorial
,比如這個 linux-tutorial 整個構建響應信息如下
Result:
Already up to date.
yarn install v1.22.4
[1/4] Resolving packages...
success Already up-to-date.
Done in 1.11s.
yarn run v1.22.4
$ 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/nprogress (i.e. "@vuepress/plugin-nprogress") ...
tip Apply plugin smooth-scroll (i.e. "vuepress-plugin-smooth-scroll") ...
tip Apply plugin @vuepress/back-to-top (i.e. "@vuepress/plugin-back-to-top") ...
tip Apply plugin @vuepress/pwa (i.e. "@vuepress/plugin-pwa") ...
tip Apply plugin @vuepress/medium-zoom (i.e. "@vuepress/plugin-medium-zoom") ...
tip Apply plugin @vuepress/search (i.e. "@vuepress/plugin-search") ...
tip Apply plugin @vssue/vssue (i.e. "@vssue/vuepress-plugin-vssue") ...
tip Apply plugin code-copy (i.e. "vuepress-plugin-code-copy") ...
tip Apply plugin @vuepress/last-updated (i.e. "@vuepress/plugin-last-updated") ...
tip Apply plugin baidu-tongji-analytics (i.e. "vuepress-plugin-baidu-tongji-analytics") ...
tip Apply plugin baidu-autopush (i.e. "vuepress-plugin-baidu-autopush") ...
ℹ Compiling Client
ℹ Compiling Server
✔ Server: Compiled successfully in 53.18s
✔ Client: Compiled successfully in 53.67s
wait Rendering static HTML...
[2K[1Gwait Generating service worker...
success Generated static files in build/.vuepress/dist.
Done in 80.58s.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#配置 github webhook 地址
關於上圖中的 URL,換成你自己的 IP 和開放的端口,還有各種參數。
之後就可以測試下,往 gitHub 上 push 一個文檔的修改,看是否能觸發自動構建。
#配置自定義域名
本人的 DNS 在萬網,完全的網址重定向,只能在萬網的機器纔可以,所以只能使用轉發到一個 IP 上,所以筆記訪問端口就只能是 80 端口了,其他的端口不支持配置。
下面是修改後的配置
/usr/servers/nginx/conf/nginx.conf
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
lua_package_path "/usr/servers/lualib/?.lua;;";
lua_package_cpath "/usr/servers/lualib/?.so;;";
# include noteBuild.conf;
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name _;
#charset koi8-r;
#access_log logs/host.access.log main;
# 將 github webhook 調用的入口移動到這裏來了,公用一個域名
location /note-auto-build {
default_type 'text/html';
content_by_lua_file /usr/servers/nginx/conf/noteBuild.lua;
}
# 有幾個筆記項目就寫幾個指向
location ^~ /linux-tutorial {
alias /usr/servers/notework/release/linux-tutorial/;
}
}
# 這個是針對不同域名的配置
# 我這裏給每一個筆記項目都配置了一個二級域名
server {
server_name linux-tutorial.mrcode.cn;
listen 80;
# 這個是能訪問到 index.html 文件
location / {
alias /usr/servers/notework/release/linux-tutorial/;
}
# 這裏是兼容有前綴的 css 等資源下載,由於我們的 .vuepress/config.js base 中配置了前綴
# 要同時兼容能推送到 githubio 上,這裏就只能這樣曲線救國了
# 實現的效果就是訪問 inux-tutorial.mrcode.cn ,就能正常閱讀
location ^~ /linux-tutorial {
alias /usr/servers/notework/release/linux-tutorial/;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
關於上面的配置,按照你自己的需求來組織是否給二級域名,還是一個域名就全部搞定