Tips:與前文 《進擊的 Ansible(一):Ansible 快速入門》 一樣,本文使用的 Ansible 版本 2.5.4,項目示範環境 MacOS。由于 Ansible 項目開發活躍版本更新快,很多 API 接口不向後相容,是以對照本文實踐時請確定所用版本一緻。
學完前文《進擊的 Ansible(一):Ansible 快速入門》後,用來釋出單體項目綽綽有餘。但是實際生産環境中一個服務往往有多個元件,比如部署大資料服務時,常常需要部署一個“大資料全家桶”:Hadoop、 Zookeeper、 Hive、 Mysql、 Flink 等。這時僅靠前文中的知識就有點捉襟見肘了,繁多的 yaml 檔案和其他配置檔案依賴關系複雜,如果不能正确地劃分目錄組織項目結構,對于後期維護非常不利。是以今天的文章着重解決一下這個問題:如何科學正确地劃分 Ansible 應用的目錄結構?
首先要樹立這樣一個觀念:“把 Ansible 視為一種程式設計語言”。我們可以将 Ansible 了解為專門用來管理自動化釋出的 DSL,它的基本文法規則約等于 yaml 語言規則,諸如 synchronize、pip、template 等。同時 Ansible 子產品可等價為語言的内置函數或内置包,也就是編寫 playbook 就是在寫 Ansible 這門語言的代碼塊。如此,隻要我們沿着程式設計語言的思路去了解 Ansible,很多疑惑會迎刃而解:比如 Ansible 支援變量,子產品 when 就是程式設計語言的流程控制語句 if, 子產品 loop 或 with_* 就是程式設計語言中的循環疊代語句 for 或 while。
使用程式設計語言進行項目開發的過程中,我們是如何降低項目複雜度的?當然是進行“子產品化”。不同的功能封裝到不同的包或檔案中,這樣構成一個業務功能的最小機關我們稱之為“子產品”。在項目的入口檔案中,我們通過 import (Python、Golang 等語言中使用此關鍵字) 或 require (Node.js 等語言使用此關鍵字)等關鍵字把需要的子產品載入進來,然後就可以進行業務邏輯上的編排。
這樣做的優點顯而易見,一個子產品是一個業務功能的具體實作,當後期有修改的需求時隻需要修改相關的子產品即可,這正是 SOLID 原則中的 “SRP” (單一職責原則) 所提倡的。此外,子產品化還支援像“搭積木”一樣根據業務需求靈活地組織業務流程,這樣就能最大限度地複用目前子產品,這也符合程式設計原則中的 “DRY” (Don't Repeat Yourself)。
是以在我們将 Ansible 視為一門程式設計語言(DSL)的現在,我們可以發現在 Ansible 文檔中用 Roles 表示“子產品”這個概念,用 import_tasks、include_tasks 等表示 import 這個概念。這裡說一個題外話,不知道有沒有人覺得 Ansible 中發明的“playbook”、“roles” 等直譯成“劇本”、“角色”的概念讓人摸不着頭腦?
現在我們樹立了“Roles = 子產品”的概念。我們在看一下文檔中對 Roles 的定義,豐富一下細節:
Roles let you automatically load related vars, files, tasks, handlers, and other Ansible artifacts based on a known file structure. After you group your content in roles, you can easily reuse them and share them with other users.
“角色允許您基于已知的檔案結構自動加載相關的變量、檔案、任務、處理程式和其他Ansible工件。在将内容按角色分組後,可以輕松地重用它們并與其他使用者共享它們。”
直白來講就是 Roles 是對變量、檔案、任務等的封裝,目的是為了子產品重用。
如何使用 Roles?
在軟體設計範式的最佳實踐中有一條叫做 “約定大于配置”,簡單來講就是“軟體中做了一些前提性假設,這些假設就是軟體開發者與軟體使用者的約定。作為軟體使用者你遵守這些約定即可,不再需要(或不支援)對這些約定進行配置。”—— 一定程度上可以了解為軟體中的預設配置。
Ansible 在使用 Roles 時同樣存在 “約定大于配置” 的情況,并且這些約定是硬性的(即不支援在配置檔案中自定義)。
首先,Role 的目錄結構是固定的。
An Ansible role has a defined directory structure with eight main standard directories. You must include at least one of these directories in each role. You can omit any directories the role does not use.
Ansible 角色有一個定義好的目錄結構,其中有八個主要的标準目錄。該已規定好的目錄結構,示例如下:
By default Ansible will look in each directory within a role for a main.yml file for relevant content.
這八個目錄的作用是:
tasks/main.yml:放置 role 執行任務時用到的檔案。
handlers/main.yml:處理程式,可以在 role 内部或外部使用
library/my_module.py:子產品,可以在 role 中使用(有關更多資訊,請參見在rroles 中嵌入子產品和插件)。
defaults/main.yml:role 的預設變量(有關更多資訊,請參閱使用變量)。這些變量具有所有可用變量中最低的優先級,并且可以被任何其他變量(包括庫存變量)輕松覆寫。
vars/main.yml:role 中的其他變量。(與 Ansible 子產品中的 vars 作用一緻,隻不過這裡的 vars 表示目錄。)
files/main.yml:role 部署時用到的檔案。
templates/main.yml:role 部署時用到的模闆。與 Ansible 子產品中的 templates 作用一緻,隻不過這裡的 templates 表示目錄。)
meta/main.yml:role 使用到的中繼資料。
在每個角色中必須包含至少一個這樣的目錄,當然我們可以省略角色不使用的任何目錄,但是每個目錄下的 main.yml 檔案是該目錄的入口檔案,Ansible 讀取時會預設查找該檔案。是以這個 main.yml 檔案不能省略。
其次,存儲和查找 roles。
上文我們已經了解到了一個 role 的内部目錄結構,但是這遠遠不能滿足實際生産的需求。在文章的開始部分我們也以一個大資料項目為例,往往需要部署 Flink、Hadoop 等多個元件。這每一個元件都可以看做是一個 role。那麼 Ansible 是如何查找 roles 的呢?
預設情況下,有 2 種方式:
在 Ansible 的釋出項目中,建立一個叫做 roles 的目錄。
預設情況下,Ansible 會自動查找 /etc/ansible/roles 目錄下的 role。
舉個例子,我們要使用 Ansible 建立一個釋出大資料“全家桶”的項目 bigdata,該項目下要包含 Flink、Mysql、Hive 這 3 個 role。那麼 bigdata 這個項目的目錄結構大緻如下:
很明顯可以看到 roles 下的 Flink、hive、Mysql 的子目錄結構就是上文中提到的八大目錄。
快速建立 Role
從上文可知,每建立一個 role 都必須至少含有八大目錄之一。是以 Ansible 中已内置了一個指令行工具 ansible-galaxy 快速建立 role 的八大目錄,減輕我們的工作量。
假設該 role 名稱是 flink,用如下指令生成相關目錄:
使用 tree 指令看到 ansible-galaxy 生成的目錄正是 role 所要求的标準的八個目錄。
ansible-galaxy init 其他幾個實用的參數:
ansible-galaxy init -force role_name,預設情況下建立的 role 與目前工作目錄下存在的檔案重名的話,會抛出異常。使用 -force 選項會強制建立 role 目錄,并對 role 目錄下重名的目錄或檔案進行替換。
ansible-galaxy init --role-skeleton=/path/to/skeleton role_name,使用過 Maven 的同學應該知道, Maven 支援以其他項目做骨架建立新項目。ansible-galaxy 同樣支援該功能,以 /path/to/skeleton 路徑下的 role 為骨架,把所有的檔案都進行拷貝來建立新的 role。
Galaxy:role 線上分享社群
此外與 Docker Hub、Grafana Dashboards 類似,Ansible Galaxy 也有一個線上社群 Galaxy[https://galaxy.ansible.com/home],上面有開發者分享的各種已經開發好的 roles。友善我們搜尋現成的 role 下載下傳,也可以上傳自己開發的 role 到 Galaxy。
下載下傳或上傳 role 到 Galaxy 網站,同樣需要使用指令行工具 ansible-galaxy。預設情況下 ansible-galaxy 調用的 Galaxy 服務端的位址是 https://galaxy.ansible.com, 可以通過 -server 選項或在 ansible.cfg 檔案中重新配置 Galaxy 的位址。
下載下傳 roles
下載下傳 roles 的文法模闆是:
預設情況下 ansible-galaxy 會把 role 下載下傳到環境變量 ANSIBLE_ROLES_PATH 中,ansible-galaxy 提供了參數 --role_path 指定 role 下載下傳的位址。
ansible-galaxy 其他指令速覽
ansible-galaxy search elasticsearch,查找 Galaxy 網站中的 role elasticsearch
ansible-galaxy info username.role_name,檢視 username.role_name 的詳細資訊
ansible-galaxy list,檢視已安裝的 roles
ansible-galaxy remove username.role_name,解除安裝安裝的 username.role_name
ansible-galaxy login,登入 Galaxy 網站
如果你堅持讀完上述部分,那麼你肯定對于如何使用 role 了然于心,簡單來講就是目前 Ansible 應用下需要存在一個叫做 roles 的目錄。接下來我們聊聊 Ansible 應用下除了 roles 目錄外,其他目錄該如何布局呢?Ansible 最佳實踐官方文檔[https://docs.ansible.com/ansible/2.5/user_guide/playbooks_best_practices.html#content-organization]中是這樣建議的:
Your usage of Ansible should fit your needs, however, not ours, so feel free to modify this approach and organize as you see fit.
One crucial way to organize your playbook content is Ansible’s “roles” organization feature, which is documented as part of the main playbooks page. You should take the time to read and understand the roles documentation which is available here: Roles.
Ansible 整體的目錄結構沒有一定之規,适合你的目前需求就好。但是 Roles 這個概念至關重要。
良心的 Ansible 官方在 Github 上開了一個項目 ansible-examples[https://github.com/ansible/ansible-examples]專門用來收集優秀的最佳實踐。大家可以根據實際需求吸收借鑒,下面我分享一下我常用的項目布局:
Makefile,用來封裝 Ansible 的釋出指令
deploy.ym,是執行 Ansible 指令時的入口檔案
files,用來存放 role 相關的部署包,一般體積較大,不會使用 git 進行版本管理。
inventories,用來管理部署機器。
roles,用來部署的元件。從上面的目錄可知,目前主要是用來部署大資料相關的元件。
給自己打個小廣告:在下一個實戰章節将使用這個項目布局釋出大資料項目,在這個過程中又需要補充哪些 Ansible 的知識呢?為什麼我不直接使用 Galaxy 網站上的 role 而是要自己從頭開發呢?在部署 Hadoop3、Flink 項目中,使用 Ansible 又踩了哪些坑呢?
敬請期待 《進擊的 Ansible(三):Ansible 大資料實踐》
參考資料
使用 Ansible 傳輸檔案的幾種方式:
https://zdyxry.github.io/2019/11/22/使用-Ansible-傳輸檔案的幾種方式/
Ansible:
https://gist.github.com/MrNice/89a3bbe44e218c9d2309
Roles:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#id2
Galaxy User Guide:
https://docs.ansible.com/ansible/2.5/reference_appendices/galaxy.html
約定優于配置:
https://zh.wikipedia.org/wiki/約定優于配置
一文讀懂浏覽器存儲與緩存機制
Python Type Hints 從入門到實踐