最近都好忙,需求太多了,幹不完,加上最近作息時間的調整,都沒時間寫部落格了,趁著這兩天稍微有點時間,想擼一發;
其實在寫的部落格有好幾篇,但都是陸陸續續的,本來想繼續寫之前的,突然想起半個月前,同學提出,能不能在開發提tag時自動打包?
之前釋出過一篇專案流程規範,目前的專案都在遵守這個規範,而研發每次有改動過程式碼的時候,都會提測,而提測就相當於提tag,這個tag
的概念不說了,就是基於當前產品分支重新拉的分支,tag的格式如下圖;
而測試拿到這個tag後,就需要去到jenkins打包,要輸入一堆引數,然後等待打包結果;
有時候,研發勤奮點,一天提多次tag,測試就需要多次去打包,測試同學覺得太麻煩了,因此就提出一個想法,能不能在開發提tag時自動打包?
能,必須能,沒有做不到的事情;
分解
做事之前,要先想想要做什麼?
- 搭建jenkins環境及安裝對應外掛
- jenkins打通到gitlab
- 觸發任務
想了下,大致就這3步,那就來一起做吧;
搭建jenkins
為了測試,jb就用了自己的阿里雲伺服器從頭開始搭建一遍,具體搭建過程不說明,之前寫的一篇文章有提及到,直接對照操作就好;
步驟 | 說明 |
---|---|
安裝Java | sudo yum install java |
安裝jenkins | yum install jenkins |
啟動jenkins | service jenkins start |
安裝外掛 | 完 |
注意
修改jenkins埠 jenkins預設埠是8080,可能會跟別的軟體衝突,因此建議修改下埠;
進入jenkins配置檔案
vi /etc/sysconfig/jenkins
複製程式碼
開啟後,找到JENKINS_USER
跟JENKINS_PORT
這兩項進行修改即可;
修改成root跟具體埠儲存退出即可;
這時候,直接輸入主機IP+剛設定的埠就好啦;
阿里雲開放埠許可權 上面訪問ip+埠,有可能打不開連結,因為阿里雲對埠做了限制,因此需要開放埠;
登入阿里雲,首頁右上找到控制檯;
找到雲伺服器ECS
點選例項,找到該例項的安裝組配置
點選規則說明,新增即可;
如果是按照上面的文件來,安裝完外掛,建立完使用者後,就應該進入到首頁,會顯示如下內容,至此,jenkins環境搭建就完啦~!
對了,jenkins的目錄在這裡:
/var/lib/jenkins
複製程式碼
jenkins打通到gitlab
公司的程式碼倉庫是用gitlab,因某種原因,就開放公網啦,那jb就在gitlab新建一個jbtest專案;
如果有小夥伴說,沒有gitlab怎麼辦?沒關係,可以用github代替,至於github相關的配置,可以檢視該文章:git介紹及GitHub配置教程
jenkins安裝gitlab
既然確定是要用jenkins+gitlab,那就先在jenkins上安裝下gitlab外掛吧;
點選jenkins首頁,有個系統管理按鈕;
點選後右側會顯示內容,下滑,點選外掛管理;
進入到外掛管理介面,就看到updates等4個欄目,那點選Available
,右側輸入gitlab
,然後找到GitLab
跟GitLab Hook
,勾選,點選底部的install即可;
test專案有了,gitlab的外掛也安裝了,那我們就在jenkins新建一個job吧,輸入了專案名稱,就進入到設定項;
丟棄舊的構建
這裡的丟棄舊的構建,可選,但是習慣選擇7天,,最大保留300個; 原因是,jenkins每次構建都會生成一個歷史構建記錄及對應的產物,如果公司有100個產品,每天自動打包10次,一天就有1000個產物,伺服器磁碟空間是個問題,因此設定個7天,設定個最大數,定時刪除即可;
- 持構建的天數:根據你所填寫的天數來儲存構建記錄
- 保持構建的最大個數:有幾條構建記錄就儲存幾條
- 釋出包保留天數:釋出的產物儲存的天數
- 釋出包最大保留#個構建:釋出了多少個產物就儲存多少個
上面的丟棄舊構建不是要點,繼續;
繼續下滑,會發現Source Code Management
,中文是原始碼管理,而我們的程式碼是存放到gitlab的,因此就選擇git了,點選後如下圖展開;
這裡有小夥伴可能有疑問,既然是放gitlab,為啥不是選擇gitlab,而是選擇git?
git、github、gitlab
這裡就花點時間說明下git、github、gitlab;
git是一款免費的、開源的分散式版本管理控制系統(工具);
gitHub是一個面向開源及私有軟體專案的託管平臺,
只支援git作為唯一的版本庫格式進行託管;
gitlab,是一款基於Git的專案管理軟體,擁有GitHub擁有的一切,但它還具備讓團隊對它們的repositories進行控制的功能;
複製程式碼
希望經過這麼一說,能讓你稍微清楚下;
原始碼管理
點選git,把專案的地址copy到這裡;
沒許可權是肯定的,那我們就點選add
建立賬戶唄,選擇jenkins;
輸入gitlab/github的賬號密碼,但是輸入完後發現還是報錯;
彆著急,那去伺服器上看看,git安裝了嗎?
沒安裝,那就安裝羅;
yum install git
複製程式碼
等待安裝完,再輸入git --version
跟where is git
來看版本及安裝位置;
安裝完後,就順便試試能不能clone專案吧;
不出所料,果然不行,因為還要配置金鑰啊;
$ ssh-keygen -t rsa -C "your_email@youremail.com"
//注意,雙引號裡面是你的郵箱。填你註冊github的郵箱就行了。按enter執行。
複製程式碼
一路回車就行,密碼一般不用設定~
上圖紅框裡的就是地址,cd過去;
有id_rsa
和id_rsa.pub
兩個檔案,這兩個就是SSH Key的祕鑰對,
id_rsa
是私鑰,不能洩露,
id_rsa.pub
是公鑰,可以公開;
配置ssh
在git bash 執行 cat id_rsa.pub
,把輸出的內容copy出來,然後開啟gitlab/github網站,點選右上角自己的圖示,點選Setting->ssh key
頁面,點選add ssh key
~
這裡還有一個特殊的問題:
因開放公網的原因,每次git clone
的下載程式碼的時候是連線的https://
而不是git@git (ssh)
的形式,導致每次pull/push等遠端操作的時候,都需要輸入賬號密碼,非常麻煩;
解決辦法:
在專案根目錄輸入:
git config --global credential.helper store
git pull/git push(第一次要再輸入一次,以後就不用)
複製程式碼
會在使用者目錄下生成檔案.git-credential記錄使用者名稱密碼的資訊;
那回到jenkins,開啟測試job的設定,再看是否正常;
發現已經好了,沒問題,當然也會有小夥伴依然有問題,那就需要這樣做;
- 開啟jenkins首頁
- 點選系統管理
- 全域性工具設定
- 修改git地址
開啟後,滑動到git欄,如果有問題的話,可能會看到錯誤提示:
There's no such executable git in PATH: /sbin, /usr/sbin, /bin, /usr/bin.
複製程式碼
在出錯的地方填入:
"whereis git"的地址 + "/bin/git"
(如上面"whereis git"的地址為"/usr/bin/git",則應該填入 "/usr/bin/git/bin/git") 並儲存
複製程式碼
然後再回到job的原始碼管理中新增git地址,就會好了;
既然可以連線到gitlab了,那我們就直接下滑到build,選擇add build step,因為是伺服器,所以直接選擇執行shell
,如果是Windows系統,也可以選擇執行Windows批處理命令
;
因jb的專案裡面有個test.py
檔案,那專案clone下來肯定是想執行這個檔案啦,因此內容就是輸入python test.py
,然後點選儲存;
回到job的首頁,點選立即構建;
因test.py
的作用是向釘釘發一條訊息,因此成功的話,釘釘就會收到一條資訊;
到這裡,說明jenkins是對接到gitlab是通的了;
觸發任務
看看標題,目的是:提tag自動打包
那先看看,tag是怎麼生成的? 具體看git命令列第11章,這裡有說明;
這裡就不bb了,直接貼:
git tag -a '3.4.0/1811111212' -m 'jbtest tag'
git push --tags
複製程式碼
- 建立一個含附註型別的標籤非常簡單,用
-a
指定標籤名字即可; -m
選項則指定了對應的標籤說明;git push --tags
就是一次推送所有本地新增的標籤;
然後再輸入git tag
檢視當前tag資訊;
既然知道tag是怎麼生成的,那就看看有沒有辦法知道tag被建立了?
第一時間當然是想到鉤子-hook啦;
來看下官方解釋:
鉤子(hooks)是一些在"$GIT-DIR/hooks"目錄的指令碼, 在被特定的事件(certain points)觸發後被呼叫。
當"git init"命令被呼叫後, 一些非常有用的示例鉤子檔案(hooks)被拷到新倉庫的hooks目錄中; 但是在預設情況下這些鉤子(hooks)是不生效的。 把這些鉤子檔案(hooks)的".sample"檔名字尾去掉就可以使它們生效了。
複製程式碼
簡單地來說有點類似回撥,就是特定事情完成後回撥執行事件。
那這鉤子,在jenkins
跟gitlab
上怎麼搞?gitlab
支援嗎?
gitlab鉤子
開啟gitlab
對應的專案,點選settings
-Integrations(整合)
開啟後,就是hook的內容啦,簡單瞄下,發現有個選項叫Tag push events
,看了下描述,好像蠻符合我們的要求,介面顯示,需要輸入URL
跟Secret Token
,這兩玩意怎麼來?
jenkins獲取URL跟Secret Token
開啟jenkins,開啟對應的job,點選設定,查詢Build when a change is pushed to GitLab
,gitlab上的URL就是該處的連結,如下圖紅框,複製過去即可;
同時點選右下的Advanced(高階)
按鈕;
然後點選右下的Generate按鈕;
然後會生成一串Secret token,複製到gitlab那;
那我們再試試,直接在伺服器打個tag且push看釘釘會不會收到資訊?
嘖嘖嘖,沒問題啊,搞定啦,另外看了下hook,支援的內容蠻多的,tag push
、push event
、merge requests
等;
gitlab沒有setting許可權
上面說的條條是道,但實際現實是殘忍的,開啟實際的專案,會發現自己沒有setting
許可權:
遇到這種情況,不是說不能處理,只能看門檻變高了,有2個方法:
嘗試跟對應的負責人溝通,看能否給一個帶master許可權的賬號;
如果有足夠的資料讓老大認可這個功能,就會給一個帶master許可權的賬號,就可以為所欲為啦;
但如果給的理由不讓人信服或者老大覺得沒鳥用,但依然要做這個功能,那隻能換種方式了,但至少要求依然有倉庫的可讀許可權
;
換個角度,連倉庫許可權都沒有,就別想做了。。
大致的思路就是,利用定時功能,不斷檢測該專案的tag,當發現原tag不是最新tag時,就認為有最新tag,此時再通知jenkins處理;
如果是這樣,那jenkins上的選項會有點不同,構建的時候就要選擇指令碼呼叫,指定TOKEN_NAME,然後可以通過連線JENKINS_URL/job/JOBNAME/build?token=TOKEN_NAME
來啟動build
;
對了,做這個功能,還有兩種形式:
- 檢測指令碼放到產品專案根目錄下;
- 檢測指令碼單獨一個專案;
第一種方式的好處時,省事,但是一般不允許,因為產品專案一般存放跟該產品相關的內容,而這個指令碼典型是通用的,後面如果多個產品想複用就麻煩了
第二種方式的就是獨立專案,可複用,把檢測專案跟產品專案放到同一臺jenkins機器上,這樣它們都在jenkins/workspace
目錄下,通過傳參的方式切換不同目錄即可;
而jb採用的是第二種方式;
檢測指令碼
這個指令碼的目的是什麼? 就是定時檢測tag是不是最新的,如果不是,則執行相應操作;
那難度就在於,怎麼判斷tag是不是最新的? Google下,有例子:
git describe --tags `git rev-list --tags --max-count=1`
複製程式碼
嘗試下,好像沒問題,那就暫且相信吧;
好奇問下,這命令到底是啥意思?
其實這是兩條git命令;
git describe --tags
git rev-list --tags --max-count=1
複製程式碼
git describe --tags 顯示當前離當前提交最近的tag,實際發現,帶不帶引數都一樣?
不加任何引數的情況下,git describe 只會列出帶有註釋的tag;
實際,該命令是可以帶3個引數的,tags
、always
、dirty
,這一般用的比較少,不展開說明;
git rev-list --tags --max-count=1
git-rev-list :按反向時間順序列出提交物件 意思就是把倒序方式展示最新提交內容;
max-count=1,也很好理解,只獲取1個,如果寫2,則獲取2個;
那命令實際就變成了這樣:
git describe 9c7246b2026cec052af6a3b6297995e494c7b398
複製程式碼
最終輸出的就是tag,有種奇淫怪招的感覺;
當然,不會用git的話,也有另外一種方式達到獲取最終一個tag的效果:
#獲取tag資訊,轉list
content = os.popen("git tag" ).read().split("\n")
for i in content:
if ( i != ''):
tag_list.append(i)
print(tag_list[-1])
複製程式碼
就是輸入git tag
,獲取所有tag資訊,再重新存在一個list,只拿最後一個,也可以再做下判斷,只儲存最後一條,方式很多,類似,但這種效果不好是,假如一個專案經過多輪迭代,有幾千條tag,就需要時間了,因此還是推薦第一種;
為了模擬真實場景,就在跟目錄下新建一個指令碼,跟專案同一根目錄;
指令碼的內容如下:
# _*_ coding:utf-8 _*_
import re
import os
import sys
import json
import time
import requests
from apscheduler.schedulers.blocking import BlockingScheduler
tag = ""
scheduler = BlockingScheduler()
base_dir = os.getcwd()
def postDingDing(content):
dingdingurl = ["https://oapi.dingtalk.com/robot/send?access_token=你的釘釘token"]
headers = {'Content-Type': 'application/json'}
String_textMsg = {
"msgtype": "markdown",
"markdown": {
"title" : "有新tag啦",
"text": "新tag: "+content
}
}
requests.packages.urllib3.disable_warnings()
String_textMsg = json.dumps(String_textMsg)
for i in dingdingurl:
requests.post(i, data=String_textMsg, headers=headers, verify=False)
def getProjectsName():
if len(sys.argv) > 1:
return sys.argv[1]
else:
print("沒有傳專案引數,請重新輸入,例子:python check_gittag.py jbtest")
def check_tag(dir):
os.chdir(base_dir+"/"+dir)
# 原型:git describe --tags 'git rev-list --tags --max-count=1'
id = os.popen("git rev-list --tags --max-count=1").read()
content = os.popen("git describe --tags "+ id).read()
return content
def start_task():
global tag
projects_name = getProjectsName()
last_tag = check_tag(projects_name)
if (tag != last_tag):
print("有新tag啦: "+last_tag)
postDingDing(last_tag)
tag = last_tag
# else:
# print("沒有新tag,繼續輪訓")
def get_time():
"""
獲取當前時間
"""
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
if __name__ == "__main__":
print(get_time() + " 魔法儀式已啟動!")
scheduler.add_job(start_task, "interval", seconds=6, id="check_tag")
scheduler.start()
複製程式碼
因為是用來測試,因此jb是做了通知釘釘的功能,執行上面的程式碼,會發現有一個問題:push了新tag,沒有通知!!!
後來想了下,哦,是沒有,因為本地的程式碼還是舊的,比如研發本地push到倉庫,但是檢測指令碼是在伺服器A,那肯定是不會知道有程式碼更新啦;
解決方案,馬上想到,那push後就通知啊,結果想起,沒鉤子許可權。。
那沒問題,在上面的指令碼加多一個更新命令就好啦;
#更新遠端程式碼到本地倉庫
git fetch origin
複製程式碼
流程通了,那怎麼對接到jenkins?
再接jenkins
看回jenkins,按照要求試試,輸入以下命令:
curl -i jenkins_url/job/job_name/build?token=yourtoken
複製程式碼
結果出現403.。。
兩種解決方案:
- 使用其他外掛代替
- jenkins全域性安全點選下圖紅框內容,jenkins首頁-系統管理-全域性安全設定;
jb選擇的是第二種方案,勾選後,再次執行上面的命令,沒問題,並且可以收到啦~
再看鉤子
其實故事到上面就完啦,但是呢,雖然知道hook怎麼用,但還是想了解更多,因此就有了這篇啦;
什麼是鉤子
Git Hooks就是在Git執行特定事件(如commit、push、receive等)後觸發執行的指令碼。
按照Git Hooks指令碼所在的位置可以分為兩類:
- 本地Hooks,觸發事件如commit、merge等;
- 服務端Hooks,觸發事件如receive等;
鉤子能做啥
基本上,用上鉤子都是定製化的指令碼程式,在實際工作中,基本鉤子是萬能的,如:
- post-receive:每當有新的提交的時候就通知專案成員;
- pre-commit:檢查每次的commit message是否符合編碼規範;
- post-merge:當merge成功後,通知專案成員;
鉤子放哪裡
$project_name/.git/hooks
複製程式碼
在.git/hooks/
資料夾下。當你init一個倉庫的時候,下邊會有一些鉤子的例子,以.sample
結尾。
當然也可以在這個目錄下自由定製hooks的功能,當觸發一些git行為的時候,就會自動觸發執行的hooks功能;
常見鉤子
本地鉤子:
名稱 | 功能 |
---|---|
pre-commit | 當執行commit 動作時先執行此hook ,可以用此hook 做一些檢查,比如程式碼風格檢查,或者先跑測試; |
prepare-commit-msg | 當commit時需要輸入message 前會觸發此hook ,可以用此hook 來定製自己的default message 資訊; |
commit-msg | 當使用者輸入commit 的message 後被觸發,可以用此hook 校驗message 的資訊,比如是否符合規定,有沒有cr等; |
post-commit | 在整個提交過程完成之後會被呼叫,可以用於傳送new commit 通知; |
post-checkout | 由git checkout 命令呼叫,可以用於為自己的專案設定合適的工作區,比如自動生成文件、移動一些大型二進位制檔案等,也可以用於檢查版本庫的有效性; |
pre-rebase | 由git rebase 命令呼叫,可以用來拒絕所有的已經push的commits進行rebase操作; |
post-merge | 由git merge 呼叫,在merge 成功後執行,可以用於merge後的訊息通知; |
post-receive | 在成功推送後被呼叫,適合用於傳送通知; |
pre-receive | 由git push 呼叫,向倉庫推送程式碼時會被執行; |
update | 在pre-receive 之後被呼叫,分別被每個推送上來的引用分別呼叫; |
pre-push | 當push時,remote refs被更新,但是在所有的objects傳輸前被觸發; |
服務端鉤子:
名稱 | 功能 |
---|---|
pre-receive | 當收到push動作之前會被執行; |
update | 收到push動作之前被執行,但是有可能被執行多次,每個branch一次; |
post-receive | 當push動作已經完成的時候會被觸發,可以用此hook來push notification等,比如發郵件,通知持續構建伺服器等; |
自定義鉤子
如果想自定義鉤子怎麼辦?
比如現在新增一個jb
鉤子,用於傳送common
通知的;
#!/usr/bin/env python
import smtplib
from email.mime.text import MIMEText
from subprocess import check_output
# 獲得新提交的git log --stat輸出
log = check_output(['git', 'log', '-1', '--stat', 'HEAD'])
# 建立一個純文字的郵件內容
msg = MIMEText("Look, I'm actually doing some work:\n\n%s" % log)
msg['Subject'] = 'Git post-commit hook notification'
msg['From'] = 'mary@example.com'
msg['To'] = 'boss@example.com'
# 傳送資訊
SMTP_SERVER = 'smtp.example.com'
SMTP_PORT = 587
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo()
session.login(msg['From'], 'secretPassword')
session.sendmail(msg['From'], msg['To'], msg.as_string())
session.quit()
複製程式碼
當然,記得給許可權給你鉤子,chmod
;
小結
好啦,本章就到此接觸啦,基礎內容有點,但是不多,都是環境配置,本章主要講述以下內容:
- 搭建jenkins
- git配置
- jenkins打通git
- gitlab hook
- 檢測指令碼
- jenkins通過url觸發任務
- git tag命令部分講解
大致是這樣,還有些細節,差不多就的啦;
好啦,如果有什麼疑問,歡迎一起溝通;
最後,謝謝大家~