NodeJS App的持續整合(Continuous Integration)伺服器架設

應用程式開發過程中很重要的一個部分是Continuous Integration,尤其是團隊開發的情況底下,有一台CI Server對於掌控系統開發狀況、團隊協作等都有很大的幫助,也因此目前多數軟體開發一定會有個CI Server。在開發NodeJS App的時候自然也應該要有個CI Server,本篇文章有幾個重點:
  • 以Upstart Job的方式執行NodeJS App
  • 架設Jenkins並設定Jenkins Job,包含從Git Server取得原始碼、建置及自動部署的工作
  • CI Server的相關系統設定

這裡假設你已經:

  • 寫過一個以上的NodeJS App
  • 有一個Git Server做檔案控管
另外由於本人是使用CoffeeScript,因此會提到一些Cakefile的設定,Cakefile跟Makefile差不多,都是建置用的設定檔,不同的地方在於Cakefile也是以CoffeeScript語言撰寫。

那就讓我們開始進入正題吧,以下的操作都是在CI Server上(就簡稱CIS吧),在CI Server上我們會需要Node, NPM才能建置、執行NodeJS App、Git用以抓取原始碼、Jenkins是本文的主角:CI。

安裝指令很簡單:
#Git
sudo apt-get install git git-core

#NodeJS, NPM
sudo apt-get install nodejs npm
sudo apt-get install nodejs-dev #Optional:有需要才安裝

#Jenkins
sudo apt-get install jenkins
Jenkins預設是在8080 port,如果需要修改port的話到/etc/default/jenkins.conf
HTTP_PORT=8080 #改成你要的port

Upstart Job設定檔

Upstart是一支Linux下的task/service管理程式,已經內建在ubuntu,這裡我們需要設定一個myApp.conf來讓App在系統開機時執行/關機時關閉

#!upstart
description "myApp server"
author      "Fin Chen"

#開機執行/關機關閉
start on startup
stop on shutdown

# Restart when job dies
respawn

# Give up restart after 5 respawns in 60 seconds
respawn limit 5 60

#設定執行環境參數
env NODE_ENV=production

script
    logger "start running myApp..." #log到syslog
    chdir /data/apps/myApps #切換至App目錄,主要是避免執行node時的目錄抓取問題
    exec /usr/bin/node /data/apps/myApp/lib/app.js > /data/apps/myApp/log/app.log 2>&1
end script
這裡我們設定了一個簡單的Job,開機時執行myApp/lib/app.js並log,並且會在crash之後試著重啓。之後只要把這個設定檔放在/etc/init/#{jobName}.conf下面,就可以用sudo start/stop #{jobName}來手動執行/關閉此Job。(Copy設定檔的動作寫在下一章節的Cakefile裡,也是自動化的)

Cakefile新增Install Task

如果你的Cakefile/Makefile沒有相關的Install Task,那就需要建立一個,Jenkins建制的時候也會用到。Install Task的目的很簡單:建置需要執行App所需要的檔案及環境。以下是參考用的Cakefile部分
install = (options) ->
  base = options.basedir or '/data/apps/dove-server'
  console.log   "Installing app to #{base} ..."
  exec([
    "npm install" #抓取相關lib
    "sudo mkdir -p #{base}" #建立App目錄
    "sudo cp -rf node_modules public lib views config.json #{base}" #複製檔案
    "sudo cp myApp.conf /etc/init/myApp.conf" #把upstart設定檔放到預設的system job資料夾
  ].join(' && '), (err, stdout, stderr) ->
    if err then console.log stderr.trim() else console.log 'Install successfully completed'
  )
task 'install', 'installing apps', -> build -> install({})
#此處與install無關的設定都省略,build部分就是run coffescript compiler並建置其他需要的檔案。Install task的工作就是先build之後再執行上面的Install function

Jenkins Jobs

安裝完成的Jenkins透過瀏覽器開啓http://ServerIP:8080(預設port 8080)來開啓界面,應該會長得像下面這樣(剛安裝完的應該不會有Job在裡面所以右邊應該是空的) 在這我們要先幫Jenkins裝一個Git Plugin,點擊左方的管理Jenkins,選擇管理插件進入插件頁面,標簽列點擊有效的,然後搜尋(ctrl+f)Git Plugin(Git相關Plugin很多,注意別找錯了),勾選checkbox之後拉到最下方點及安裝就完成安裝。

新增App Job:點擊New Job進入新增Job頁面,填入Job name(這裡我輸入myApp)並選擇Build a free-style software project後完成新增。之後就會在首頁看到一個新的Job。

設定App Job:從首頁的Job列表直接點myApp(Job name)進去,點擊左方選單的設定,在這填入Git Repositories資料(URL, Branch, Browser),如下圖:

註:如果是使用Bitbucket等需要以https登入的public git service那麼輸入的URL會像這樣https://{username}:{password}@bitbucket.org/{git_location},這是目前使用Jenkins比較方便的登入方式,直接用bitbucket給的clone url是不能用的。如果不想把密碼直接打在這裡的話可以參考這篇文章

再來是設定build的時間,此處用cron的格式來設定。以及build的時候要做哪些事情,見下圖:

可以看到此數在每天早上05:19的時候執行下方的shell指令:cake install,stop/start myApp,也就是每天早上Jenkins會先從Git把資料抓下來,執行一次install,並且重啓app。

另外要注意git需要設定global name/email參數,沒有設定的話git功能是無法使用的:

su - jenkins
git config --global user.name "username"
git config --global user.email "email"

Sudo設定

如果只是照前面的設定,Jenkins會因為沒有sudo權限而在在sudo stop/start的指令卡死(或更早的install script地方),所以我們還要額外的給Jenkins一些sudo權限,執行sudo visudo並輸入以下設定
#讓使用者jenkins可以擁有以下指令的sudo權限,並且不用密碼
jenkins ALL = NOPASSWD: /bin/mkdir, /bin/rm, /bin/cp, /sbin/start, /sbin/stop

如此就大致上設定完成了。

確認

我們可以直接執行Jenkins Jobs頁面左方的"馬上建構"測試job是否有執行。並可以連入Server輸入以下指令確認真的有跑起來:
$status myApp
myApp start/running, process 3607 #顯示程序為running狀態,並且PID為3607
$ps -ef | grep 3607 #查詢PID 3607程序的資料

總結

一切設定順利完成之後,系統會每天自動從git抓取最新資料建置並安裝執行,我們就可以每天從CI Server得知程式的最新狀態,並可以拿CI Server來做一些相關的測試。

沒有留言:

張貼留言