Ansible:Ansibl项目生产环境快速布局
Tips:與前文 《進擊的 Ansible(一):Ansible 快速入門》 一樣,本文使用的 Ansible 版本 2.5.4,項目演示環境 MacOS。由于 Ansible 項目開發活躍版本更新快,很多 API 接口不向后兼容,所以對照本文實踐時請確保所用版本一致。
學完前文《進擊的 Ansible(一):Ansible 快速入門》后,用來發布單體項目綽綽有余。但是實際生產環境中一個服務往往有多個組件,比如部署大數據服務時,常常需要部署一個“大數據全家桶”:Hadoop、 Zookeeper、 Hive、 Mysql、 Flink 等。這時僅靠前文中的知識就有點捉襟見肘了,繁多的 yaml 文件和其他配置文件依賴關系復雜,如果不能正確地劃分目錄組織項目結構,對于后期維護非常不利。所以今天的文章著重解決一下這個問題:如何科學正確地劃分 Ansible 應用的目錄結構?
把 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 的定義,豐富一下細節:
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 角色有一個定義好的目錄結構,其中有八個主要的標準目錄。該已規定好的目錄結構,示例如下:
├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars└── main.ymlBy 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 這個項目的目錄結構大致如下:
? bigdata tree -L 3 . └── roles├── flink│ ├── defaults│ ├── files│ ├── handlers│ ├── meta│ ├── tasks│ ├── templates│ ├── tests│ └── vars├── hive│ ├── defaults│ ├── files│ ├── handlers│ ├── meta│ ├── tasks│ ├── templates│ ├── tests│ └── vars└── mysql├── defaults├── files├── handlers├── meta├── tasks├── templates├── tests└── vars很明顯可以看到 roles 下的 Flink、hive、Mysql 的子目錄結構就是上文中提到的八大目錄。
ansible-galaxy
快速創建 Role
從上文可知,每創建一個 role 都必須至少含有八大目錄之一。所以 Ansible 中已內置了一個命令行工具 ansible-galaxy 快速創建 role 的八大目錄,減輕我們的工作量。
假設該 role 名稱是 flink,用如下命令生成相關目錄:
ansible-galaxy init flink使用 tree 命令看到 ansible-galaxy 生成的目錄正是 role 所要求的標準的八個目錄。
? tree flink flink ├── README.md ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars└── main.ymlansible-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 install username.role_name默認情況下 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 網站
整體布局:Suit is best
如果你堅持讀完上述部分,那么你肯定對于如何使用 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 ├── README.md ├── deploy.retry ├── deploy.yml ├── files │ ├── apache-maven-3.8.3-bin.tar.gz │ ├── apache-zookeeper-3.7.0-bin.tar.gz │ ├── flink-1.14.0-bin-scala_2.11.tgz │ ├── hadoop-2.7.5.tar │ ├── hadoop-3.3.1.tar.gz │ ├── mysql-connector-java-8.0.26-1.el7.noarch.rpm │ ├── mysql-connector-java-8.0.26.jar │ └── openjdk-11.0.2_linux-x64_bin.tar.gz ├── inventories │ └── hosts └── roles├── flink├── hadoop├── hadoop3├── hive├── java├── linux├── mvn├── mysql└── zookeeper-
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/%E4%BD%BF%E7%94%A8-Ansible-%E4%BC%A0%E8%BE%93%E6%96%87%E4%BB%B6%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F/
- 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/%E7%BA%A6%E5%AE%9A%E4%BC%98%E4%BA%8E%E9%85%8D%E7%BD%AE
總結
以上是生活随笔為你收集整理的Ansible:Ansibl项目生产环境快速布局的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何让你的大文件上传变得又稳又快?
- 下一篇: 服务端渲染基础