使用 Jenkins 設定 GitHub 觸發程序並通知 Telegram Bot
此文章是接續前面 Jenkins 及 Ansible IT 自動化 CI/CD 介紹 文章,此篇會實際安裝及實作 Jenkins,大家記得在學習前要先檢查自己的版本是否有新的更新!那我們開始囉 😘
Jenkins 安裝與實作
我這次會使用 Docker-compose 來進行安裝,除了 Docker 以外也有不同的安裝方式,可以參考 Jenkins download and deployment,本次使用的環境版本如下:
版本
- macOS:11.6
- Docker:Docker version 20.10.14, build a224086
- Jenkins:jenkins/jenkins:lts-jdk11
- yamllint:1.26.0
安裝
這邊會使用 Jenkins 提供的 官方 LTS 映像檔 來作為基底,因為我們要多安裝測試程式 yamllint,所以就自己寫一個 Docker-compose:(同樣的程式碼會放在 GitHub,也直接包成映像檔放在 DockerHub,歡迎大家自行取用)
yamlint,它是語法檢查工具,可以用來檢查 yaml 檔案的語法是否正確以及符合規範,我們看一下實際操作的畫面:
yamllint 測試
接下來先看一下整個 Docker-compose 結構以及各參數:
.
├── Docker-compose.yaml
├── jenkins
│ └── DockerfileDocker-compose.yaml
version: "3.8"
services:
jenkins:
build: ./jenkins/
container_name: jenkins
ports:
- 8080:8080
- 50000:50000
restart: always
volumes:
- ./jenkins_home:/var/jenkins_home參數說明:
build: ./jenkins/:因為要先安裝 yamllint,所以使用 Dockerfile 另外寫。container_name:jenkins:容器的名稱。ports: -8080:8080 - 50000:50000:8080 是待會我們瀏覽儀表板會使用到的 Port,如果本機上 8080 已經被佔用,可以自行更換,50000 是 Jenkins 所使用的 Port。restart: always:當容器停止時,會自動重新啟動容器。volumes: - ./jenkins_home:/var/jenkins_home:掛載目錄,就算刪除容器一樣可以保留其他設定。我將啟動Docker-compose.yaml的資料夾下多一個 jenkins_home 與容器內 /var/jenkins_home 做映射,大家可以自己去調整。
jenkins/Dockerfile
FROM jenkins/jenkins:lts-jdk11
LABEL maintainer="[email protected]"
USER root
RUN apt-get upgrade -y\
&& apt-get update -y\
&& apt-get install yamllint -y參數說明:
FROM:我們使用 Jenkins 官方提供的 LTS 維護版本。USER:因為要先安裝東西,所以直接給 root 權限。RUN:先升級完後,再更新,最後再裝 yamllint。(-y 是同意所以詢問)
最後使用 docker-compose 來執行:
$ docker-compose up -d要在 Docker-compose.yaml 資料夾下指令才有用。
下完指令後,他就會在背景開始安裝,可以試著用瀏覽器瀏覽 http://localhost:8080,查看有沒有跳出下面這個畫面:

瀏覽器訪問 http://localhost:8080
我們看到它需要輸入一組 Administrator password,我們要使用 docker logs 來查看,會發現最後會有寫 Please use the following password to proceed to installation 的地方:
$ docker logs jenkins
*************************************************************
*************************************************************
*************************************************************
Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password to proceed to installation:
70c0780f62a7441f90286be106908378
This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
*************************************************************
*************************************************************
*************************************************************其中的 70c0780f62a7441f90286be106908378 ,就是我們的 Administrator password,直接複製並貼到欄位後按 Continue。
我們可以看到它詢問是否要安裝套件,我們選擇左邊 Install suggested plugins 安裝推薦的套件即可:

安裝推薦的套件
等待它安裝套件,安裝完後會自動跳到註冊畫面:

等待安裝…
輸入完基本的資料後,按 Save and Continue:

創建 Admin 使用者
最後看到下面這個畫面就代表我們安裝好囉!

Jenkins 儀表板
建立第一個 Jenkins Job
我們已經成功安裝好並進入到 Jenkins 儀表板,我們先來建立第一個 Job,它的功用是告訴我們系統檔案的即時使用狀況,讓我們對 Jenkins 有初步的了解:
- 點選儀表板的新增作業或是 Create a Job:

