背景
在測試環(huán)境部署這塊,經(jīng)歷過以下幾個階段:
-
階段一
有一臺測試服務(wù)器把項(xiàng)目放上面測試,當(dāng)初也沒有什么相關(guān)的經(jīng)驗(yàn)脸爱,每次改完代碼本地打包上傳到服務(wù)器上辩昆,然后一頓命令啟動項(xiàng)目搜骡,完成了最原始的部署。
這種方式構(gòu)建和部署全靠人肉,項(xiàng)目簡單的時候還好說,項(xiàng)目一多配置一多( 比如微服務(wù) )中間哪個環(huán)節(jié)粗心出點(diǎn)錯那簡直就是災(zāi)難划乖。
同時還要專門有人對運(yùn)維相關(guān)的技術(shù)比較了解,不然我不在的時候測試工作就完全停滯了挤土。
-
階段二
既然都是重復(fù)工作琴庵,那就整理下步驟寫個腳本:
從 SVN/Git 拉代碼
Maven 構(gòu)建打包
重啟 Tomcat
每次執(zhí)行下腳本就搞定了⊙雒溃看著挺不錯的迷殿,不過實(shí)際執(zhí)行時的情況總會復(fù)雜許多( 服務(wù)器賬號權(quán)限、測試人員對 Linux 的熟悉程度筒占、項(xiàng)目啟動依賴復(fù)雜等等問題 )贪庙。
-
階段三
了解到 Jenkins 是個不錯的工具,那就把腳本的內(nèi)容遷移到 Jenkins 上翰苫,不管是開發(fā)還是測試只要在 web 界面上點(diǎn)擊一下按鈕即可完成構(gòu)建部署,很 easy 这橙。
-
階段四
容器化:使用 Docker 來部署項(xiàng)目奏窑,這樣就可以干掉原來服務(wù)器上散落各地參差不齊的 Tomcat ( 不同項(xiàng)目依賴不同 ),利用 Docker Compose 對項(xiàng)目進(jìn)行編排屈扎,提供一種規(guī)范的構(gòu)建配置( 同時也是一份文檔 )埃唯,大大減小了后期維護(hù)和交接的成本。
-
階段五
上面的階段已經(jīng)能解決日常需求了鹰晨,但是還有一點(diǎn)問題就是每次提交完代碼還要手動去 Jenkins 上發(fā)布墨叛,能更自動點(diǎn)就更好了( 嗯止毕,就是懶 )。
于是就引出了本文的目標(biāo) —— 自動持續(xù)構(gòu)建漠趁,不需要人工操作 ( 留人工操作用于處理特殊情況 )扁凛。
方案流程
開發(fā)提交代碼。
開發(fā)對需要發(fā)布的版本打上 Tag 闯传。
觸發(fā) GitLab 的 tag push 事件谨朝,調(diào)用 Webhook 。
Webhook 觸發(fā) Jenkins 的構(gòu)建任務(wù)甥绿。
Jenkins 構(gòu)建完項(xiàng)目可以按版本號上傳到倉庫字币、部署、通知相關(guān)人員等等共缕。
安裝 GitLab
GitLab 官方文檔 已經(jīng)介紹的比較詳細(xì)了洗出,這里不再贅述,下面給出最終調(diào)整過的 Docker Compose 配置( 參考 ):
gitlab:
image: "twang2218/gitlab-ce-zh:11.0.2"
restart: always
hostname: 'gitlab'
ports:
- "10022:10022"
- "10086:10086"
# postgresql 端口
- "5432:5432"
volumes:
- ./gitlab/data:/var/opt/gitlab
- ./gitlab/log:/var/log/gitlab
- ./gitlab/config:/etc/gitlab
environment:
GITLAB_OMNIBUS_CONFIG: |
# 倉庫路徑图谷,填寫宿主機(jī)的域名或 IP
external_url 'http://192.168.xxx.xxx:10086'
# ssh 連接端口
gitlab_rails['gitlab_shell_ssh_port'] = 10022
# 調(diào)整工作進(jìn)程數(shù)減小內(nèi)存占用翩活,最小為 2
unicorn['worker_processes'] = 2
# 設(shè)置時區(qū)
gitlab_rails['time_zone'] = 'Asia/Shanghai'
# 郵箱配置
gitlab_rails['gitlab_email_from'] = '<your_email>'
gitlab_rails['gitlab_email_display_name'] = '<your_email_name>'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = 'smtp.163.com'
gitlab_rails['smtp_port'] = 25
gitlab_rails['smtp_user_name'] = "<your_email_account>"
gitlab_rails['smtp_password'] = "<your_email_password>"
gitlab_rails['smtp_domain'] = 'smtp.163.com'
gitlab_rails['smtp_tls'] = false
gitlab_rails['smtp_openssl_verify_mode'] = 'none'
gitlab_rails['smtp_enable_starttls_auto'] = false
gitlab_rails['smtp_ssl'] = false
gitlab_rails['smtp_force_ssl'] = false
# 數(shù)據(jù)庫配置
gitlab_rails['db_host'] = '127.0.0.1'
gitlab_rails['db_port'] = 5432
gitlab_rails['db_username'] = "gitlab"
gitlab_rails['db_password'] = "gitlab"
postgresql['listen_address'] = '0.0.0.0'
postgresql['port'] = 5432
postgresql['md5_auth_cidr_addresses'] = %w()
postgresql['trust_auth_cidr_addresses'] = %w(0.0.0.0/0)
postgresql['sql_user'] = "gitlab"
postgresql['sql_user_password'] = Digest::MD5.hexdigest "gitlab" << postgresql['sql_user']
# 備份設(shè)置-保留7天
gitlab_rails['backup_keep_time'] = 604800
GITLAB_BACKUPS: "daily"
GITLAB_SIGNUP: "true"
GITLAB_ROOT_PASSWORD: "lb80h&85"
GITLAB_GRAVATAR_ENABLED: "true"
說明:
這里使用 漢化版 鏡像,如果不適應(yīng)可以換回 官方原版 鏡像
gitlab/gitlab-ce:11.0.2-ce.0
蜓萄。項(xiàng)目初始配置 + 啟動很慢隅茎,需要一段時間,日志中出現(xiàn) Reconfigured 時表示啟動成功嫉沽。
192.168.xxx.xxx 替換為宿主機(jī)的 IP 地址辟犀。
初始管理員賬號密碼:
root
/lb80h&85
( 自行修改配置文件中的密碼 )。該配置為 乞丐版 绸硕,內(nèi)存占用 2G+ ( worker_processes 越多內(nèi)存占用越大堂竟,默認(rèn)為 8G )。
postgresql 為容器中內(nèi)置的數(shù)據(jù)庫( 賬號密碼:
gitlab
/gitlab
)玻佩,非必要情況就不要暴露端口了出嘹。郵箱填寫用于 發(fā)送找回密碼和通知 的發(fā)件人賬號( 收不到郵件? )咬崔,不想配郵箱可以刪掉相關(guān)配置税稼,不影響正常使用( 注冊賬號時郵箱可以隨便填 )。
-
如果指定了
external_url
垮斯,那么其中的端口號就是用于 NGINX 監(jiān)聽的端口號( 如果nginx['listen_port']
沒有顯式配置 )郎仆,所以上面配置中的端口映射是10086:10086
而非10086:80
。( 參考 ) 由于安全問題兜蠕,新版本瀏覽器禁用了
10080
端口的訪問扰肌,可以換成其他端口。( 參考 )
安裝 Jenkins
為了測試方便熊杨,本文中使用 Docker 化的 Jenkins 曙旭,如果需要調(diào)用一些特殊的命令或腳本就不是很方便盗舰,實(shí)際使用過程中可以換成普通版的。
Docker Compose 配置如下:
version: '3'
services:
jenkins:
image: jenkins/jenkins:2.456
container_name: jenkins
networks:
- net
user: "root"
restart: always
ports:
- 9000:8080
environment:
- JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
volumes:
- /etc/localtime:/etc/localtime:ro
- ./data:/var/jenkins_home:rw
- ./backup:/var/jenkins_backup:rw
# 網(wǎng)絡(luò)配置
networks:
net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.23.0.0/16
說明:
-
初次啟動請打印日志桂躏,日志中有管理員賬號的初始密碼钻趋,第一次登錄的時候需要用到。
Jenkins initial setup is required. An admin user has been created and a password generated. Please use the following password to proceed to installation: db7bb60324dc4331bc0dd3e79cc499a5 This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
為了方便沼头,使用了 root 賬號啟動 Docker 容器爷绘,如果使用默認(rèn)賬號啟動還需要修改本地目錄( data、backup )的讀寫權(quán)限进倍。
初始化過程中有些插件可能搜不到土至,可以在賬號初始化結(jié)束后再進(jìn)入設(shè)置頁面安裝插件。
配置 GitLab
注冊賬號什么的就不贅述了猾昆,建一個測試項(xiàng)目 test 陶因,隨便 commit 幾條內(nèi)容。
按下圖步驟創(chuàng)建賬號的 access token 垂蜗,用于 Jenkins 調(diào)用 GitLab 的 API 楷扬。
記下這里生成的 access token ( gRCtwVWU8cxwHdxxVZJD
),后面要用到贴见。
配置 Jenkins
-
安裝插件
安裝過程可能會失敗烘苹,多試幾次就好了,可以嘗試更新 Jenkins 片部。
插件 說明 Git Parameter 用于參數(shù)化構(gòu)建中動態(tài)獲取項(xiàng)目分支镣衡。 Generic Webhook Trigger 用于解析 Webhook 傳過來的參數(shù)。 GitLab 用于推送構(gòu)建結(jié)果給 GitLab 档悠。 -
添加 GitLab 憑據(jù)
憑據(jù) -> 系統(tǒng) -> 全局憑據(jù) -> 添加憑據(jù)廊鸥,把上面 GitLab 中生成的 access token 填進(jìn)去。
-
配置 GitLab 連接
系統(tǒng)管理 -> 系統(tǒng)設(shè)置 -> GitLab 配置項(xiàng)辖所,填入 GitLab 相關(guān)的配置惰说,后面配置項(xiàng)目時用到。
-
新建項(xiàng)目 test
新建一個 Job ( 構(gòu)建一個多配置項(xiàng)目 )缘回,大部分配置可以按上圖照抄:
勾選 參數(shù)化構(gòu)建過程吆视,添加 Git Parameter 類型的參數(shù) ref ,這樣手動點(diǎn)擊構(gòu)建按鈕(
Build with Parameters
)的時候就可以指定分支進(jìn)行構(gòu)建酥宴。Source Code Management 選擇 Git 揩环,添加項(xiàng)目地址和授權(quán)方式( 賬號密碼 或者 ssh key ,不能選 GitLab API token )幅虑,分支填寫構(gòu)建參數(shù) $ref 。
-
Build Triggers 選擇 Generic Webhook Trigger 方式用于解析 GitLab 推過來的詳細(xì)參數(shù)顾犹,其中 Token 用 GUID / UUID 生成一個倒庵。
用法說明: 在 GitLab 的 Webhook 編輯頁面中點(diǎn)擊 View details 查看調(diào)用詳情褒墨,其中 Request body 就是傳遞給 Jenkins 的參數(shù),利用 JSONPath 語法( 在線測試 )將這個大的 JSON 解析為一個個小的自定義參數(shù)用于后面的構(gòu)建流程擎宝。
其他觸發(fā)方式中: Trigger builds remotely 是 Jenkins 自帶的郁妈, Build when a change is pushed to GitLab 是 GitLab 插件 提供的,都屬于簡單的觸發(fā)構(gòu)建绍申,無法做復(fù)雜的處理噩咪。
雖然 Generic Webhook Trigger 提供了 Token 參數(shù)進(jìn)行鑒權(quán),但為了避免不同項(xiàng)目進(jìn)行混調(diào)( 比如 A 項(xiàng)目提交代碼卻觸發(fā)了 B 項(xiàng)目的構(gòu)建 )极阅,還要對請求做下過濾胃碾。 Optional filter 中 Text 填寫需要校驗(yàn)的內(nèi)容( 可使用變量 ), Expression 使用正則表達(dá)式對 Text 進(jìn)行匹配筋搏,匹配成功才允許觸發(fā)構(gòu)建仆百。
Build 內(nèi)容按自己實(shí)際的項(xiàng)目類型進(jìn)行調(diào)整,使用 Maven 插件 或 腳本 等等奔脐。
GitLab Connection 選擇上面添加的 GitLab 連接(
Jenkins
) 俄周, Post-build Actions 添加Publish build status to GitLab
動作,實(shí)現(xiàn)構(gòu)建結(jié)束后反饋構(gòu)建結(jié)果給 GitLab 髓迎。
-
回到 GitLab 的項(xiàng)目頁面中峦朗,添加一個 Webhook :
http://JENKINS_URL/generic-webhook-trigger/invoke?token=<上面 Jenkins 項(xiàng)目配置中的 token>
觸發(fā)器選擇 標(biāo)簽推送事件 。因?yàn)槿粘i_發(fā)中 push 操作比較頻繁而且不是每個版本都需要構(gòu)建排龄,所以只針對需要構(gòu)建的版本打上 Tag 就好了波势。
創(chuàng)建完使用 test 按鈕 先測試下,可能會出現(xiàn)下面的錯誤:
Hook execution failed: URL 'http://192.168.xxx.xxx:9000/generic-webhook-trigger/invoke?token=d63ad84eb18cb04d4459ec347a196dce' is blocked: Requests to the local network are not allowed
測試效果
可以在 GitLab 上直接添加 Tag 艰亮,不過我覺得用 IDEA 操作更方便點(diǎn),就把代碼拉下來在本地操作挣郭。
使用快捷鍵 Ctrl + Shift + K
調(diào)出 Push 窗口 迄埃,把 Tag 推送到 GitLab 中。
回到 GitLab 頁面可以看到觸發(fā)了 Webhook 兑障, View details 查看請求詳情侄非, Response body 中 triggered
字段值為 true
則表示成功觸發(fā)了 Jenkins 的構(gòu)建。
如果 triggered
字段值為 false
很可能是 Optional filter 中實(shí)際的 Text 值和正則表達(dá)式 Expression 不匹配( 見 Response body 中 regexpFilterText
和 regexpFilterExpression
的具體值 )流译,比如刪除 Tag 的時候沒有 commitsId 就不會匹配上逞怨。
再看下構(gòu)建結(jié)果:
見上面的
Publish build status to GitLab
。
注意: 每添加一個 Tag 就會觸發(fā)一次事件福澡,不管是不是一起 push 的叠赦。所以一次 push 多個 Tag 會觸發(fā) Jenkins 進(jìn)行多次構(gòu)建。不過 Jenkins 已經(jīng)做了處理革砸,默認(rèn)串行執(zhí)行任務(wù)( 一個任務(wù)結(jié)束后再執(zhí)行下一個 )除秀,而且在構(gòu)建前有一個 pending 狀態(tài)糯累,此時被多次觸發(fā)會進(jìn)行合并,并取首次觸發(fā)的參數(shù)册踩,如下圖所示:
測試發(fā)現(xiàn)新版 Jenkins 似乎不再合并構(gòu)建了泳姐。
關(guān)于 Tag 的幾點(diǎn)說明
推送 Tag 到遠(yuǎn)端的時候,遠(yuǎn)端已存在( 同名 )的 Tag 不會被添加到遠(yuǎn)端暂吉。
拉取遠(yuǎn)端的 Tag 時胖秒,本地已存在( 同名 )的 Tag 不會添加到本地。
拉取遠(yuǎn)端的 Tag 時慕的,本地不會刪除遠(yuǎn)端已刪除的 Tag 阎肝,需要同步遠(yuǎn)端的 Tag 可以先刪除本地所有 Tag 再進(jìn)行 pull 。
刪除 Tag 也會推送事件业稼,要做好過濾( 上面配置中已使用 commitsId 字段進(jìn)行過濾 )盗痒。
后續(xù)
通過上面的步驟已經(jīng)初步實(shí)現(xiàn)了想要的效果,還有幾個點(diǎn)后續(xù)可以再考慮下:
上文只包含自動構(gòu)建的內(nèi)容低散,對于項(xiàng)目的部署可以考慮幾種方式:手動選擇指定的版本進(jìn)行發(fā)布俯邓、構(gòu)建任務(wù)結(jié)束后直接觸發(fā)部署任務(wù)、定時部署最新版本( 根據(jù)實(shí)際需求調(diào)整 )熔号。
測試發(fā)版的頻率會比較高稽鞭,會生成大量的 Tag ,可以約定 Tag 的格式引镊,比如用
test 0.0.1
表示觸發(fā)測試環(huán)境的項(xiàng)目構(gòu)建朦蕴,用online 1.0.0
表示觸發(fā)正式版本構(gòu)建,隔離之后可以方便后續(xù)的維護(hù)和清理弟头。構(gòu)建部分可以整合 Docker 吩抓,把構(gòu)建結(jié)果打包到 Docker 鏡像中( 代碼版本庫的 Tag 正好可以作為鏡像的 Tag ),再上傳到 Docker 鏡像倉庫( 私服 或者第三方倉庫 )中赴恨,后續(xù)部署就可以直接從鏡像倉庫拉取鏡像直接運(yùn)行了疹娶。
集成自動化測試 ,比如 這個 伦连。
嘗試配置 GitLab 自帶的 CI / CD 雨饺。
相關(guān)
總結(jié)
以上就是對曾經(jīng)踩過的一些坑進(jìn)行的整合,也沒什么好總結(jié)的惑淳《罡郏總之,合理地利用現(xiàn)有工具來解放雙手歧焦,就能有更多時間做其他想做的事移斩!
時間有限一些基礎(chǔ)的步驟就不細(xì)講直接一筆帶過了,方案上可能有些細(xì)節(jié)方面也沒考慮全,歡迎評論留言叹哭。