首頁>技術>

在本篇文章中,我們將介紹持續整合的基本概念,為什麼用持續整合,以及如何利用開源軟體 Jenkins 來實現持續整合。

持續整合簡介

本系列文章的第一篇概述中我們提到,持續整合可以類比於工廠中的流水線操作。例如生產一輛汽車,一切從裸車架開始,車架用吊鉤送上傳送帶,經過裝配、打磨、測試等一系列複雜而緊湊的統一化流程,最終產出一輛功能齊全、品質卓越的完整汽車。

持續整合類似軟體開發中的流水線,只是持續整合中的流水線通常來說是自動化的,也就是說不需要任何人為干預,一個軟體程式就可以從原始碼開始,經過一系列的構建步驟,最終形成成熟的產品。什麼時候啟動這個流水線呢?一般來說,是程式碼變更的時候。其實,這裡所說的流水線還包括了部署的過程,一般說持續整合通常會提到 持續部署(CD)。嚴格意義上來說這是兩個概念:持續整合(CI)是指不斷將程式碼不斷同步到主幹,持續部署是指程式碼經過評審後自動部署到生產環境。為了方便起見,我們將這兩個概念合二為一,統稱為 CI/CD 。

例如上圖這個持續整合流水線,當持續整合工具檢測到原始碼有變更的時候,會啟動這個流水線:

首先獲取原始碼;並行構建前後端應用;構建 Docker 映象;單元測試;完成部署。

經歷了這幾個步驟之後,一次整合過程就算完成了。整個流程不需要人為干預,唯一需要開發者做的,就是提交一次程式碼更新程式碼倉庫,持續整合工具會自動將後面的事情(包括部署)一步步幫你做完,全程自動化。

為什麼用 CI/CD

其實我們可以不用 CI/CD 來完成從編碼到部署的過程。那麼,為什麼我們要用 CI/CD 呢?首先我們看看下面一個流程圖。

這是一個從碼程式碼到最終部署交付的流程例子:我們花數小時碼程式碼(Coding),不到 1 分鐘提交程式碼(Commit),然後構建(Build)這個應用花 1 分鐘到 1 小時(根據應用複雜程度),接著花數分鐘部署(Deploy)這個應用,最後測試(Test)。除開程式碼和提交的時間,後面的構建+部署時間最少也得花幾分鐘,而測試可能會花更久。

我們要知道的是,構建和部署一般來說是重複性的工作,例如執行一次 npm run build:prod 打包前端程式碼,或者將打包好後的前端靜態檔案拷貝到目標地址。如果是人來操作這些流程,非常浪費時間和精力。雖然構建部署一次可能花不了多少時間,但考慮到企業中通常是多人協同工作,每個人都會提交程式碼,而且很可能是多次提交,這樣需要執行的次數就是遠不止一次或幾次了。你簡單做一做乘法,就知道會有多少人工時間成本會花費在上面,而人工成本目前來說是越來越貴的。因此,使用持續整合將降低時間成本(Time Expense)。

另外,人工來處理構建部署等流程容易出錯。人無完人,即使是富有經驗的架構師上線部署也可能會出現操作失誤導致系統上線失敗。在作者的職業生涯中,發現有很多因為人的原因部署失敗的情況,例如忘記更改環境變數、資料庫連線串配置錯誤、執行命令輸入錯誤等等。而這些都可以通過自動化的流程來避免,因為機器是很死板的,一旦設定好,就會原封不動的按規定執行,不會出現操作失誤(當然排除諸如網路原因等導致的錯誤)。因此,使用持續整合還可以降低人為錯誤(Human Error)。

上面這個流程圖中紅色部分(編碼和提交)是無法自動化的,需要人工操作;而綠色部分(構建和部署)是可以自動化的,也是需要儘可能全部自動化的;黃色部分(測試)是半人工半自動化的,因為我們可以通過 單元測試(Unit Test) 來自動化很多測試工作,但一些複雜的測試用例(例如頁面的排版是否符合設計預期)則需要人工來完成,因此測試部分是半自動化的。這裡多提一下單元測試,固然單元測試是非常有助於提升程式碼的工程品質,但是編寫單元測試卻相當耗費時間,差不多跟寫功能的時間差不多,因此會將整個專案時間加倍,所以需要在時間與品質之間權衡是否需要採用單元測試。

開源工具 Jenkins

要實現 CI/CD,我們需要一些工具。我們推薦的工具是 Jenkins,這也是企業環境中用的比較多的持續整合開源軟體。下面我們將詳細介紹一下 Jenkins,包括基本介紹、安裝、基本使用以及如何實踐應用到 DevOps 工作流中。

