不用打開界面,在命令行完成代碼部署(jenkins)

問題

有時候,在本地提交完代碼,接着需要將代碼部署到測試壞境。

一般部署過程都需要自己登錄到某個部署平臺,手動去觸發。(不包括有些可能直接push完代碼就自動觸發部署了)。

雖然這樣手動觸發操作很簡單,但每次都打開網頁,找項目,去操作,也不免有些麻煩。

思考

能不能在提交完代碼,就接着在命令行,完成部署呢?

簡單實現

這裏以 jenkins 爲例,說說我的處理過程。

1、打開 jenkins 中你要遠程部署的項目界面,點擊配置。
在這裏插入圖片描述
2、在配置中找到“構建觸發器”欄目,在“身份驗證令牌”中填入一段字符串。下面的小字是訪問鏈接的拼寫規則,原來遠程構建觸發器是通過 HTTP 協議訪問鏈接實現的,接下來說說拼寫規則。記得先將這步的修改應用,保存。
在這裏插入圖片描述
3、完成了這些,我們來說觸發鏈接的拼寫規則:

參數說明:
JENKINS_URL: jenkins 的域名或ip + 端口號
PEOJECT_NAME:項目名稱
TOKEN_NAME:上一步配置的字符串

  • 不帶參數:
JENKINS_URL/job/PROJECT_NAME/build?token=TOKEN_NAME
  • 帶參數:
JENKINS_URL/job/PROJECT_NAME/buildWithParameters?token=TOKEN_NAME&KEY=value

4、拿着第三步拼好的鏈接,直接在瀏覽器中訪問。

如果返回 201 狀態碼,恭喜已經成功觸發部署了。
如果返回 403 狀態碼,那麼可能你的 jenkin 開啓了 CSRF 保護。
需要回到主界面 -> 系統管理 -> 全局安全配置 -> 找到 CSRF Protection 關掉就好了。

通過上面的簡單操作,已經可以實現遠程觸發構建了,但是如果需要在命令行訪問的話,我們還需要寫一個簡單的 shell 腳本。

#  你的 jenkins 用戶名
user="USERNAME"
# 你的 jenkins 密碼 
password="PASSWORD"

curl -u $user:$password 上面拼接好的URL

保存上面的腳本文件到自己的項目裏,在 .gitignore 忽略掉,比如我保存到我的項目下並命名爲 .publish

接下來測試下好不好用,在項目目錄下,直接執行 sh .publish,然後回到 jenkins 項目界面,發現項目已經在部署了。

優化

經過上面的處理,已經完成用命令行遠程觸發構建。但是有一個小缺憾,就是觸發部署後,沒有狀態返回。這個我怎麼知道部署成功了沒有?

我們先整理思路。

因爲觸發部署的時候並沒有返回什麼可利用的信息,所以要想拿到部署過程中的狀態返回,必須輪詢 /api/json 接口,這個接口會返回部署的相關信息。

接口格式:

JENKINS_URL/job/PROJECT_NAME/api/json

接下來我們分析這個接口返回的信息,看看有什麼可以利用的?

分析後發現,想要做顯示進度肯定沒戲了。但我們發現有這幾個字段可以利用,來實現簡單的狀態判斷。

這幾個字段下都會自帶一個數字 id。

lastBuild // 最後一次構建
lastCompletedBuild // 最後一次完成的構建
lastSuccessfulBuild // 最後一次成功的構建

在構建開始 lastBuild 會生成一個新 id,這個時候 lastCompletedBuild 的 id 還是上次構建的 id。等 lastCompletedBuild 的 id 變成新 id,標誌着構建完成。這個時候再對比 lastBuild 和 lastSuccessfulBuild 是否一樣,來判斷構建是否成功。

有了思路,我們來用代碼實現。

由於部署信息接口返回的都是 json 或者 xml 格式,用 bash 解析可能需要安裝其他東西。所以接下來用 node.js 實現。

這裏爲了簡單,我還用 curl 來模擬登錄。除此之外,也可以在 jenkins 中設置自己用戶的 token (網上有教程)或者使用 node.js 模擬登錄。

/**
 * 觸發部署腳本
 * 需要在 node 環境下運行
 */
const exec = require('child_process').exec

// 獲取命令行最後一個參數
const arg = process.argv.pop()

// jenkins 的登錄賬號密碼
const user = 'USER_NAME'
const password = 'PASSWORD'

// 訪問地址
const url = 'JENKINS_URL/job/'

// 環境配置,這裏的 key 對應輸入的參數
const envArr = {
  test: 'PROJECT_NAME',
  pre: 'PROJECT_NAME'
}

// 默認部署測試環境
let env = envArr[arg] ? envArr[arg] : envArr['test']

// 構建命令
const build = `curl -u ${user}:${password} ${url +
  env}/buildWithParameters?token=XXX&KEY=value`
// 獲取部署信息命令
const info = `curl -u ${user}:${password} ${url + env}/api/json`

function sleep() {
  return new Promise(resolve => {
    setTimeout(resolve, 1000)
  })
}

// 開始構建
function start(cmd) {
  return new Promise((resolve, reject) => {
    exec(cmd, (err, stdout, stderr) => {
      if (err) reject(err)
      else resolve(stdout)
    })
  })
}

// 獲取部署信息
function getInfo(cmd) {
  return new Promise((resolve, reject) => {
    exec(cmd, (err, stdout, stderr) => {
      if (err) reject(err)
      else resolve(stdout)
    })
  })
}

void (async () => {
  await start(build)

  let data = JSON.parse(await getInfo(info))
  var lastId = data.lastBuild.number
  var comId = data.lastCompletedBuild.number
  var sucID = data.lastSuccessfulBuild.number

  console.log('開始部署')

  // 判斷是否部署完成
  while (lastId !== comId) {
    console.log(`#${lastId} ${env} 部署中,請稍等...`)

    // 休息後請求
    await sleep()
    let data = JSON.parse(await getInfo(info))
    lastId = data.lastBuild.number
    comId = data.lastCompletedBuild.number
    sucID = data.lastSuccessfulBuild.number
  }

  // 判斷是否部署成功
  if (sucID === lastId) {
    console.log('部署成功!')
  } else {
    console.log('部署失敗!')
  }
})()

對於上面的代碼進行自己業務參數的更改,命名爲 .publish 就可以實現命令行發佈了。

node .publish test // 測試環境部署
node .publish pre // 預發佈環境部署

最後看下最終的運行效果,部署過程中,每行開頭會顯示這次部署的id,中間(馬賽克)是項目名稱:
在這裏插入圖片描述
好了,上面就是關於 jenkins 遠程觸發構建的嘗試,後面可能還會優化。因爲對各方面的知識都是剛接觸,可能有些地方思路有侷限性。希望有大牛看到可以提出寶貴的意見。謝謝!

end~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章