新增作業
- 輸入 Job 專案名稱並選擇建立 Free-Style 軟體專案:

設定 Job 專案
可以看到這邊有不同的專案類型可以選擇,Free-Style 以及 Pipeline 這兩種類型的專案基本上就涵蓋大部分的需求。Free-Style 類型的專案提供了非常大的彈性讓使用者來做原始碼管理以及建置。如果建置流程涉及多個專案,則可以使用 Pipeline 類型的專案來組合及定義建置邏輯。
- 接下來設定專案組態:

設定專案組態
要記得幫每一個專案都加上描述,讓其他人知道該專案的用途或是使用時機等。
接著,在建置的下拉式欄位選擇 選擇建置步驟 > 執行 Shell

設定專案組態
輸入 df -h 指令:

設定專案組態
我們這邊透過建置 執行 Shell 這個建置步驟來告訴 Jenkins,未來這個專案被建置,就會執行 df -h 這個指令。
- 專案組態設置完後,我們點選左邊的馬上建置來建置剛剛建好的專案,如果我們設定上沒有問題,應該會在左下角的建置歷程這邊看到我們的第一個建置紀錄:

建置專案
- 點進去後,再點 Console Output,可以看到這次建置的結果:

建置專案
這樣我們的第一個 Jenkins Job 就設定完成囉!Jenkins 也確實的執行我們所設定的指令,並將系統的使用狀況呈現在終端機的輸出上。
以上就是我們第一個簡單的專案建置流程,當然,Jenkins 可以做到的事情不僅如此,在後面我們會透過安裝不同的套件來強化 Jenkins,來達到完整的持續整合 😁
原始碼管理與建置觸發程序
上面有提到 Jenkins 作為一個持續整合的工具,與原始碼管理系統的整合尤其重要。我們這一章節,會介紹如何在 Jenkins 上透過原始碼管理 (source code management,SCM) 系統,例如從 GitHub 獲得專案的原始碼,並設置建置觸發程序 (build triggers) 來實踐持續整合。
建置專案
HTTPS
接下來我們先建立一個新的 Job,選擇 Free-style 模式,這次要在原始碼管理裡面選擇 Git,在 Repositories > Repository URL 裡面輸入我們這次要測試的 repository URL:

設定 Repository URL
SSH
如果我們想要透過 SSH 來存取專案,我們會遇到以下狀況:

SSH 尚未設定錯誤訊息
會有錯誤訊息是因為我們還沒有把 Jenkins 與 GitHub 做 SSH 金鑰配對,所以 GitHub 拒絕 Jenkins 透過 SSH 存取。那要怎麼解決呢?
最簡單的方法就是在 Jenkins 主機下建立 SSH 金鑰,並將公開金鑰 Key 加入到 GitHub 帳號中,有需要的朋友可以再自行使用,該範例使用 HTTPS 來做設定。
建置觸發程序
由於我們還沒有定義任何建置的觸發程序,所以除非我們手動去操作 Jenkins,不然 Jenkins 並不會主動幫我們進行建置。因此,在建置觸發程序這個欄位內,我們可以自由設定我們希望 Jenkins 何時自動幫我們進行建置專案。那依照專案的屬性不同,我們也可以採用不同的建置時機。那最常見的有以下兩種:
定期建置
在 Jenkins 中,我們是採用 Cron Format 的方式來定義建置行程。Cron Format 總共五個欄位,欄位與欄位之間可用空白或 Tab 鍵做區隔:
- 分 (minute):0 - 59 分
- 時 (hour):0 - 23 時
- 日 (day of month):1 - 31 日
- 月 (month):1 - 12 月
- 星期 (day of week):星期 0 - 7 (其中 0 與 7 都代表星期天)
假設我們希望每個 30 分鐘就建置一次當前專案,我們可以在定義規則裡面填入 H/15 * * * *:

定期建置
GitHub hook trigger for GITScm polling
這種觸發方式在持續整合時非常實用。我們可以讓 Jenkins 自動監測當在原始碼專案有任何的 push event 發生時就進行建置。為了要使用這種方式建置,需要以下幾個步驟來設定:
新增 GitHub personal access token
- 進入 GitHub 首頁,點選右上角下拉選單,點選 Settings:

GitHub hook trigger for GITScm polling 設定
- 先點選左邊的 Developer settings > 點選左邊的 Personal access tokens > 點選右上角的 Generate new token,輸入 token 的描述並勾選
reposcope 以及admin:repo_hookscope 跟admin:org_hookscope,點選 Generate token:

