本文章爲系列文章的第二篇,以前已經寫了一篇 《用開源軟件打造企業級 DevOps 工做流(一):概述》,主要介紹了DevOps的基本概念以及一些組成要素。在這篇文章中,咱們將介紹 版本控制系統 / VCS(Version Control System)
,除了介紹版本控制的基礎概念之外,咱們還將介紹如何使用開源的 GitLab
來實現版本控制系統。git
版本控制系統主要是針對軟件開發過程當中對代碼變動的管理,保證了代碼的可回溯、可審查、可管理等功能需求,而最終的目的,是可維護性。在上一篇文章中,咱們舉例闡述了沒有版本管理工具會出現什麼問題,所以不會在本文贅述。其實主要問題就是沒有版本管理工具致使的可維護性的降低,從而致使各類不可預測的bug的出現。docker
版本的主要內容包括三部分:數據庫
檢入檢出控制(Check-In / Check-Out Control)瀏覽器
分支與合併(Branch / Merge)bash
歷史記錄(History)服務器
關於檢入檢出,咱們能夠理解爲代碼與 版本控制系統數據庫(VCS Database)
的同步與交互過程(以下圖)。網絡
檢出(Check-out)
至關於用戶將 版本控制系統數據庫(VCS Database)
的代碼同步了一份到本地,若是與本地代碼發生了衝突,會比對本地代碼並作相應處理(後面咱們會討論合併)。ssh
檢入(Check-in)
至關因而檢出的逆操做,也就是將本地代碼同步到遠端版本管理系統,實際上是對代碼數據庫的一種更新,至關於一次升級,所以,VCS 須要對將要更新的代碼進行版本審查,並會拒絕將不合法的代碼升級(例如非最新升級)更新到數據庫中。分佈式
檢入檢出的設置保證了代碼數據庫的原子操做,不會由於兩我的同時提交代碼而形成衝突。更改代碼一般在本地進行,每一次更改完畢後會將最新的代碼提交到代碼數據庫,同時更新代碼倉庫,保證遠端代碼是最新的。工具
代碼的 分支(Branch)
概念是指同一「祖先「的代碼在不一樣的方向上各自進行更迭,互不干擾。不一樣分支的代碼通過不斷的迭代,雖然來自同一個「祖先」節點,但極可能演變成徹底不一樣的功能和結構。
一個分支至關因而對某個節點的拷貝,同時也能夠本身發展成新的版本。版本控制系統中有分支的概念是爲了方便開發多個 功能(Feature)
時防止互相干擾,是一種解決代碼衝突的方式。
例如,某開發團隊須要開發 功能 A
和 功能 B
,而這兩個功能都須要在 文件 M
上進行修改。若是同時開發 功能 A
和 功能 B
,則會很難協調,由於開發人員須要同時操做文件 M。這就跟要求兩個猴子吃同一根香蕉同樣困難,那麼咱們爲何不分紅兩根香蕉、一隻猴吃一根呢?
所以,咱們建立了兩個分支 A
和 B
,兩個開發者分別開發,互不影響,互不干擾,這樣操做不會形成代碼衝突,開發起來很是和諧。
雖然咱們解決了同時修改一個文件的問題,咱們還須要將兩個開發好的功能整合起來,這就產生了 合併(Merge)
的概念。
如上面那張圖,當 A 功能
和 B 功能
都開發好了以後,分別爲版本 A2
和版本 B2
,須要將二者整合在一塊兒,產生新的版本 M2
,這個整合的過程就是合併。
固然,合併的過程會產生 衝突(Conflict)
,也就是兩個分支同時修改了同一份代碼。通常的版本控制系統(例如 Git
或 SVN
)會嘗試自動將代碼進行合併,例如很是明顯的增刪操做。然而,也有不能自動合併的狀況,一般要求開發人員手動合併代碼,這叫 解決衝突(Resolve Conflict)
。
開發過程當中,咱們的分支管理會有不少種策略,通常開發團隊會根據項目的須要和團隊的狀況選擇合適的分支管理策略,這個後面會講。
這個其實很好理解,代碼的全部變更,變更了什麼(What)、何處變動的(Where)、什麼時候變的(When)、由誰提交的變動(Who)、爲何變動(Why,提交註釋),這些都會體如今 歷史記錄(History)
中。
若是代碼出了問題、或者須要參考歷史功能等,開發者能夠根據歷史記錄來回溯代碼,找到 Bug 發生的緣由,以及理解歷史代碼的設計等等。這有助於幫助後續的開(jie)發(pan)者(xia)更加輕鬆地掌握須要管理的代碼。
咱們在前面着重介紹了一下分支與合併,這裏咱們會介紹一下其衍生出來的分支管理策略,這對平常開發來講很是重要,由於不一樣的分支策略對項目開發來講有着深遠的影響。
分支管理策略能夠看做是一種開發模式:團隊成員之間如何經過分支與合併操做來協同工做,將不一樣的功能整合在一塊兒,開發測試環境如何隔離,生產環境上線後如何作相應更改等等。
下面咱們將介紹幾種常見的分支管理策略。
主幹開發(Trunk Based Development)
簡稱爲 TBD,是一種常見的分支管理策略,也是 Google 和 Facebook 等大型互聯網巨頭常常採用的策略之一。
主幹開發要求全部代碼都提交到 主幹(Master)
分支上,從而避免了開發者們看到的代碼是過期代碼的狀況。只有當須要 發佈(Release)
的時候,主幹才建立一個當前節點的分支,做爲發佈用。
對於主幹開發來講,開發者要求天天開發前都同步最新代碼,若是有與新提交代碼的衝突,須要在本地本身解決後從新提交到主幹上。這樣的好處在於,因爲開發者的本地代碼基本是跟主幹同步的,所以合併時並不會有重大的變動,合併代碼的時候相對比較容易,不會花不少時間。
而這樣作的缺點也很明顯,若是不少人在項目上進行開發,會致使源源不斷的更新代碼提交到主幹,這會致使發佈的時候存在衆多提交而致使出現了 bug 難以追溯,進而難以修復,容易出現「一顆耗子屎壞了一鍋粥」的狀況。
咱們接下來要介紹的 Git Flow
分支管理策略就是來解決這個缺點的。
Git Flow
是一種 特性分支(Feature Branch)
策略。特性分支策略的概念跟主幹開發策略的概念是相對的,意思是不一樣的功能拉出一個分支單獨開發,開發好後再合併到主幹,保證功能之間互不影響和干擾。
Git Flow 是特性分支策略的一種,是 Vincent Driessen 在 《A Successful Git Branching Model》(nvie.com/posts/a-suc…) 中提出的一種分支模型(以下圖)。
簡單來講,Git Flow 要求有 Master
(主幹)、Develop
(開發)、Release
(發佈)和 Hotfix
(熱修復)幾個基礎分支。
每次須要開發新功能時,在 Develop
分支下拉出一個 Feature
分支(特性分支)來進行單獨開發,開發好後合併到 Develop
分支。當 Develop
分支開發到必定程度的時候,再將其合併到 Release
分支。
Release
分支是在生產環境的 Master
分支前的起 UAT
測試緩衝做用的預備分支。當 Release
分支準備好以後,就將其合併入 Master
主幹分支,這樣就至關於在生產環境上發佈了新版本了。
當線上版本出了 Bug 須要修復的時候,咱們會在直接在 Master
分支上拉出一個 Hotfix
分支,在這個分支上直接作修復,而後合併回主幹。同時 Hotfix
上的幾回修復還會合併到 Develop
上的某個節點,以保存此次修復,這樣 Develop
與 Master
就基本保持了一致。
這是經典意義的 Git Flow,但在實際操做的時候咱們並不必定會原封不動地徹底照搬這個模式。例如,不少時候咱們其實用不到 Release
分支,只存在 Master
和 Develop
,這對於中小型項目來講比較靈活。有時候 Release
也被稱爲 Test
測試分支。另外還有些變種,例如主幹開發與 Git Flow 的部分結合,在 Develop
分支上作主幹開發,每次須要部署到生產環境的時候就將其合併入 Release
或 Master
分支,以發佈正式版本。
Git
和 SVN(Subversion)
是兩個比較受歡迎的版本控制工具。二者之間最大的區別是:SVN 是集中式的,而 Git 是分佈式的(以下圖)。
SVN 要求代碼倉庫只有一箇中心倉庫,全部開發者在作提交代碼的操做前,必須保證本身本地代碼與中心倉庫的代碼徹底同步;而 Git 相對來講就靈活得多,Git 不要求全部開發者的本地代碼徹底一致,在提交時只要求被 push
的倉庫分支與本地的一致就能夠。
另外,SVN 的分支合併複雜且不健壯,由於 SVN 沒法區分合並是人工操做仍是自動合併的,所以將不會建立一個合併記錄節點;而 Git 則相反,會在合併後建立一個合併記錄節點,這增長了可回溯性。並且,用 Git 建立分支的成本很低,只須要 git branch <branch_name>
就能夠了。
因爲分支合併的複雜性,SVN 一般不適合用做特性分支策略,而適合主幹開發模式(Google App Engine 就是 SVN 管理的)。
而 Git 則既適合主幹開發模式,又天生支持特性分支策略。因此,咱們通常都採用更靈活的 Git 做爲版本控制工具,Git 也是如今更爲主流的選擇。
GitLab 是一個開源的版本控制系統,使用 Git 做爲代碼管理工具,並在此基礎上搭建了 Web 服務,它有着精美的 Web UI 界面,方便用戶操做使用。
GitLab 是用 Ruby 編寫的開源項目,有很是自由的 MIT 版權,容許二次開發並投入商業使用。
GitLab 支持 Git 代碼倉庫、權限管理、合併請求、Issues、Wiki、CI/CD 等很是多的強大功能。
GitLab 很是相似 GitHub,支持代碼倉庫、代碼合併、代碼審覈等基礎功能,區別在於:GitHub 是一款雲端產品,並且項目大多爲開源項目(私有倉庫有限制);而 GitLab 是開源產品,能夠很是輕鬆的部署在任意一臺服務器上。
咱們用 GitLab 做爲咱們 DevOps 工做流的緣由主要在其強大的可視化界面和權限管理,至關於增強版的 Git 倉庫。由於人是視覺動物,可視化以後能夠更加高效的處理各類複雜信息,GitLab 能夠幫助咱們作到可視化操做。
而對於企業開發來講,一般會有管理多個項目的需求,不一樣的項目也會有不一樣的開發者參與進來,所以有效地管理這些權限會是個須要注意的問題,而 GitLab 自己就支持相關的權限管理。
安裝 GitLab 很是簡單,咱們推薦的方式是用容器化工具 Docker 來進行安裝。若是您對 Docker 不熟悉,能夠去網上查找一下相關資料(我相信會很是多),或者關注本系列即將介紹的 DevOps 容器篇,在這篇文章中,咱們將着重介紹 Docker。
在安裝以前,確保您已經在本機或者服務器上安裝了 Docker,可以執行基本的 Docker 操做,例如docker ps
。
sudo docker run --detach \ # --detach 表示是後臺運行
--hostname gitlab.example.com \ # GitLab 中引用的 hostname,須要設置爲服務器域名
--publish 443:443 --publish 80:80 --publish 22:22 \ # 映射端口
--name gitlab \ # 容器名稱
--restart always \ # 容器掛了以後會自動重啓
--volume /srv/gitlab/config:/etc/gitlab \ # 配置持久化
--volume /srv/gitlab/logs:/var/log/gitlab \ # 日誌持久化
--volume /srv/gitlab/data:/var/opt/gitlab \ # 數據持久化
gitlab/gitlab-ce:latest # 鏡像名稱
複製代碼
這是官方文檔中的 Docker 啓動命令,只須要在命令行中輸入以上命令,就能夠啓動 GitLab 了。
稍微等待幾十秒,在瀏覽器中輸入 http://localhost
就能夠看到 GitLab 的登錄頁面了。
這裏咱們不打算詳細介紹 GitLab 的全部功能,咱們只會簡單介紹 DevOps 工做流中的重要部分,主要是 Git 的版本控制部分:克隆倉庫、建立分支、合併分支。剩下的功能交給讀者閱讀官方文檔或者本身安裝體驗。
在代碼項目中,複製下面 SSH 或者 HTTP 的地址,例如 ssh://localhost/user/project1
,在本地命令行中輸入以下內容。
git clone ssh://localhost/user/project1
複製代碼
而後會在當前目錄建立一個該項目的目錄,並將文件從遠端拷貝下來。這裏會建立一個origin
的remote
記錄。能夠經過以下方式看到。
git remote -v
複製代碼
若是咱們經過 merge request
的方式來進行版本控制管理,咱們將還會用到 git remote
的操做。
咱們能夠在界面中建立分支,但咱們也能夠在本地建立。
在本地項目中輸入以下內容建立 develop
分支。
git branch develop
git checkout develop
# or
git checkout -b develop
複製代碼
而後更改一些代碼,並經過git commit
提交代碼。接下來,將代碼推送到遠端服務器。
git push origin develop
複製代碼
這樣,遠端就建立了一個 develop
分支,而且將本地 develop
分支上的commits
更新到服務器上了。
當咱們想經過合併的方式將 develop
的更新同步到主幹 master
分支時,咱們須要合併操做。
在本地,能夠這樣操做。
git checkout master
git merge develop
git push origin master
複製代碼
這樣就完成了主幹的合併。
然而,有些時候特別是比較大型的項目時,咱們並不但願在 master
分支上進行修改,咱們想強制要求經過合併代碼的方式來更新主幹分支。所以,咱們須要加一個保護操做。咱們能夠在項目中的 Settings -> Repository -> Protected Branch
中設置保護主幹分支,也就是說,不容許 push
到 master
(讀者請自行了解如何設置,這裏不贅述)。
若是作了這樣的保護限制,咱們須要經過 merge request
的方式來合併分支。在 GitLab 中的項目首頁,點擊左側菜單的 Merge Requests
,點擊 New merge request
,選擇 Source branch
爲 develop
,Target branch
爲 master
,點擊 Compare branches and continue
,進入提交合並請求頁面。在這個頁面中,你能夠看到一些合併信息,包括此次合併有哪些 commits
,哪些代碼有更改、更改了什麼,等等。點擊 Submit merge request
,一個 merge request
就建立好了。而後,若是你是有權限的角色的話,你能夠在這個合併請求頁面中點擊 Merge
贊成此次請求,master
分支也就合併好了。
GitLab 在合併分支時加入的代碼審閱功能對於 Code Review 來講很是方便。一般來講有權限贊成合併請求的開發者都是 Reviewer,須要在合併以前審閱提交的代碼,並根據審閱的結果贊成或拒絕合併請求。
本篇文章主要介紹了版本控制系統的主要概念,包括檢入檢出、分支合併、歷史記錄,以及兩種分支開發策略(主幹開發和 Git Flow),還比較了 Git 和 SVN。另外,本文還着重介紹了開源版本控制系統 GitLab,介紹了其概念、安裝和基本使用。這些知識,對於咱們後面講 DevOps 工做流是很是重要的基礎。下一篇,咱們將介紹持續集成(CI),這與版本控制系統息息相關,由於諸如 Jenkins 或者 GitLab CI/CD 能夠用 GitLab 代碼倉庫做爲源碼來源來自動構建產品。沒有版本控制系統,CI 的優點會受到侷限。所以,版本控制系統是 DevOps 工做流中很是重要的模塊。
在後面的文章中,咱們將繼續介紹 DevOp 的其餘內容,包括持續集成、容器化、編排、網絡、以及如何將這一切串聯起來協同組成企業級的 DevOps 工做流。敬請期待後面的內容。