天天看點

ansible中的playbook詳解

首先簡單說明一下playbook,playbook是什麼呢?根本上說playbook和shell腳本沒有任何的差別,playbook就像shell一樣,也是把一堆的指令組合起來,然後加入對應條件判斷等等,在shell腳本中是一條一條的指令,而在playbook中是一個一個的task任務構成,每個task任務可以看做shell中的一條指令;shell腳本一般隻是在目前伺服器上執行,而playbook則是在不止一個伺服器上執行,是以playbook需要在其中指定運作該playbook的伺服器名。

playbook使用yml标記語言,這是一種标記語言,這種标記語言在檔案的最開始需要使用三個“-”來說明檔案開始,然後使用縮進來說明代碼塊的範圍。下面通過一個簡易的執行個體,來說明playbook的文法。【執行個體來自官方文檔】

運作結果如下:

雖然playbook中定義了執行的主機,但是有時候我們可能僅想在定義的主機中的部分機器上執行,這時候怎麼辦?修改playbook中的hosts的範圍,但是每次改變主機就修改一次,比較麻煩,我們可以使用--limit參數,指定該playbook在指定的主機上執行。有以下inventory檔案,我們想在dbservers上執行上面測試用的playbook内容。

上面測試的playbook中hosts定義all,我們想僅在dbservers上執行。

--inventory=path,指定inventory檔案,預設是在/etc/ansible/hosts下面。

--verbose,顯示詳細的輸出,使用-vvvv顯示精确到每分鐘的輸出。

--extra-vars=vars:定義在playbook使用的變量。

--forks:指定并發的線程數,預設是5.

--connection=type:指定遠端連接配接主機的方式,預設是ssh,設定為local時,則隻在本地執行playbook、

--check:檢測模式,playbook中定義的所有任務将在每台主機上檢測,但是并不執行。

在系統中,我們修改了伺服器的配置檔案,這時候就需要重新開機操作服務,就可以使用到handlers。

在使用handlers時需要注意以下幾點:

Handlers隻有在其所在的任務被執行時,才會被運作;如果一個任務中定義了notify調用Handlers,但是由于條件判斷等原因,該任務未被執行,那麼Handlers同樣不會被執行。

Handlers隻會在每一個play的末尾運作一次;如果想在一個playbook中間運作Handlers,則需要使用meta子產品來實作。例如: -meta: flush_handlers.

如果一個play在運作到調用Handlers的語句之前失敗了,那麼這個Handlers将不會被執行。我們可以使用meta子產品的--force-handlers選項來強制執行Handlers,即使Handlers所在的play中途運作失敗也能執行。

這個變量我們來說明ansible中變量(不包含role中的變量)用法。

有如下playbook腳本:

運作上面的playbook如下:

上面詳細資訊的标準輸出為test,說明變量的值已經傳遞了。

首先來看下playbook的内容:

變量檔案的定義

然後,檢視執行的結果:

在ansible中,inventory檔案通常是指ansible的主機群組定義檔案hosts。在hosts檔案中,變量會被定義在主機名後面或組名的下方。

inventory檔案如下:

檢視playbook的内容如下:

執行一下這個playbook,結果如下:【對應的主機顯示了各自對應的變量值】

回想一下,這種方法定義變量雖然簡單直覺,但是若是變量特别多的情況下,會怎麼樣?特别是給對應的主機定義變量,若是變量太多,則管理起來會很不友善的,是以引入了主機變量群組變量。

【inventory檔案仍然使用上面的檔案】

在執行ansbile指令時,ansible預設會從/etc/ansible/host_vars/和/etc/amsible/group_vars/兩個目錄下讀取變量定義,如果/etc/ansible下面沒有這兩個目錄,可以直接手動建立,并且可以在這兩個目錄中建立與hosts(這裡是指inventory檔案)檔案中主機名或組名同名的檔案來定義變量。

先來看主機變量

playbook的内容如下,執行結果如下:

再來說明一下主機組變量

建立與組名同名的檔案

執行結果如下:

有時候在執行ansbile任務時,可能需要從一台遠端主機上擷取另一台遠端主機的變量資訊,這時候可以使用hostvars變量,這個變量包含了指定主機上所定義的所有變量。

譬如,若是想擷取host1上變量admin_user的内容,在任意主機上直接上使用下面代碼即可。

ansible提供了一些非常有用的内置變量,幾個常用的如下:

grorps:包含了所有hosts檔案裡的主機組的一個清單。

group_names: 包含了目前主機所在的所有主機組名的一個清單。

inventory_hostname: 通過hosts檔案定義的主機名。(與ansible_home意義不同)

inventory_hostname_short:變量inventory_hostname的第一部分。譬如inventory_hostname的值為books.ansible.com,那麼inventory_hostname_short的值就是books。

play_hosts: 将執行目前任務的所有主機

注冊變量,其實就是将操作結果,包括标準輸出和标準錯誤輸出,儲存到變量中,然後再根據這個變量的内容來決定下一步的操作,在這個過程中用來儲存操作結果的變量就叫注冊變量。

上面的playbook執行結果如下:

一個注冊變量通常會有以下4個屬性:

changed:任務是否對遠端主機造成的變更。

delta:任務運作所用的時間。

stdout:正常的輸出資訊。

stderr:錯誤資訊。