GitHub hook trigger for GITScm polling 設定
- 會產生一個 token,請先把 token 複製下來,離開這個畫面後,token 就會看不到了!(此 token 已刪除 ✌️)

GitHub hook trigger for GITScm polling 設定
設定 Jenkins GitHub
- 進入 Jenkins 儀表板頁面,點選左邊管理 Jenkins > System Configuration 的設定系統,往下滑找到 GitHub:

GitHub hook trigger for GITScm polling 設定
- 找到後,再 GitHub Servers 下拉欄位選擇 Add GitHub Server,會看到下面畫面,API URL 輸入
https://api.github.com,Credentials 點 Add:

GitHub hook trigger for GITScm polling 設定
- Kind 選擇 Secret Text,Secret 輸入剛剛存的 Personal Access Token,Description 簡單描述一下:

GitHub hook trigger for GITScm polling 設定
- 設定完後,點選一下右邊的 Test connection,如果我顯示
Credentials verified for user UserName, rate limit: xxx就代表成功囉!

GitHub hook trigger for GITScm polling 設定
設定專案組態
- 接著我們跳回來剛剛的專案組態,並勾選 GitHub hook trigger for GITScm polling:

設定專案組態
- 寫一個 Shell Script 來建置專案:
for file in $(find . -type f -name "*yaml")
do
yamllint $file
done
設定專案組態
這邊利用一個簡單的 Shell Script 迴圈來對所有 YAML file 進行 yamllint 的檢查,最後點選儲存離開。
GitHub 上整合 Jenkins
先到 GitHub 被建置專案的頁面下點 Setting 標籤 > 點選左邊的 Webhook > 點選右上角的 Add webhook > 輸入 Jenkins Hook URL 到 Payload URL:
記得 Jenkins Hook URL 後面要加
/github-webhook/,小弟我卡在這裡很久 😢 😢

Webhooks 設定
- Jenkins Hook URL 設定"
由於我們是將 Jenkins 運行在本機端,所以 Jenkins Hook URL http://localhost:8080 是 Private IP。GitHub 沒有辦法抓 Private IP,為了練習,我們可以透過 ngrok 這套簡單小工具來暫時將 http://localhost:8080 變成 Public IP。
ngrok 的使用方式很簡單,只要先下載 brew install ngrok/ngrok/ngrok ,並使用 ngrok http 8080 指令,將 Private IP 變成 Public IP:

ngrok 將 Private IP 變成 Public IP
圖片中 https://2063-111-235-135-57.jp.ngrok.io 就是 Public 的 Jenkins Hook URL
完成後,先點選 Recent Deliveries 檢查是否成功,底下的 Response 需要是 200,才是對的歐!(這裡一定要先檢查,不然後面會找問題到死 XD)

Webhooks 設定
測試
我們都設定好後,要開始來測試,我們可以直接先點選 馬上建置,來測試是否可以透過 GitHub personal access token,抓取 GitHub 的檔案。

馬上建置
可以看到在建置流程那邊發現建置失敗,點進去可以看詳細內容,

建置失敗
點選左側的 Console Output,可以看到我們有成功獲取 GitHub 上得專案,並且執行我們的 Shell 來檢查 yaml 的檔案格式,發現是因為格式有錯誤,所以建置才會失敗 ❌

Console Output
接下來我們先修改一下 yaml 的檔案,後重新 push 到 Github 上,並觀察 Jenkins 會不會自動建置 !(修改位置大家可以直接看 Commit 結果)

Console Output
當你 push 完後,發現它會自動建置,請因為我們修改成正確格式,所以他也建置成功囉!
也可以點選左側有一個新的 GitHub Hook Log ,可以看到我們成功透過 GitHub hook trigger for GITScm polling 偵測到有新的 event,透過 WebHook 讓 Jenkins 知道。

GitHub Hook Log
建置後觸發通知
當我們自動建置成功當然沒什麼問題,但如果失敗有可能就會影響後續程式的上線時間,所以我們希望建置完成後,可以收到通知,通知除了可以用 email 以外,也可以使用套件去串接我們常用的平台,例如 Telegram、Slack、Line 等等,接下來我會教大家要怎麼去串接這些服務,在開始之前要請大家先安裝兩個套件:
安裝/設定 Build Timestamp
Build Timestamp 這個套件可以幫我們在稍後傳送通知時加上當下的時間戳,那要怎麼安裝套件呢?先到儀表板首頁,點選左側的 管理 Jenkins > 點選 管理外掛程式:

