手把手帶你一塊兒從0到1搭建一個企業級的自動化構建流程 網上完整的關於多分支流水線的配置不多,但願這篇不短的文章能給你帶來幫助html
因爲公司的Jenkins配置沒有部署成功的通知,在我學了幾天的Jenkins後終因而對公司的Jenkins配置下手了,結果我剛裝完dingtalk
插件自動重啓後,發現以前主管配置的構建項目數據都丟失了,害,正好給了我練手的機會,因而就有了如下從0到1的辛酸歷程。前端
這裏假設你的服務器已經裝好了dockerjava
使用的鏡像是jenkinsci/blueocean
,這是一個jenkins的穩定及持續維護的鏡像源,自己就集成了Blue Ocean等使用插件,很是方便。node
docker pull jenkinsci/blueocean
複製代碼
docker run -idt --name kmywjenkins -p 9090:8080 -p 60000:50000 -v jenkins-data:/var/jenkins_home -v /data/web-data/docker.sock:/var/run/docker.sock jenkinsci/blueocean
複製代碼
參數解釋:linux
-idt
以交互的方式、新建一個模擬終端運行容器git
--name
容器的別名web
-p
指定容器映射宿主機的端口 -> 宿主機端口:容器端口正則表達式
-v jenkins-data:/var/jenkins_home
Jenkins容器在工做的時候,若是要執行Docker的命令(例如 docker ps、docker run等),須要有個途徑能鏈接到宿主機的docker服務,此參數就是用來創建容器和宿主機docker服務的鏈接的spring
-v /data/web-data/docker.sock:/var/run/docker.sock
將該容器的數據保留在宿主機的目錄,這樣即便容器崩潰了,裏面的配置和任務都不會丟失docker
須要注意的是,docker中默認是以jenkins
用戶運行的Jenkins,如需以root用戶能夠加參數-u root
,本示例未指定root。
有時候須要進入Jenkins容器執行一些命令,能夠經過docker exec
命令訪問,例如:docker exec -it [containerid] bash
若要手動重啓Jenkins,能夠執行如下命令:docker restart [containerid]
經過以上步驟,若是正常走到這裏,能夠經過如下地址訪問http://121.41.16.183:9090/
,ip地址爲服務器的地址。
輸入一下命令獲取解鎖的token,docker exec kmywjenkins cat /var/jenkins_home/secrets/initialAdminPassword
在瀏覽器中輸入對應的token以解鎖:
鏈接git倉庫,ssh鏈接服務器均須要相應的憑據,能夠在憑據管理中先建立好,而後須要使用的地方直接選擇憑據便可。這裏以鏈接git、ssh須要的憑據爲例:
類型選擇Username with password
用戶名密碼爲登陸gitte的帳號密碼
ID是憑據的惟一標識,可自定義,後面在JenkinsFile中經過ID去引用憑據
配置後的結果
ssh鏈接服務器時須要密鑰,咱們先在服務器生成一對公私鑰,而後複製私鑰,填入便可
類型選擇SSH Username with private key
Username
是鏈接服務器的用戶名,如jenkins
在Private Key
項選中Enter directly
,點擊Add,粘貼剛複製的私鑰
配置後的結果
以前的Jenkins任務是FreeStyle的方式建立的,這種方式不夠靈活,界面也不夠清爽,這裏選擇使用聲明式流水線方式(Declarative Pipeline)建立,能夠多分支獨立構建,便於之後的擴展。
咱們這裏使用 BlueOcean 這種方式來完成此處 CI/CD 的工做,BlueOcean 是 Jenkins 團隊從用戶體驗角度出發,專爲 Jenkins Pipeline 從新設計的一套 UI 界面,仍然兼容之前的 fressstyle 類型的 job,BlueOcean 具備如下的一些特性:
若是安裝的是jenkinsci/blueocean
鏡像,默認是已經集成了BlueOcean,沒有的可前往插件管理安裝對應的插件。
點擊打開Blue Ocean,能夠看到已經建立好的兩個流水線,分別是前端和後臺,須要用到不一樣的工具,在後面會提到,如何建立流水線
點擊建立流水線
我司用的是gitte,因此選擇Git,而後填入要鏈接的倉庫地址,須要鏈接到Git倉庫的憑據,咱們以前已經建立好了,直接選中便可,若是未建立,在下面的表單直接編輯便可,最後點擊建立流水線
到這裏咱們就建立了一個多分支流水線,Jenkins會掃描倉庫,帶有JenkinsFile的分支會被檢測出來,JenkinFile是多分支流水線的配置文件,使用的是Groovy語法,能夠直接點擊建立流水線,Jenkins會自動爲你的項目建立一個JenkinsFile
如今能夠可視化地編輯想要執行的階段及步驟,這裏加了一個打包的階段,裏面有個步驟是提示開始打包
,點擊保存
填入提交信息,點擊Save & Run
,會講JenkinsFile上傳到git,並根據JenkinsFile執行一個構建任務,目前的構建步驟只有一個,是提示開始打包
我這裏不知道爲何會卡在這個地方不動,因此我在vscode直接建立並編輯JenkinsFile,這種方式更靈活,我更推薦這種方式,下面我會先簡單介紹下JeninsFile的基礎語法,僅包含本項目用到的,對於中小企業的構建需求,基本夠用了。
只需先了解大體的語法,具體的用法會在後面說明
// 前端項目JenkinsFile配置,後端項目配置稍有不一樣,後面會區分說明
pipeline {
agent any
environment {
HOST_TEST = 'root@121.41.16.183'
HOST_ONLINE = 'jenkins@39.101.219.110'
SOURCE_DIR = 'dist/*'
TARGET_DIR = '/data/www/kuaimen-yunying-front'
}
parameters {
choice(
description: '你須要選擇哪一個環境進行部署 ?',
name: 'env',
choices: ['測試環境', '線上環境']
)
string(name: 'update', defaultValue: '', description: '本次更新內容?')
}
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
causeString: 'Triggered on $ref',
token: 'runcenter-front-q1w2e3r4t5',
tokenCredentialId: '',
printContributedVariables: true,
printPostContent: true,
silentResponse: false,
regexpFilterText: '$ref',
regexpFilterExpression: 'refs/heads/' + BRANCH_NAME
)
}
stages {
stage('獲取git commit message') {
steps {
script {
env.GIT_COMMIT_MSG = sh (script: 'git log -1 --pretty=%B ${GIT_COMMIT}', returnStdout: true).trim()
}
}
}
stage('打包') {
steps {
nodejs('nodejs-12.16') {
echo '開始安裝依賴'
sh 'yarn'
echo '開始打包'
sh 'yarn run build'
}
}
}
stage('部署') {
when {
expression {
params.env == '測試環境'
}
}
steps {
sshagent(credentials: ['km-test2']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} uname -a"
sh "scp -r ${SOURCE_DIR} ${HOST_TEST}:${TARGET_DIR}"
sh 'echo "部署成功~"'
}
}
}
stage('發佈') {
when {
expression {
params.env == '線上環境'
}
}
steps {
sshagent(credentials: ['km-online']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} uname -a"
sh "scp -r ${SOURCE_DIR} ${HOST_ONLINE}:${TARGET_DIR}"
sh 'echo "發佈成功~"'
}
}
}
}
post {
success {
dingtalk (
robot: '77d4c82d-3794-4583-bc7f-556902fee6b0',
type: 'MARKDOWN',
atAll: true,
title: '你有新的消息,請注意查收',
text:[
'# 運營管理系統發佈通知',
'---',
'#### **所屬:前端**',
"#### **構建任務:${env.BUILD_DISPLAY_NAME}**",
"#### **Git commit:${env.GIT_COMMIT_MSG}**",
"#### **本次更新內容:${params.update}**",
"#### **部署環境:${params.env}**",
'#### **構建結果:成功**'
]
)
}
}
}
複製代碼
pipeline
必須在最外層
agent
定義了在哪一個環境裏執行,默認any
stages
階段,標識構建流程的標籤塊,子節點是stage
steps
執行步驟
post
全部階段執行完成後執行一些邏輯
when
能夠控制該階段是否執行
environment
環境變量,在這裏定義的變量,JenkinsFile的任何地方均可以訪問
tools
項目使用到的構建工具,聲明系統配置中已經定義好的工具,如maven
parameters
定義參數,能夠提供用戶輸入或者選擇
post
構建結束後會執行這裏,有success
、failure
、success
,本示例將在success
(構建成功時)發起釘釘通知
因爲我司的技術團隊較小,CI/CD流程就沒那麼複雜,不會包含代碼檢查、自動化測試、Code Review等流程,我將簡要說明我所搭建的前端與後端CI/CD流程以及爲何這麼搭建。
提供兩種構建方式,一種是代碼上傳自動構建,一種是參數化構建,可選擇部署到測試環境仍是線上環境。
自動構建默認部署到測試環境,因爲線上環境很重要,自動化構建會有必定風險,因此須要人工干預選擇參數進行構建。
後端的全部項目都是放在一個git倉庫中,因此就沒有作自動構建
接下來就每一步做詳細說明,以及可能遇到的坑
當咱們提交新的代碼到git倉庫,Jenkins就會自動開始構建已經配置好的該項目的任務
在git倉庫配置一個Jenkins服務器的webhook地址,當git倉庫有變更時會請求這個地址,Jenkins就能收到通知而後開始構建任務
咱們須要先安裝一個插件Multibranch Scan Webhook Trigger,可進入插件管理搜索進行安裝
進入項目的配置界面,勾選Scan by webhook,填入自定義token,須要確保token的惟一性,不會與其它項目的衝突
過濾分支
這是一個多分支流水線,Jenkins默認會檢出全部包含Jenkinsfile的分支,若是配置了webhook,就會自動觸發相應分支的構建任務;有時候咱們只想master發生變化後纔去構建任務,這時就用到了過濾分支的配置,進入項目配置,在分支源git
項找到add
按鈕並點擊
選擇根據名稱過濾(支持通配符)
,或者你能夠選擇根據名稱過濾(支持正則表達式)
,效果同樣,只是過濾格式不太同樣,我這裏在相應的地方填入master
,即只檢索master
分支,這樣就達到咱們想要的效果了。
進入遠端倉庫(我這裏是Gitte),點擊Webhooks,接着點擊添加 WebHook
填入URL,IP地址爲Jenkins部署的服務器,token爲咱們剛設置的,/multibranch-webhook-trigger/invoke
是固定地址,點擊添加
會自動發起一個請求,即咱們剛填寫的,如相應以下則表示配置成功,相應的構建任務也會自動執行
使用了yarn
進行安裝依賴及打包,須要先配置nodejs環境
nodejs
進行安裝 nodejs-版本號
,該項目用的是yarn
,因此在Global npm package to install
,加入了配置項,構建的時候會自動安裝yarn
,若是是npm能夠忽略該配置 pipeline {
stage('打包') {
steps {
// 執行環境,nodejs-12.16是咱們剛配置的別名,還有一種方式是在agent中配置執行環境,在tools中配置使用的包,感興趣的能夠自行研究
nodejs('nodejs-12.16') {
echo '開始安裝依賴'
sh 'yarn'
echo '開始打包'
sh 'yarn run build'
}
}
}
}
複製代碼
pipeline {
tools {
maven 'Maven3.6.3'
}
parameters {
// 提供要部署的服務器選項
choice(
description: '你須要選擇哪一個環境進行部署 ?',
name: 'env',
choices: ['測試環境', '線上環境']
)
// 提供構建的模塊選項
choice(
description: '你須要選擇哪一個模塊進行構建 ?',
name: 'moduleName',
choices: ['kuaimen-contract', 'kuaimen-core', 'kuaimen-eureka-server', 'kuaimen-manage', 'kuaimen-member', 'kuaimen-order', 'kuaimen-shop', 'tiemuzhen-manage']
)
booleanParam(name: 'isAll', defaultValue: false, description: '是否須要全量(包含clean && build)')
string(name: 'update', defaultValue: '', description: '本次更新內容?')
}
stages {
stage('全量清除舊數據...') {
when {
expression {
params.isAll == true
}
}
steps {
echo "開始全量清除"
sh "mvn package clean -Dmaven.test.skip=true"
}
}
stage('全量打包應用') {
when {
expression {
params.isAll == true
}
}
steps {
echo "開始全量打包"
sh "mvn package -Dmaven.test.skip=true"
echo '打包成功'
}
}
stage('清除舊數據...') {
when {
expression {
params.isAll == false
}
}
steps {
echo "開始清除${params.moduleName}模塊"
sh "cd ${params.moduleName} && mvn package clean -Dmaven.test.skip=true"
}
}
stage('打包應用') {
when {
expression {
params.isAll == false
}
}
steps {
echo "開始打包${params.moduleName}模塊"
sh "cd ${params.moduleName} && mvn package -Dmaven.test.skip=true"
echo '打包成功'
}
}
}
}
複製代碼
parameters
parameters
中主要是提供參數化構建的選項,在其它地方能夠經過"${params.isAll}"
這種形式拿到用戶的交互信息,配置後效果以下:
when>expression
表達式中的參數若是未true
,則執行,反之跳過該stage
mvn
在系統配置中默認就已經提供了該環境,進入系統全局工具配置,添加以下配置(相似nodejs)
這種方式引用
tools {
maven 'Maven3.6.3'
}
複製代碼
pipeline {
agent any
environment {
HOST_TEST = 'root@121.41.16.183'
HOST_ONLINE = 'jenkins@39.101.219.110'
SOURCE_DIR = 'dist/*'
TARGET_DIR = '/data/www/kuaimen-yunying-front'
}
stage('部署') {
when {
expression {
params.env == '測試環境'
}
}
steps {
sshagent(credentials: ['km-test2']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} uname -a"
// 將打包好的文件上傳到服務器
sh "scp -r ${SOURCE_DIR} ${HOST_TEST}:${TARGET_DIR}"
sh 'echo "部署成功~"'
}
}
}
stage('發佈') {
when {
expression {
params.env == '線上環境'
}
}
steps {
sshagent(credentials: ['km-online']) {
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} uname -a"
sh "scp -r ${SOURCE_DIR} ${HOST_ONLINE}:${TARGET_DIR}"
sh 'echo "發佈成功~"'
}
}
}
}
}
複製代碼
environment
定了全局變量,在其它地方可直接引用
sshagent
用於鏈接服務器,須要先安裝插件ssh-agent,credentials
是鏈接服務器的憑據ID,咱們在一開始已經教你們建立好了
pipeline {
agent any
environment {
HOST_TEST = 'root@121.41.16.183'
TARGET_DIR = '/data/www/kuaimen-auto'
HOST_ONLINE = 'jenkins@39.101.219.110'
}
tools {
maven 'Maven3.6.3'
}
stage('部署應用') {
when {
expression {
params.env == '測試環境'
}
}
steps {
echo "開始部署${params.moduleName}模塊"
sshagent(credentials: ['km-test2']) {
sh "ssh -v -o StrictHostKeyChecking=no ${HOST_TEST} uname -a"
// 將打包後的文件上傳到服務器
sh "cd ${params.moduleName}/target && scp *.jar ${HOST_TEST}:${TARGET_DIR}/${params.moduleName}"
// 匹配出該Java進程而後殺掉
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} \"uname;ps -ef | egrep ${params.moduleName}.*.jar | egrep -v grep | awk '{print \\\$2}' | xargs -r sudo kill -9\""
// 啓動該進程
sh "ssh -o StrictHostKeyChecking=no ${HOST_TEST} \"nohup /data/apps/jdk1.8/bin/java -jar ${TARGET_DIR}/${params.moduleName}/${params.moduleName}-0.0.1-SNAPSHOT.jar --spring.profiles.active=test >/dev/null 2>&1 &\""
sh 'echo "部署成功~"'
}
echo '部署成功'
}
}
stage('發佈應用') {
when {
expression {
params.env == '線上環境'
}
}
steps {
echo "開始發佈${params.moduleName}模塊"
sshagent(credentials: ['km-online']) {
sh "ssh -v -o StrictHostKeyChecking=no ${HOST_ONLINE} uname -a"
sh "cd ${params.moduleName}/target && scp *.jar ${HOST_ONLINE}:${TARGET_DIR}/${params.moduleName}"
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} \"uname;ps -ef | egrep ${params.moduleName}.*.jar | egrep -v grep | awk '{print \\\$2}' | xargs -r sudo kill -9\""
sh "ssh -o StrictHostKeyChecking=no ${HOST_ONLINE} \"nohup /data/apps/jdk1.8/bin/java -jar ${TARGET_DIR}/${params.moduleName}/${params.moduleName}-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev >/dev/null 2>&1 &\""
sh 'echo "發佈成功~"'
}
echo '發佈成功'
}
}
}
複製代碼
須要注意的是,在匹配進程的那段shell中的awk '{print \\\$2}'
,$
符號須要用三個反斜線進行轉義,否則會沒法執行成功,這裏曾卡了很久,但願大家別踩坑了
咱們這裏使用釘釘發起通知,主要原理是在釘釘羣建立一個webhook機器人,而後把webhook的地址填入DingTalk插件的配置項,最後在JenkinsFile中進行以下配置便可:
pipeline {
stage('獲取git commit message') {
steps {
script {
// 將獲取到的git commit賦值給GIT_COMMIT_MSG
env.GIT_COMMIT_MSG = sh (script: 'git log -1 --pretty=%B ${GIT_COMMIT}', returnStdout: true).trim()
}
}
}
post {
success {
dingtalk (
robot: '77d4c82d-3794-4583-bc7f-556902fee6b0',
type: 'MARKDOWN',
atAll: true,
title: '你有新的消息,請注意查收',
text:[
'# 運營管理系統發佈通知',
'---',
'#### **所屬:後端**',
"#### **構建任務:${env.BUILD_DISPLAY_NAME}**",
"#### **本次更新內容:${params.update}**",
"#### **部署環境:${params.env}**",
'#### **構建結果:成功**'
]
)
}
}
}
複製代碼
GIT_COMMIT
這個是Jenkins系統全局變量,得到的是git commit ID,而後經過它拿到具體的提交信息,並賦值給env.GIT_COMMIT_MSG
,全局變量能夠經過這種方式訪問env.BUILD_DISPLAY_NAME
robot爲機器人ID,在系統配置中添加以下配置項
webhook在建立完機器人的時候可以拿到
點擊羣設置 -> 智能羣助手
選擇自定義機器人,配置完成後就能夠看到webhook的地址了
通過上面的配置,咱們已經完成了前端、後臺的自動化構建配置,接下來再說明一下分別是如何觸發構建的
Build with Parameters
,選擇相應的參數進行構建,線上環境必須經過這種方式,保證必定的安全性 後端只配置了參數化構建,緣由前面已經說了,選擇要構建的環境、模塊進行構建
點擊打開Blue Ocean
選擇要構建的分支
彈出參數選擇,這和Build with Parameters
差很少,可是界面更好看,更清爽了,選擇後點擊Run
便可開始構建
構建結果,很直觀,根據顏色能夠判斷構建成功了,若是失敗了是紅色
在Blue Ocean的活動欄能夠看到歷史構建,點擊以下位置的按鈕能夠從新構建該歷史項,即回滾
到這裏終於告一段落了,雖然折騰了很多時間,可是將公司的工程化流程完善了仍是有點小小的成就感的,之後能夠愉快得寫代碼了,自動化的事情就交給Jenkins了。
將這個記錄下來一個是方便之後隨時查閱,還有一個是但願能讓朋友們少踩些坑,完~
BlueOcean實戰多分支pipeline構建(Jenkins)
Complete Jenkins Pipeline Tutorial for Beginners [FREE]