title: 使用Jenkins自動部署博客
toc: true
comment: true
date: 2017-12-17 19:48:10
tags: ['Jenkins', 'CI']
category: ['Jenkins']
這篇文章比較簡單,適合初學持續集成的讀者,本文可以幫助你對基於Jenkins的持續集成有一個比較全局的概念。
提出問題
為了使用HTTPS,我將博客從GitHub Pages遷移到了我的服務器上。由於博客基於Hexo,在遷移之前,我的工作流程是:
本地寫Markdown格式文章->Hexo生成HTML並推送到GitHub->GitHub Pages自動使用最新內容
現在由於Hexo渲染以后的HTML文件需要放到服務器上,那么工作流程變為:
本地寫Markdown格式文章->Hexo生成HTML並推送到GitHub->手動登錄服務器
->進入放博客文章的文件夾->執行命令git pull
增加的兩步雖然說操作量不大,但是總顯得很麻煩。於是我希望,在我把博客的HTML文件push到GitHub以后,服務器能自動從GitHub上把HTML內容拉下來。由於使用了Nginx,所以只要博客的HTML發生了更新,那么使用瀏覽器訪問https://kingname.info時,新內容自動就會出現。這樣一來,對我來說,看起來就像是我剛剛push了網頁內容到GitHub,博客就自動更新了。
讓服務器從GitHub上面拉代碼,這個操作本身很簡單。人來操作就一行代碼git pull。寫個Python腳本也就兩行代碼。但問題是,服務器怎么知道GitHub發生了更新?
有人說,Kingname,你不是做爬蟲嗎?你寫個爬蟲,每一秒檢查一下GitHub不就可以了嗎?這種辦法當然可以。但問題是,我一周就更新一次博客,但這個爬蟲為了等這一次更新,一周要訪問GitHub高達604800次?更何況我有時候一個月都不更新。
所以顯然不能讓服務器主動檢查GitHub更新,這種“輪詢”操作效率太低。那么如果反過來,一旦GitHub有更新,它就通知服務器,然后服務器再去拉代碼,這不就簡單高效了嗎?
解決問題
為了實現這個目的,就需要使用一些持續集成的工具。本文使用的是Jenkins。
Jenkins在敏捷開發界可以說是大名鼎鼎了。使用Jenkins搭建一整套持續集成環境,可以實現開發者往代碼倉庫一提交代碼,代碼自動進行單元測試,覆蓋率測試,代碼風格檢查自動生成報告,自動通知部門同事開始Code Review。當代碼被合並入主干以后,服務器自動拉下最新代碼,自動編譯,自動在幾千幾萬台服務器上部署。在整個過程中,開發者只需要做一件事,那就是git push(當然在實際情況下,后面還會加一些參數)。
本文實現的是博客的自動部署,沒有任何測試,也沒有Code Review,也沒有編譯,服務器也只有一台,復雜程度當然遠遠低於持續集成。不過管中窺豹,來看看這個簡單地流程是如何走通的,對初學者也會有幫助。
本文假設你已經在服務器上面搭建好了Jenkins環境。如果你還沒有安裝Jenkins或者不會安裝,那么可以“參考”這篇文章:搭建持續集成環境(一)。由於這篇文章是18個月以前寫的,系統也是小眾的Arch Linux,所以建議你還是在網上搜一下最新的Jenkins安裝教程比較好。
設置GitHub
在GitHub中進入博客所在的Repo,並點擊Settings,如下圖所示。

在設置頁面,單擊左側的Integrations & services,並選擇Add service,如下圖所示。

從下拉菜單中,選中Jenkins (GitHub plugin)。在新打開的界面,填寫Jenkins的信息,如下圖所示。

其中Jenkins hook url填寫的是我的服務器的Jenkins地址加上/GitHub-webhook/,所以完整的地址為http://xx.xx.xx.xx:8080/GitHub-webhook/。把這里的xx換成實際的IP地址或者域名即可。需要注意的是,網址末尾的斜杠一定不能省略。
填寫好信息以后保存,GitHub就配置好了。
配置Jenkins
Jenkins需要安裝GitHub Plugin才能接收到GitHub發來的通知。進入Jenkins的系統管理-管理插件,在可選插件選項卡中,搜索GitHub plugin並安裝,安裝完成Jenkins會重啟。重啟以后可以在已安裝選項卡下面發現GitHub plugin,如下圖所示。

回到Jenkins首頁,單擊左上角新建按鈕,新建一個項目,項目類型為構建一個自由風格的軟件項目。任務的配置信息如下圖所示。

其中的項目名稱和描述可以隨意填寫。勾選GitHub project,並把博客對應的GitHub Repo的地址填入。往下拉,看到源碼管理,點選Git,依然填寫博客對應的Repo地址。如下圖所示。

繼續往下拉,在構建觸發器單擊增加構建步驟,在彈出的下拉菜單中選擇Execute shell。勾選GitHub hook trigger for GITScm polling。在Execute shell對應的輸入框中輸入命令,將當前目錄下的所有文件和文件夾全部復制到/home/bexercise/kingname.github.io/文件夾下。如下圖所示。

其中,文件夾/home/bexercise/kingname.GitHub.io/里面的內容如下圖所示。這是Hexo生成的HTML文件和資源文件。

這里需要解釋一下這一條命令:
cp -r ./* /home/bexercise/kingname.GitHub.io/
其中的cp -r表示復制文件和文件夾。./表示當前目錄。./*表示當前目錄下面的所有內容。因此整條命令的意思是把當前目錄下的所有內容全部復制到/home/bexercise/kingname.GitHub.io/下,並且如果文件名相同,就會直接覆蓋。需要注意的是,kingname.GitHub.io這僅僅是一個普通的文件夾而已,別看它的名字長得像個網址,但其實它只是一個名字比較怪的普通文件夾而已,沒有什么特殊的意義。
這個項目在構建的時候,它會自動從GitHub上面對應Repo所有的文件拉取到當前的文件夾下,所以執行了這一條復制命令以后,博客HTML文件自然就被復制到了網站的根目錄下。
修改權限
由於Jenkins在安裝的時候,會自動創建一個名為jenkins的普通賬號,這個賬號沒有管理員權限。jenkins執行命令的時候,它也會使用這個賬號。但是由於kingname.GitHub.io這個文件夾是用戶bexercise創建的,所以jenkins賬號默認是沒有權限讀寫這個文件夾的。現在需要給jenkins賬號授予權限。使用bexercise這個賬號登錄服務器,使用以下命令給jenkins賦予權限,讓它可以讀寫kingname.GitHub.io文件夾:
sudo chown -R jenkins:jenkins /home/bexercise/kingname.GitHub.io
執行完成這一行命令以后,jenkins才可以把其他地方的文件復制到這個文件夾里面。
使用方法
沒有什么復雜的使用方法,在Hexo中,執行命令hexo d就可以把本地生成好的HTML文件提交到GitHub中。然后打開瀏覽器,打開博客,發現新的文章已經出現在首頁了。
在Jenkins項目的執行歷史里面,也可以看到它被自動觸發而產生的歷史記錄。如下圖所示。

舉一反三
由於Jenkins可以運行Shell命令,進行單元測試本質上也是運行一條命令,那這不就可以實現自動進行單元測試了嗎?那么如果把Shell命令改成運行一個Python腳本,那不就可以做任何事情了嗎?如果Python腳本里面寫了發送郵件的代碼,那不就實現了你一提交代碼,其他人就收到郵件了嗎?
