1. 程式人生 > >使用Jenkins + git submodule 實現自動化編譯,解決程式碼安全性問題

使用Jenkins + git submodule 實現自動化編譯,解決程式碼安全性問題


道哥的第 030 篇原創

[TOC] ## 一、一個真實的程式碼洩漏故事 事情發生在功能機的時代,我們專案組開發一款手機,軟體開發成員大概有 20 人左右吧。結果在手機發布的一週後,另一家小廠就推出了軟體介面、功能幾乎完全一樣的手機,除了開機介面。 因為那個時代,大家幾乎都是使用 MTK、高通提供的解決方案,都是統一的選單式功能,你沒法拿出有力的證據來說明別人偷竊了你的程式碼。 後來內部查明,的確是有開發人員把程式碼洩漏出去了,於是後來所有的電腦上 USB 口全部被禁掉了。 這是我親身經歷的真實故事,當時每個人負責一個模組,比如:A 負責通話管理和電話簿,B 負責系統設定,C 負責簡訊和彩信。。。在編譯的時候,是需要所有的程式碼放在一起,統一編譯的,這也就意味著所有的軟體人員都可以拿到全部原始碼,這也就為程式碼洩漏埋下了隱患,出現了這次嚴重的事件,畢竟人為財死、鳥為食亡! 那麼,是否有一些程式碼管控方式,來解決這個許可權問題呢? 現在專案中,都強調要分層、分模組,這是從軟體工程的角度來考慮的。如果再進一步, 把這些模組都劃分為一個小的子系統,每個開發人員只負責自己的模組,並且只能有許可權拉取自己的程式碼,這樣他就沒法獲取到一個專案中所有模組的程式碼了。 只有專案整合人員(管理員),才有全部許可權來拉取所有原始碼來構建整個系統,這樣的話,就可以對程式碼的安全問題有更好的掌控了。 要實現這樣的程式碼管控,使用 git 工具中的 submodule 就可以完成,這篇文章,我們就來詳細的講解一下 git submodule 的使用。 這篇文章是工具型的,可能比較長,為了提供一站式服務,我會把相關的資源、步驟、遇到的錯誤資訊等細節都記錄下來,方便以後查閱。 不論如何,經過這篇文章,你可以學習、瞭解下面這幾個方面的知識點: > 1. Jenkins 的基本使用方法; > 2. git submodule 的基本指令用法; > 3. 通過三個 demo 專案,一步一步操作實現程式碼的安全管控; > 4. 利用 Jenkins + git submodule 來實現自動化編譯; > 5. git subtree 與 submodule 的區別; 如果您需要文中提到的軟體和程式碼資源,在文章末尾可以找到下載方式。 ## 二、Jenkins 的基本使用 #### 1. Jenkins 是什麼? Jenkins是一個開源、由 Java 編寫的持續整合工具,也就是說它幫助我們自動構建各類專案。Jenkins 執行在 Servlet 容器中(例如 Apache Tomcat),在 Ubuntu 系統中使用 apt-get 就可以一鍵安裝。 Jenkins 有下面幾個特點: > 1. 嵌入在 Web 伺服器中,通過瀏覽器來操作,非常方便; > 2. 可以執行基於Apache Ant和Apache Maven的專案,以及任意的Shell指令碼和Windows批處理命令; > 2. 可以通過各種手段觸發構建。例如提交給版本控制系統時被觸發,通過類似Cron的機制排程,在其他的構建已經完成時,還可以通過一個特定的URL進行請求; > 3. Jenkins強大的外掛式,使得Jenkins可以整合很多軟體,可能幫助我們持續整合我們的工程專案; > 5. 給使用者很大的許可權和靈活性來自動釋出、部署等等。 其他的有點我就不吹了,我覺得很好用,如果有機會,你也可以試一下。另外,我測試用的虛擬機器是新安裝的 Ubuntu16.04-64,按照下面的流程操作,保證可以順利執行。 JDK 和 Jenkins 的安裝方法,在網路上很多資料,有些過程是有問題的,或者某些關鍵步驟沒寫清楚。為了便於你一次就操作成功,我還是記錄在這裡。 如果你對安裝過程已經很熟悉了,可以直接滑到下一個主題。 #### 2. 安裝 JDK8 (1) 下載,解壓 下載 jdk-8u221-linux-x64.tar.gz,(文末提供下載地址),解壓到目錄 /home/sewain/OpenSource ,解壓指令: ``` sudo tar -zxvf jdk-8u221-linux-x64.tar.gz -C /opt ``` (2) 設定環境變數 執行指令:`vim ~/.bashrc`,在末尾新增如下內容: ``` export JAVA_HOME=/opt/jdk1.8.0_221 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=./$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jart ``` 我建議你也用這樣的環境變數,以後如果升級 JDK 版本,只需要修改 `JAVA_HOME` 就可以了。 (3) )重新載入環境變數 執行指令:`source ~/.bashrc`,此時環境變數就生效了。 驗證一下:` java -version`,出現如下資訊就說明 OK 了: ``` java version "1.8.0_221" Java(TM) SE Runtime Environment (build 1.8.0_221-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode) ``` #### 3. 安裝 Jenkins (1) 匯入 Jenkins 儲存庫的 GPG 金鑰 ``` sudo wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add - ``` 上面的命令應輸出 `OK`,這意味著金鑰已匯入成功,並且來自此儲存庫的軟體包將被視為受信任。 (2) Jenkins儲存庫新增到系統中 ``` sudo sh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list' ``` (3) 使用 apt 安裝 ``` sudo apt update sudo apt install jenkins ``` Jenkins 服務將在安裝過程完成後自動啟動,可以通過指令 `systemctl status jenkins` 進行驗證。 `systemctl status jenkins` (4) 配置埠 Jenkins 是嵌入在一個 tomcat 伺服器中的,預設使用埠 8080,容易與其他服務衝突,因此需要修改一下。涉及到 2 個檔案: 檔案一:/etc/init.d/jenkins 第一行的 PATH 變數中,新增自己的 JDK 地址: ``` PATH=/bin:/usr/bin:/sbin:/usr/sbin:/opt/jdk1.8.0_221/bin ``` 檔案二:/etc/default/jenkins 把 HTTP\_PORT 的值修改為新的埠號,例如: HTTP\_PORT=9090 。 (5) Jenkins 的啟動和停止指令 ``` sudo service jenkins start sudo service jenkins stop ``` 如果不幸遇到錯誤,可以反覆使用這兩個指令來排除錯誤。 #### 4. 在瀏覽器中配置 Jenkins 在瀏覽器中輸入: htpp://localhost:9090,稍等一會,出現介面: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100536759-176209724.png) 按照介面提示,從 `/var/lib/jenkins/secrets/initialAdminPassword` 檔案中複製安全密碼(需要 root 許可權),填入到瀏覽器視窗中。 此時出現安裝外掛視窗,一般只需要安裝推薦的外掛即可: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100536992-1276099353.png) ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100537240-65998494.png) 外掛安裝結束後,進入管理員配置介面: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100537491-850212028.png) ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100537740-1932211491.png) 至此,Jenkins 的安裝就順利完成了! #### 5. 在 Jenkins 中配置一個小專案 (1) 準備一個測試程式碼 Test1 Jenkins 僅僅是一個構件框架,具體的編譯過程是由使用者來決定的。 Jenkins 首先通過 git 工具獲取遠端倉庫中的程式碼,然後執行使用者指定的編譯指令。 因此,我們需要先提前準備好一份測試程式碼,並放到 Jenkins 可以訪問到的遠端倉庫中,當然了,你在本地的 Ubuntu 系統中部署一個 git 倉庫也是可以的。為了方便,我測試的程式碼 Test1 放在 gitee 中了。 (2) 建立一個新專案 ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100537982-874350785.png) (3) 輸入專案名稱,並選擇第一個自由風格(Free project) ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100538240-771386952.png) (4) 在第一個標籤 General下,輸入專案的描述資訊(Description) 內容可以隨便寫。 (5) Source Code Management 原始碼管理 Jenkins 在構建(編譯)的過程中,需要獲取到原始碼,因此需要配置 git 倉庫的地址和賬號資訊(使用者名稱和密碼)。 首先在 Add 下拉按鈕下,選擇 Jenkins: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100538491-370358519.png) 輸入 Username 和 Password : ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100538769-36818109.png) 賬號新增之後,在 Credentials 的下拉框中,選擇剛才新增的 gitee 賬戶,此時可以看到 紅色的許可權錯誤提示消失了,說明可以拉取到遠端倉庫中的原始碼了。 (6) Build Triggers 選擇編譯觸發器 可以根據需要選擇不同的方式來觸發,比如:定時觸發,當其他某個專案構建成功之後觸發等等。 我們這裡不選擇任何專案,下面我們會在主介面,手動點選按鈕來觸發。 (7) Build Environment 編譯環境 這部分我用的比較少,利用其他工具來輔助 Jenkins 的功能。 (8) Build 編譯 就是告訴 Jenkins 如何來構建系統,也就是說:Jenkins只是一個自動化的構建系統,具體的編譯過程,可以由使用者自己來決定,有如下選擇專案: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100539048-889830594.png) 我們這裡選擇直接執行指令碼(Execute Shell),輸入如下指令: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100539248-537625294.png) (9) Post-build Actions 編譯後操作 告訴 Jenkins: 編譯一個工程之後,需要做哪些事情?例如:傳送郵件,觸發下一個工程的自動編譯等等,而且可以新增多個動作。可選項如下: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100539501-604484583.png) 以上步驟配置好之後,Save 儲存,此時在主介面就可以看到這個專案的全貌了,如下圖: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100539754-163742489.png) 在 Jenkins 後臺中,這個專案的儲存路徑是:/var/lib/jenkins/jobs/Test1。 #### 6. 手動觸發編譯一次 由於在上面的步驟(6)中,我們沒有選擇任何觸發條件,所以需要我們在專案 Test1 的主介面中,手動單擊左側的 Build Now 按鈕來觸發。 此時,在左側的 Build History 中,可以看到編譯歷史記錄,單擊某次編譯記錄編號,可以看到這一次編譯的詳細資訊。 在編譯詳細資訊中,單擊左側的 Console Output 按鈕,可以看到編譯的輸出資訊:成功編譯得到可執行檔案。 我們可以在 Jenkins 後臺中看到,原始碼被拉到 /var/lib/jenkins/jobs/Test1/workspace 目錄中了: ![](https://img2020.cnblogs.com/blog/1440498/202104/1440498-20210401100540029-1578259056.png) 到這裡,你已經學會了 Jenkins 的最基本操作! 下面我們繼續講一下 git submodule 的使用,這部分才是核心內容! ## 三、git submodule 基本使用 #### 1. git submodule 是什麼? git submodule 是用於多模組管理的工具,它允許一個專案作為 repository,其他專案作為子模組存在於在父專案中。 父專案和子專案的提交是分開的,也就是說父專案提交的資訊只包含子專案的資訊,而不會包含子專案的程式碼;子專案有自己獨立的 commit,push,pull操作。 git submodule 一般用在比較大的專案中,為了便於複用,或者為了程式碼的安全性,常常需要分成若干個子專案來進行程式碼管理。 常用的指令包括: > 新增子模組: git submod