對于普通變量,在ansible指令行設定的,在hosts檔案中定義的,或者在playbook中定義的等,這些都是普通變量,在引用時,可以使用使用{{ variable }}的形式。ansible是用python語言寫的,是以也支援一種叫做清單的變量,形式如下:

在上面的測試中,我們的playbook都執行了一條指令叫gater_facts:no,加入了這條指令後,playbook腳本的執行速度會快很多,這是因為預設情況下,ansible是會手機遠端伺服器的主機資訊,這些資訊包含了伺服器的一些基本設定。

收集的主機資訊可以使用setup子產品檢視,一個主機的收集資訊如下:

ansible中的playbook詳解
ansible中的playbook詳解

ansible 10.0.102.162 -m setup

在實際應用中,運用的比較多的facts變量有ansible_os_family,ansible_hostname等,這些變量通常會被拿來作為when條件語句的判斷條件,來決定下一步的操作。一個簡單的執行個體:

本地facts變量

我們可以自己定義facts變量,把這個變量寫入一個以.fact結尾的檔案中,這個檔案可以是json檔案或ini檔案,或者是一個可以傳回json代碼的可執行檔案。然後将其放在遠端主機的/etc/ansible/facts.d檔案夾中,ansible在執行的任務時會自動到這個檔案夾中讀取變量的資訊。

在遠端主機上做如下操作:

然後再ansible主機上擷取自定義的資訊。

條件判斷在ansible任務中的使用頻率非常高。我們可以根據一些條件的不一樣執行不同的task。

很多任務隻有在特定條件下才能執行,這就是when語句發揮作用的地方。

一個簡單的執行個體,關閉掉ip位址為10.0.102.162伺服器上的mysql服務,如下:

執行的結果如下:

這個就是when條件語句的用法很簡單。需要注意when語句的作用于paly的作用時間,當when的條件滿足時,然後才會執行play中的任務。ansible還提供了另外兩個與when相關的語句changed_when和failed_when條件判斷。

暫空

預設情況下,ansible所有任務都是在我們指定的機器上面運作的,當在一個獨立的叢集環境配置時,這并沒有什麼問題。而在有些情況下,比如給某台伺服器發送通知或者向監控伺服器中添加被監控的主機,這個時候任務就需要在特定的主機上運作,而非一開始指定的所有主機,此時就需要ansible的委托任務。

使用delegate_to關鍵字可以配置任務在指定的伺服器上執行,而其他任務還是在hosts關鍵字配置的所有機器上執行,當到了這個關鍵字所在的任務時,就使用委托的機器運作。

檢視MySQL是否在運作狀态,是以在檢查之前首先關掉162上的mysql服務。【為了友善檢視狀态】

這裡委托是在指定的機器上執行,若是想在本地伺服器上執行,可以把ip位址換為127.0.0.1即可。也可以使用local_action方法。

結果如下:

有些情況下,一些任務的運作需要等待一些狀态的恢複,比如某一台主機或者應用剛剛重新開機,我們需要等待它上面的某個端口開啟,此時我們就不得不将正在運作的任務暫停,直到其狀态滿足我們的需求。下一個執行個體【摘抄】

在少數情況下,ansible任務運作的過程中需要使用者輸入一些資料,這些資料要麼比較秘密不友善,或者資料是動态的,不同的使用者有不同的需求,比如輸入使用者自己的賬戶和密碼或者輸入不同的版本号會觸發不同的後續操作等。ansible的vars_prompt關鍵字就是用來處理上述這種與使用者互動的情況的。下面是一個簡單的執行個體。

然後執行上面的playbook,因為我們隻是測試,隻需要在一台機器上執行,是以加入了--limit參數。

手動輸入的變量值,在後面的play中仍然可以用{{ var_name }}的形式調用。

關鍵字vars_prompt幾個常用的選項總結如下:

private: 預設值為yes,表示使用者輸入的值在指令行不可見;将值設為no時,使用者輸入可見。

default:為變量設定預設值,以節省使用者輸入時間。

confirm:特别适合輸入密碼的情況,如果将其設定為yes,則會要求使用者輸入兩次,以增加輸入的安全性。

預設情況下,ansible在執行一個playbook時,會執行playbook中定義的所有任務。ansible的标簽功能可以給角色,檔案,單獨的任務甚至整個playbook打上标簽,然後利用這些标簽來指定要運作playbook中的個别任務,或不執行指定的任務,并且它的文法非常簡單。

通過一段代碼來說明tags的用法,代碼摘自《ansible權威指南》

将上述代碼儲存,可以通過以下指令來隻執行“Notify on completion”任務。

如果想忽略掉某個任務,可以使用--skip-tags關鍵字指定。

ansible從2.0.0版本開始引入了塊功能。塊功能可以将任務進行分組,并且可以在塊級别上應用任務變量。同時,塊功能還可以使用類似于其他程式設計語言處理異常那樣的方法,來處理塊内部的任務異常。

上面的playbooj和之前的并沒有什麼不同,隻是假如了block之後,代碼更容易檢視。

塊功能可以用來處理任務的異常。比如一個ansible任務時監控一個并不太重要的應用,這個應用的正常運作與否對後續的任務并不産生影響,這時候我們就可以通過塊功能來處理這個應用的報錯。如下代碼:

當塊中任意任務出錯時,rescue關鍵字對應的代碼塊就會被執行,而always關鍵字對應的代碼塊無論如何都會被執行。