管理 Jenkins > 管理外掛程式
再 Plugin Manager 的 可用的裡面搜尋 Build Timestamp,選擇後點下方的 Download now and install after restart,等待他安裝後會自動重啟。

安裝 Build Timestamp
重啟後從儀表板點選左側 管理 Jenkins > 點選 設定系統,找到 Build Timestamp,開啟設定,並設定 Timezone 為 Asia/Taipei 以及 pattern yyyy-MM-dd HH:mm:ss z,這樣我們待會就可以使用 BUILD_TIMESTAMP 參數來獲取當下時間,記得要按下儲存歐!

設定 Build Timestamp
安裝/設定 Notify.Events
Notify.Events 這個套件可以串接很多的平台,例如 Telegram、Slack、Line 等,也可以透過它寄發郵件,是一個十分方便的套件,但缺點是他需要註冊,免費版只有每個月 300 次的訊息傳輸量,但在我們測試階段已經十分夠用。一樣我們用剛剛的方法安裝 Notify.Events。

安裝 Notify.Events
安裝好後,Notify.Events 他不需要先設定,它可以依據不同的 Job 有不同的設定,所以我們開啟剛剛的 Job 組態,拉到最下面找到 建置後動作 ,選擇 Notify.Events:

安裝 Notify.Events
可以看到這邊要先輸入 Token,那 Token 就必須去官網註冊後設定。
我們先開啟瀏覽器,搜尋 Notify.Events,註冊帳號後,在 Channels 點選 Create,輸入一下 Title 按下 Save。

Notify.Events 官網設定
完成後,應該可以看到以下畫面,這邊就可以讓我們選擇來源,以及要發送到哪裡:

Notify.Events 官網設定
我們先選擇 Sources,點選 Add source,可以看到很多來源,選擇 CI/CD and Version control ,再選擇 Jenkins:

Notify.Events 官網設定
點選 Next,就可以看到以下畫面,它告訴我們要將它提供的 Token 貼入設定檔,也就是我們剛剛在 Job 組態裡面的那個 Token:

Notify.Events 官網設定
設定好 Sources,接下來要設定接收方,回到剛剛 Notify.Events 的儀表板,點選 Subscribe,我們測試使用 Telegram 來當接收方,它會跳出一個視窗,告訴你要怎麼把他的機器人加成好友或是加入群組,這邊就依大家需要自行選擇,那我就將它加入群組,使用 /subscribe DRr0bIZ0 @NotifyEventsBot 指令來綁定

Notify.Events 官網設定
這時候我們都設定好了,我們回到 Job 組態的 Notify.Events 設定位置,將 Token 貼上去,它可以自訂訊息的模板,可以全部都一樣,也可以針對建置後的狀態,產生不同的訊息模板,我們來自定義設計一下:
Success
📢 Jenkins 建置通知 📣
時間:$BUILD_TIMESTAMP 🕐
名稱: <a href="$PROJECT_URL">$PROJECT_NAME</a>
次數: <a href="$BUILD_URL">#$BUILD_NUMBER</a>
建置狀態: 🟢 <b>$BUILD_STATUS</b> 🟢
<a href="$BUILD_URL/console">建置日誌連結</a>
--------- 😍😍😍 ---------
Notify.Events Success
Failure
📢 Jenkins 建置通知 📣
時間:$BUILD_TIMESTAMP 🕐
名稱: <a href="$PROJECT_URL">$PROJECT_NAME</a>
次數: <a href="$BUILD_URL">#$BUILD_NUMBER</a>
建置狀態: 🔴 <b>$BUILD_STATUS</b> 🔴
<a href="$BUILD_URL/console">建置日誌連結</a>
--------- 😭😭😭 ---------
Notify.Events Failure
Telegram 通知測試
最後我們都設定好了,就來測試一下吧!我們先故意將程式碼格式用錯,讓他先跳出錯誤,再修改,來看看結果如何吧!(文字連結是對應的 Commit )

Telegram 通知
可以看到,我們分別兩次的測試,會依據我們建置後的結果,觸發不同的通知模板。