Jenkins 簡介

可能你對 Jenkins 本身並不陌生,這是因為 Jenkins 從 2011 年開始就已經存在,是最早的也是最常用的選擇。它出自 Sun 公司的一個工程師的業餘專案,不斷改進優化後逐漸壯大成為最熱門的持續整合工具(聽起來是不是跟 JavaScript 的經歷差不多?)。

關於 Jenkins 的介紹,我們主要引用其官網上的描述。以下是官方的關於 Jenkins 的一句話描述:

Jenkins是開源CI&CD軟體領導者, 提供超過1000個外掛來支援構建、部署、自動化, 滿足任何專案的需要。

其中,CI 指代持續整合,CD 指代持續交付。

以下是其主要特點:

持續整合和持續交付: 作為一個可擴充套件的自動化伺服器,Jenkins 可以用作簡單的 CI 伺服器,或者變成任何專案的持續交付中心;簡易安裝: Jenkins 是一個基於 Java 的獨立程式,可以立即執行,包含 Windows、Mac OS X 和其他類 Unix 作業系統;配置簡單: Jenkins 可以通過其網頁介面輕鬆設定和配置,其中包括即時錯誤檢查和內建幫助;外掛: 通過更新中心中的 1000 多個外掛,Jenkins 集成了持續整合和持續交付工具鏈中幾乎所有的工具;擴充套件: Jenkins 可以通過其外掛架構進行擴充套件,從而為 Jenkins 可以做的事提供幾乎無限的可能性;分散式: Jenkins 可以輕鬆地在多臺機器上分配工作,幫助更快速地跨多個平臺推動構建、測試和部署。

從介紹總結來看,Jenkins 的核心功能是持續整合和持續交付,另外還有便捷性(安裝簡單)和擴充套件性(外掛、分散式)。

安裝 Jenkins

跟之前的文章裡安裝 GitLab 一樣,我們同樣是用 Docker 來安裝 Jenkins。在確保您已安裝 Docker 、並且能順利執行 docker ps 的前提下,執行以下命令。

docker run -u root \\ # 以root使用者執行 --restart always \\ # 永遠設定為重啟狀態,開機時也會啟動 -d \\ # daemon方式後臺執行 -p 8080:8080 -p 50000:50000 \\ # 將web埠映射出來,8080為web介面埠 --name jenkins \\ # 容器名稱\t-v jenkins-data:/var/jenkins_home \\ # 持久化資料\t-v /var/run/docker.sock:/var/run/docker.sock \\ # Docker守護程序預設監聽的Unix域套接字\t-e JAVA_OPTS=-Duser.timezone=Asia/Shanghai \\ # 調整時區為中國時區\tjenkinsci/blueocean # Jenkins映象複製程式碼

以上命令已經有註釋了,讀者可以根據需要更改其中的一些配置,例如對映埠,8080 可以是 9090、80 等等。執行上述命令後,Jenkins 需要一定初始化時間,等待片刻後在瀏覽器中輸入 http://<宿主機ip>:8080,就可以看到 Jenkins 的初始介面(如下圖),這是 Jenkins 在載入必要資料和第三方庫,大概需要幾分鐘。

初始化完畢後,瀏覽器會重新載入,我們會看到如下配置介面。

這個是告知您,需要輸入初始密碼,而這個密碼在 Jenkins 容器裡的 /var/jenkins_home/secrets/initialAdminPassword 檔案裡。輸入以下命令來檢視初始密碼。

docker exec -it jenkins bash # 進入容器命令列cat /var/jenkins_home/secrets/initialAdminPassword # 檢視初始密碼複製程式碼

將檢視到的初始密碼輸入到上述介面中,點選 Continue 進入下一步。載入片刻後,您將看到如下選擇介面。

安裝完畢後,輸入第一個管理員賬戶,點選 Save and Continue 進入到下一步,然後點選 Save and Finish,最後選擇 Restart,完成重啟。

重啟完畢後,您就可以註冊登陸了,請選擇剛才的管理員賬戶登陸。

使用 Jenkins

你可能最開始使用 Jenkins 的時候會發現它樸素的使用者介面一點也不酷炫,總體顯得比較老舊,不像是現代軟體的風格,不過我們有 Open Blue Ocean 加強版介面,非常扁平化和現代化,不習慣 Jenkins 預設介面的可以切換過去。下圖是進入 Jenkins 的主頁介面,可以看到左側有一些操作選項以及構建佇列和執行器狀態,右側是自動化專案的列表。

下圖是 Open Blue Ocean 的主頁介面,功能上跟預設介面差不多,只是排版和風格有所不同。

