自動化工具Ansible:基於Jenkins+Ansible+GitLab的部署實踐
轉載出處:微信公眾號EAWorld
從早期手動加指令碼的部署方式,到後來自動化工具(chef, puppet, saltstack, ansible等)的出現,再到如今DevOps的盛行,企業應用部署正式進入平臺部署階段,CD(持續部署)已經成為企業對應用部署的標準需求,運維的交付也不再是以周或天為單位,而是以分鐘為單位。
本文主要介紹自動化工具Ansible,及其在普元DevOps平臺中的應用部署和日常應用部署中的實踐。
本文目錄:
一、如何選擇合適的自動化工具?
二、Ansible架構圖及工作流程
三、DevOps基於Jenkins+Ansible+GitLab的部署實踐
四、Ansible日常應用部署實踐
五、總結
一、如何選擇合適的自動化工具?
面對眾多的自動化工具(chef, puppet, saltstack, ansible等),我們該如何選擇適合自己的呢?總的來說,無外乎從以下幾點來權衡利弊。
-
活躍度(GitHub活躍度,社群活躍度)
-
學習成本
-
使用成本
-
編碼語言
-
效能
各種開源的自動化工具在GitHub的關注度是其活躍度最直觀的體現,從圖中Contributors這一項就可以看出Ansible和SaltStack的開源專案貢獻者遠遠多於其它幾種自動化工具。越活躍的開源專案往往意味著更完善的功能和更高效的問題解決率。
Ansible Galaxy和Salt Formulas都提供了豐富的第三方工具,基本覆蓋了日常部署應用的所有需求。
Puppet和Chef使用的開發語言是Ruby,而Saltstack和Ansible使用的開發語言則是在運維開發這個圈子相對吃得開的Pythen,這也是SaltStack和Ansible相對於Puppet和Chef更容易被接收的原因。
很多選擇Ansible的朋友,大多都是覺得Ansible上手簡單,因為Ansible預設採用SSH連線的方式,不需要安裝配置Client,只需要在Server端配置SSH連線資訊即可。這也是Ansible相對其他自動化工具的一大優勢,但是這一優勢帶來的影響就是實現機制的差異導致在大規模環境下,Ansible的效能確實要比SaltStack差很多,當然,規模大概在一兩百臺機器左右Ansible的效能也是可以接受的。如果是做少量機器應用部署的話,效能問題也就不是那麼關鍵了。
綜合以上因素,最後我們選擇Ansible作為我們DevOps部署功能底層實現的自動化工具。
二、Ansible架構圖及工作流程
先來看看這張架構圖(來源於網路),看起來是不是很簡單,首先對Ansible架構圖的各個組成部分作一個說明。
核心引擎:即圖中所看到的Ansible。
核心模組(Core Module):和大多數運維工具一樣,將系統和應用提供的能力模組化,一個模組有點像程式設計中一個功能介面,要使用的時候呼叫介面並傳參就可以了。比如Ansible的service模組,你要保證名為nginx的service處於啟動狀態,只需要呼叫service模組,並配置引數name: nginx,state: started即可。
自定義模組(Custom Modules):顯而易見,如果Ansible的核心模組滿足不了你的需求,你可以新增自定義化的模組。
外掛(Plugins):模組功能的補充,如迴圈外掛、變數外掛、過濾外掛等,也和模組一樣支援自定義,這個功能不常用(我沒用到過),就不做細說了。
劇本(playbooks):說到這個,先說說Ansible完成任務的兩種方式,一種是Ad-Hoc,就是ansible命令,另一種就是Ansible-playbook,也就是ansible-playbook命令。他們的區別就像是Command命令列和Shell Scripts。
連線外掛(connectior plugins):Ansible預設是基於SSH連線到目標機器上執行操作的。但是同樣的Ansible支援不同的連線方法,要是這樣的話就需要連線外掛來幫助我們完成連線了。
主機清單(host inventory):為Ansible定義了管理主機的策略。一般小型環境下我們只需要在host檔案中寫入主機的IP地址即可,但是到了中大型環境我們有可能需要使用動態主機清單來生成我們所需要執行的目標主機(需要雲環境支援動態生成Ansible host inventory)。
Ansible工作流程大致就是這個樣子,之後在日常應用部署實踐部分對一個應用部署的呼叫流程再做說明。
三、DevOps基於
Jenkins+Ansible+GitLab的部署實踐
既然已經決定用Ansible來完成應用部署的底層實現,那我們如何將Ansible和DevOps結合起來呢?
首先想到的是API,Ansible倒是有一套Python的API介面,但想來在DevOps中做Ansible Python介面的整合封裝不太容易,再就是Ansible通過命令列提供服務,並沒有啟動程序及監聽埠,沒想通如何在DevOps中呼叫Ansible介面,自己對Python亦不是太熟,因此便放棄了這種方式。
之後便了解到了Ansible Tower,Ansible Tower是Ansible的web介面,採用REST API作為介面,先安裝起來看看效果。
上圖為首頁及任務執行頁面截圖,從它相對簡潔的頁面我們就能看出它提供的大部分功能。
-
首頁推送最近使用的Job和最近Job執行情況。
-
主機管理。
-
實時的playbooks輸出和瀏覽。
-
執行歷史資料預覽及報表。
-
基於角色的訪問控制。
-
REST API。
任務頁面截圖是一個安裝部署Nexus的Task,在它的歷史任務執行頁面可以清晰的看到任務執行的實時輸出,任務執行的變數資訊,以及任務每一步的耗時情況等。
Ansible Tower看起來還是挺不錯的,不僅提供了主機管理,任務管理,任務歷史及實時輸出等能力,還提供了直觀實用的報表。奈何,因為它收費的原因,還是被PASS掉了。
正苦思冥想之際,有幸得見一篇文章《Jenkins+Ansible+Gitlab自動化部署三劍客》,文中提到的這種使用方式與我們DevOps本身的很多設計點不謀而合。
在CI(持續整合)的設計上,我們本身也是將Jenkins作為整合工具來使用的,同時Jenkins2版本的Pipeline as Code也給CD(持續部署)帶來了無限的可能。當然,也增加了一定的學習成本,那就是Pipeline的核心Groovy,一種基於JVM(Java虛擬機器)的敏捷開發語言。
Jenkins給我映像較深的一點就是它強大的擴充套件性,它同樣支援Ansible的擴充套件外掛Ansible plugin,在Pipeline中使用外掛和其他型別的Job略有不同,建立一個Pipeline Job之後,可以使用Pipeline Syntax配置外掛和引數,然後Jenkins會自動生成可以在Pipeline中使用的程式碼片段。
再來說GitLab,當然,也可以是其他Jenkins支援的程式碼版本控制系統。它在整個過程中擔任什麼樣的角色呢?試想,我們所需要管理的部署機器和產品對應著的部署指令碼,如果單單只是儲存在某個Server端,如何進行編寫維護以及更新,如何形成運維日積月累過程中的經驗與知識產物。
這裡GitLab可以很好的幫助我們進行Playbooks的管理,我們只需要將Playbooks提交到倉庫,然後在通過Jenkins執行部署之前,將Playbooks拉取到Job的workspace中,然後呼叫執行就可以了。
如何將DevOps與這種Jenkins+Ansible+GitLab的實現方式結合起來呢?
我們DevOps部署大致操作流程如下:
-
資源:建立部署需要的環境資訊,可以是物理機,虛擬機器以及容器雲環境。
-
設計:設計部署容器,比如部署mysql和tomcat並設定tomcat依賴mysql的關係。然後提交設計。
-
轉換:配置部署策略以及部署模式,設定部署容器的引數,建立部署計劃並執行部署。
-
運維:部署容器運維,啟停、解除安裝、伸縮、回滾等操作。
實現方式大致可以簡化為:根據模板化的表設計動態生成部署配置頁面,頁面引數傳遞結合靜態的部署模板(groovy)生成Jenkins的config.xml檔案,然後呼叫Jenkins的API介面建立Jenkins的部署Job。
那我們要進行一個部署容器的擴充套件,我們需要做哪些工作呢?
1.在模板化的表設計中新新增部署容器(如mysql)的相關資訊(元件依賴,屬性定義欄位等)。
2.按照既定的規則在指令碼目錄新增groovy模板(安裝,解除安裝,運維等)。
3.在指令碼庫中新增groovy模板中對應呼叫的ansible playbooks。
四、Ansible日常應用部署實踐
因為DevOps應用及其整合的第三方工具也需要自動化部署,剛好又接觸了Ansible這樣一款自動化工具,所以就寫了一套快速部署DevOps應用及一些第三方工具的playbooks。
單看這張圖,大家可能覺得有點不明所以,我們結合DevOps平臺部署的playbooks目錄結構及檔案類容對此部署設計做一個說明。
Ansible機器分組:就是Ansible的host inventory檔案,內容為機器分組資訊及組變數,在DevOps平臺部署中擔任配置檔案的角色,部署前只需要修改此檔案即可(修改應用的安裝配置和對應每個分組的部署機器)。
DevOps部署角色:對應的site.yml是應用部署的入口檔案,這裡將DevOps應用分成8個角色,分別是devops、mysql、jenkins、nexus、sonarqube、gitlab、cmdb、jira。每個部署角色對應多個role。
Ansible Role:可以理解為Ansible中可複用的最小的操作單元,這裡考慮的不只是DevOps的部署了,考慮到playbooks檔案在今後的日常使用中也會使用到,比如要安裝一個jenkins,只需要在inventory中新增機器資訊,然後定義入口檔案使用repo(考慮到無外部網路訪問許可權情況,配置內網源)和jenkins兩個role即可。
執行命令列ansible-playbook –i devops.inventory site.yml即可開始執行部署,首先會根據site.yml入口檔案中hosts中配置的資訊去devops.inventory中獲取主機及主機變數資訊,然後根據remote_user配置和ansible.cfg中配置的SSH連線資訊去執行連線,然後根據roles配置的角色去執行相應的Task。接下來我們看看Ansible Role的目錄結構和內容。
Roles主要依賴於目錄及檔案的命名和擺放。目錄說明如下:
-
file:copy模組檔案預設路徑,這裡存放安裝檔案和一些不需要修改的固定檔案。
-
handlers:在發生改變時執行呼叫的task。如在tasks目錄下main.yml中有一步修改配置檔案後呼叫handlers,當執行時該步狀態為changed就會呼叫handlers中的task。
-
tasks:存放role任務檔案的目錄,main.yml就是任務入口檔案。
-
templates:template模組檔案預設路徑,用於存放配置檔案和會改變的檔案,檔案中會定義變數資訊,在傳遞時進行變數的替換。
-
vars:role的變數目錄,可以存放role的變數配置資訊,為了方便使用者統一配置,這裡未使用role變數,而是採用了inventory中的組變數。
以下為在Playbooks中用到的一些技巧
register:註冊變數。
場景:在mysql5.6版本安裝完成後會生成預設root使用者的密碼並寫進~/.mysql_secret檔案,那我們要在安裝完成之後用這個root密碼執行初始化操作就可以使用這種註冊變數的方式。
擴充套件用法:判斷某個檔案或資料夾是否存在,來控制task是否執行。當when語句的結果為true時才執行task。
Include:檔案載入,在一個任務檔案中呼叫另一個任務檔案。
場景:一個常用的任務片段在現今或之後的任務檔案中都可能用到,我們可以將它單獨抽離編寫一個任務檔案,然後再其它檔案通過include引用即可。
擴充套件用法:通過定義變數或註冊變數的方式,動態控制是否執行一個任務檔案。
ignore_errors:是否忽略錯誤。
場景:執行某一步,即使該步返回錯誤依然繼續其他的任務。常用與command和shell模組。如示例,在安裝mysql時先去刪除機器可能自帶的mariadb-libs,在不存在mariadb-libs包時會報錯,忽略此錯誤。
wait_for: 校驗檔案或埠的狀態。
場景:等待一個埠啟動、關閉或一個檔案的生成、刪除,常見於啟動應用後等待應用埠啟動,然後執行接下來的任務。
擴充套件用法:用來校驗埠是否啟動或檔案是否存在。
setup:獲取目標機器資訊,並註冊成主機變數。
場景:獲取目標主機ip資訊,並將ip寫進某個配置檔案。任務執行第一步就會預設會呼叫setup模組獲取目標機器資訊,只需要在指令碼中直接使用變數ansible_default_ipv4.address就可以引用主機ip地址。
template:自定義模板。
場景:大多數情況,我們只需要把配置檔案中某些需要變更的變數抽成配置即可,但像nginx這種需要動態配置或相對複雜的配置檔案,就可能會用到Jinja2強大的模板自定義的能力了,最後這張圖是安裝DevOps叢集環境是根據group分組中的ip以及組變數中的埠配置動態生成nginx config檔案的一個片段。
五、總結
Ansible作為自動化工具中的後起之秀,因其簡單易用,無代理架構的特性,已經被廣大的自動化運維愛好者和初學者所接受並使用,如果不做二次開發,甚至都不需要對Python有深入的瞭解,實際上它豐富的模組也已經基本滿足日常運維所有的需求。依稀記得第一次接觸到Ansible是在部署openshift(基於k8s的容器雲平臺)的時候,這種複雜應用的部署通過簡單的幾行配置就完成了,不只是運維,相信對Linux系統有所瞭解的研發人員也可以通過Ansible完成複雜應用的部署。