其實,介面這些都不是特別重要的問題,很快你會被它樸實但強大的核心功能(持續整合)所折服。在使用這些強大的功能之前,我們需要做一些配置。

配置節點

首先看下圖,作者有兩臺物理機,IP 地址分別是 192.168.0.2 和 192.168.0.3 (假設),Jenkins 是用 Docker 起動的容器,在 192.168.0.2 這臺宿主機裡,而我們想在宿主機(192.168.0.2)上以及另一臺物理機(192.168.0.3)上構建應用,因此需要分別需要將這兩臺機器註冊到 Jenkins 裡。

這裡簡單介紹一下 Jenkins 的原理,Jenkins 構建專案是通過 Jenkins Executor 這個 jar 包來實現構建和部署的。Jenkins 服務的本地機器叫做 主機(master) ,如果告訴主機其他機器的 IP 地址和登陸資訊,Jenkins 就可以通過 SSH 的方式在該機器上將 Jenkins Executor 拷貝過去並執行,再而與其互動通訊,通過 Jenkins Executor 完成遠端構建工作。

下面我們介紹如何配置節點。

在主頁中點選 Manage Jenkins (確保您有管理員許可權),進入管理頁面;然後點選 Manage Nodes ,進入到管理節點頁面;這裡您應該能看到 master 節點,這時候你需要新增節點,點選左側的 New Node;輸入節點名稱(Node Name),點選 OK,將看到很多配置資訊;完成配置(配置資訊如下圖),點選 Save 儲存設定。

然後,您應該就可以看到下圖節點列表了,左側 S 列代表的是節點狀態(Status),如果節點線上,會顯示為計算機的符號,如果離線,則會顯示一個計算機加紅叉的符號。你可以點選去看它的日誌(Log),如果一直連不上,需要檢視日誌排查錯誤。

節點配置好了,您就可以在這些節點上執行構建程式了。如果您有多個機器需要部署,只要一次性手動將這些資訊註冊進 Jenkins,就可以一勞永逸的在各臺機器自動化部署應用程式了。是不是很酷?

建立專案

現在,我們介紹在 Jenkins 中如何建立一個自動化專案。其實過程很簡單,只是配置方面稍微複雜一些。

在主頁點選 New Item 建立新專案;輸入專案名稱,然後選擇專案類別,強烈建議選擇 Multibranch Pipeline (多分支管道),因為這一個類別是最方便配置和最容易整合之前介紹的 GitLab 版本控制系統的類別,然後點選 OK;配置各種輸入,包括展示名稱、專案來源(來自VCS,例如Git/SVN)、構建週期(選擇每分鐘)等等。

點選 Save 儲存專案,就建立好了一個專案。

讀者可能會問:等等,構建過程跑哪兒去了?彆著急,我們接下來會將如何配置構建過程,也就是用一個配置檔案來定義構建過程,而這個配置檔案叫 Jenkinsfile。

Jenkinsfile

讀者可能會問,Jenkinsfile 是不是與 Dockerfile 有異曲同工之妙?沒錯!這兩種配置檔案都屬於 Infrastructure as Code(架構即程式碼) ,僅僅用程式碼就可以配置出計算機和網路架構,非常易於管理和擴充套件。下面我們會詳細介紹 Jenkinsfile。

Jenkinsfile 是 Jenkins 2 釋出的一個實用功能,這個功能讓用程式碼管理構建過程變成可能。它使用 Groovy 語法,很容易配置不同的構建階段。下面是一個 Jenkinsfile 的例子。

pipeline { agent { node { label 'docker' // 要執行的節點名稱 } } stages { \t// 配置階段 stage('Configure') { steps { echo 'Configuring' script { // 根據 Git 分值名稱選擇不同的 docker-compose 檔案 switch (env.GIT_BRANCH) { case 'develop': \t// 開發分支的 docker-compose 檔案 env.DOCKER_COMPOSE_FILENAME = 'docker-compose-dev.yaml' break case 'master': \t// 主幹的 docker-compose 檔案 env.DOCKER_COMPOSE_FILENAME = 'docker-compose-prod.yaml' break default: echo "Unknown branch ${env.GIT_BRANCH}" exit 1 } } } } \t// 構建階段 stage('Build') { steps { echo 'Building' \t// 用 Docker 不同分支的構建映象(用 GIT_BRANCH 環境變數區分) sh """ docker build -t awesome-image:${ENV:GIT_BRANCH} -f Dockerfile-local . """ } } \t// 測試階段 stage('Test') { steps { echo 'Testing' } } \t// 部署階段 stage('Deploy') { steps { \t// 用 docker-compose 重啟映象服務 sh """ docker-compose -f ${ENV:DOCKER_COMPOSE_FILENAME} down | true docker-compose -f ${ENV:DOCKER_COMPOSE_FILENAME} up -d """ } } \t// 清理階段 stage ('Clean-up') { steps { \t// 清理不用的 Docker 映象 sh ''' docker rmi $(docker images -f "dangling=true" -q) || true ''' } } }}複製程式碼

這裡,我們用了 Docker 來完成構建工作,Docker Compose 來完成部署工作。後面的文章會詳細介紹 Docker 在 DevOps 中的應用。

關於 Jenkinsfile 的內容以及 API 還很多,本文不會全部涵蓋。需要的朋友可以參考官方文件 jenkins.io/zh/doc/book…

配置好了 Jenkinsfile,將它放在 Git 專案根目錄下,當每次有程式碼提交的時候,Jenkins 就會拉最新程式碼,然後開始構建過程,如下圖。

檢視構建進度

用 Pipeline 構建的好處在於可以直觀的看到構建的過程,包括各階段花了多少時間等資訊。下圖是某個專案構建過程的概覽。可以看到,每一次構建都是由 VCS 程式碼提交觸發的。這樣的話,只要我們在某個分支上提交了程式碼,Jenkins 就可以自動幫我們構建、部署了。如果構建過程中有報錯,Jenkins 中會有提示資訊。

Jenkins 與其他 CI/CD 工具

Jenkins 是一個強大的工具,不過市面上還有其他很多優秀的 CI/CD 工具。如下圖,我們可以看到整個 CI/CD 市場的市場份額。

可以看到,除了 Jenkins,還有很多人用 Circle CI、Travis CI、GitLab CI 等工具。其實 Jenkins 不是唯一選擇,開發者運維者們還有很多其他的選擇,都可以分別嘗試。例如,GitLab CI,其實用了 GitLab 管理程式碼的話,可以用 GitLab CI 來做持續整合。為什麼用 Jenkins 而不是 GitLab CI 呢,這其實跟作者的工作經歷有關,作者對 GitLab CI 並不是很熟悉,有機會一定會嘗試一下。當然,客觀來說,Jenkins 靈活性更強,更輕量級,加密性好,而且是跨平臺的,但外掛品質參差不齊,導致有時容易出問題(所以我們推薦使用官方外掛)。因此,對於用 GitLab 做 VCS 且專案通常複雜性不高的使用者來說,GitLab CI 是個更好的選擇。

為什麼 Jenkins 這麼出名,是因為它是最早的開源 CI/CD 工具,存在市場比較久而已,讀者有權利選擇任何合適的工具。

下圖是各個 CI/CD 工具的市場競爭矩陣圖。

可以看到,Jenkins 的地位其實不是屬於領先地位,後來居上的 Circle CI 的市場滿意度和市場份額都領先於其他工具,是一個非常有潛力的工具,作者也會找時間嘗試一下,當然也歡迎讀者去嘗試。

總結

本文介紹了持續整合的基本概念,以及使用 CI/CD 的原因,此外還詳細介紹了開源 CI/CD 工具 Jenkins,包括 Jenkins 的簡單介紹、如何安裝、如何配置、建立專案以及如何使用 Jenkinsfile 和檢視構建進度。相信仔細閱讀了本篇文章的讀者,應該會基本了解持續整合的概念和框架,以及在企業中推廣使用持續整合的重要性。此外我們還了解了 CI/CD 工具的市場情況,並知道 Jenkins 並不是唯一的選擇,市面上還可以選擇很多其他優秀的工具,例如後起之秀 Circle CI。我們選合適的 CI/CD 工具是為了滿足企業的 DevOps 需求,而不應該侷限於工具的名聲和自己所掌握的知識,只要做好了前期調研和需求分析,我相信是可以實踐好 DevOps 中的持續整合功能的。最後提一點,就是工具並不是全部,如果沒有良好定義的流程與技能儲備,DevOps 是實踐不通的,應用再優秀的 CI/CD 工具也會失去意義。因此,我們需要經常充實自己,加強 DevOps 的知識了解,擴充自己的能力範圍,這樣才能打造出最佳的 DevOps 工作流。

我們之前介紹了 DevOps 概述、VCS,現在又介紹 CI/CD,接下來我們會講容器化,會詳細介紹 Docker,敬請期待後續文章。

作者:MarvinZhang連結:https://juejin.im/post/5e61b46ee51d4526f23a2ba6

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 輕鬆入門Sentinel