編寫和運行 Playbook
Playbook 介紹
adhoc 命令可以作為一次性命令對一組主機運行一項簡單的任務。不過,若要真正發揮Ansible的能力,需要使用功能 playbook。
playbook 是一個文本文件,其中包含由一個或多個按特定順序運行的play組成的列表。play是針對清單中選定的主機運行的一組有序任務。play可以讓您將一系列冗長而復雜的手動管理任務轉變為可輕松重復的例程,并且具有可預測性。
在 playbook 中,您可以將play內的任務序列保存為人類可讀并可立即運行的形式。根據任務的編寫方式,任務本身記錄了部署應用或基礎架構所需的步驟。
ad hoc 命令示例:
[root@controller ~ 15:54:05]# ansible -m user -a "name=new
Playbooks以yaml格式編寫,通常以 yaml 和 yml 擴展名保存。
改寫成playbook:
---
- name: Configure important user consistentlyhosts: node1tasks:- name: newbie exists with UID 4000user:name: newbieuid: 4000state: present
...
- name: Configure important user consistently
- 這是一個 Play 的起始行,
-
表示這是列表中的一個項 name
參數用于給這個 Play 定義一個描述性名稱,說明該 Play 的功能是 “持續標準化配置重要用戶”
- 這是一個 Play 的起始行,
hosts: node1
hosts
參數指定該 Play 要在哪些目標主機上執行- 這里設置為
node1
,表示只在名為node1
的主機上運行后續任務 - 縮進表示這是上一行 Play 的屬性
tasks:
tasks
關鍵字標志著任務列表的開始- 后續縮進的內容都是要在目標主機上執行的具體任務
- 縮進表示這是上一行 Play 的屬性
- name: newbie exists with UID 4000
-
表示這是任務列表中的一個任務name
參數給這個具體任務定義名稱,說明任務是 “確保 newbie 用戶存在且 UID 為 4000”- 比上一行多一級縮進,表示這是
tasks
列表中的項
user:
- 指定該任務要使用的 Ansible 模塊為
user
模塊(用于管理系統用戶) - 縮進表示這是上一行任務的屬性
- 指定該任務要使用的 Ansible 模塊為
name: newbie
name
是user
模塊的參數,指定要操作的用戶名為newbie
- 縮進表示這是
user
模塊的參數
uid: 4000
uid
是user
模塊的參數,指定該用戶的 UID(用戶 ID)為 4000- 縮進表示這是
user
模塊的參數
state: present
state
是user
模塊的參數,present
表示確保該用戶存在(如果不存在則創建)- 縮進表示這是
user
模塊的參數
...
- YAML 格式中,
...
表示文檔結束符,是可選的結束標記
- YAML 格式中,
yaml格式只使用空格縮進,對于空格的數量沒有強制要求。
基本規則:
- 同一級別的元素,使用相同的縮進。
- 對于子項目,使用比父項目更多的縮進。
- 增加空白行,提高可讀性。
Vim 編輯器設置
如果使用vim編輯器,設置vim環境便于編輯Playbooks。
在$HOME/.vimrc文件中添加以下內容:
set ai ts=2
效果:
- “ai”,即 “autoindex”,表示自動縮進。
- “ts”,即 “tabstop”,表示tab鍵使用2個空格代替。
- autocmd FileType yam,代表文件類型是yaml時,自動執行“set ai ts=2”。
Playbook 編寫
Playbook 示例
playbook.yaml 內容如下:
# yaml格式起始行,一般不省略
---# Playbook中第一個play
# play具有屬性:name,hosts,become,tasks,縮進一致
# name屬性,用于簡要描述play
- name: Enable intranet services# hosts屬性,用于定義要在哪個受管理節點執行hosts: node1# tasks屬性,用于描述play中任務,屬性是列表格式tasks:# 第一個任務# 任務具有屬性:涵name和模塊名等。# name屬性,用于簡要描述任務- name: latest version of httpd and firewalld installed# 指明模塊名,也就是要執行的任務yum:# 執行要操作的rpm包名稱name:# rpm包名稱是-開頭的列表格式,或者逗號分隔的列表格式- httpd- firewalld# 定義軟件包的狀態,lastet代表升級為最新版本state: latest# 第二個任務- name: test html page is installed# copy模塊,用于將content屬性值寫入到目標文件copy:content: "Welcome Laoma WebSite!\n"dest: /var/www/html/index.html# 第三個任務- name: firewalld enabled and running# service模塊,用于啟用并啟動firewalld服務service:name: firewalldenabled: truestate: started# 第四個任務- name: firewalld permits access to httpd service# firewalld,用于放行http服務firewalld:service: httppermanent: truestate: enabledimmediate: yes# 第五個任務- name: httpd enabled and running# service模塊,用于啟用并啟動httpd服務service:name: httpdenabled: truestate: started# Playbook中第二個play,-開頭表示列表
- name: Test intranet web serverhosts: localhostbecome: notasks:- name: connect to intranet web server# uri模塊,用于測試網站是否可以訪問uri:url: http://node1return_content: yesstatus_code: 200# yaml格式結束行,一般省略
...
YAML 注釋
在 YAML中, 編號或井號符號(#)右側的所有內容都是注釋。如果注釋的左側有內容, 請在該編號符號的前面加一個空格。注釋可用于提高可讀性。
YAML 單行字符串
YAML中的字符串通常不需要放在引號里,即使字符串中包含空格。
字符串也可以用雙引號或單引號括起。
YAML 多行字符串
-
可以使用豎線(I)字符表示,保留字符串中的換行字符。
-
也可以使用大于號(>)字符表示換行字符。執行時換行符使用空格代替,并且行內的引導空白將被刪除。
YAML 字典
可以把 YAML 字典想象成一個 “多層抽屜柜”:
- 最外層是一個大柜子(整個 YAML 文檔),柜子上貼著標簽(鍵),比如 “person”“company”。
- 打開柜子,里面可能有小抽屜(子字典),每個小抽屜也有自己的標簽,比如 “person” 柜子里有 “name”“age” 抽屜。
- 每個抽屜里裝著具體的東西(值):“name” 抽屜里放著 “Alice”,“age” 抽屜里放著 “30”。
- 要是某個抽屜標簽后面跟著 “:” 再換行縮進,就像 “拉開抽屜看到里面還有小格子”,比如 “address” 抽屜里還有 “city”“street” 這些更小的格子。
一組鍵值對的集合,又稱為映射(mapping)和哈希(hashes)。
以縮進塊的形式編寫鍵值對集合,如下方所示:user屬性是字典格式,是多個鍵值對集合。
user:name: laoma uid: 1088state: absent
字典也可以使用以花括號括起的內聯塊格式編寫,如下方所示:
user: {name: laoma, uid: 1088, state: absent}
YAML 字典的基本語法規則:
- 鍵和值之間用冒號
:
分隔,冒號后必須有空格(key: value
) - 通常使用縮進來表示層級關系(推薦 2 個空格,不建議用制表符)
- 字典可以嵌套,形成復雜的數據結構
基礎示例
# 簡單字典
person:name: Aliceage: 30is_student: false
等價于 Python 字典:
{"person": {"name": "Alice","age": 30,"is_student": False}
}
行內式字典
也可以在一行內定義字典,用花括號 {}
包裹,鍵值對之間用逗號 ,
分隔:
person: { name: Bob, age: 25, is_student: true }
嵌套字典
字典的值可以是另一個字典,形成多層結構:
company:name: Tech Corpaddress:city: Beijingstreet: Main Road 123zipcode: 100000departments:- name: HRcount: 5- name: ITcount: 20
(注:-
表示列表項,字典可以和列表結合使用)
在 Ansible 中的應用
你之前看到的 Ansible Playbook 就是典型的 YAML 字典結構:
- name: Configure user # 列表項(Play)hosts: node1 # Play 的鍵值對tasks: # Play 的鍵值對,值是一個列表- name: Create user # 任務列表項user: # 任務的鍵,值是一個字典name: newbie # user 模塊的參數(鍵值對)uid: 4000
這里的 hosts: node1
、user: {name: newbie, uid: 4000}
都是字典鍵值對的體現。
YAML 字典的核心是 “鍵值對應”,通過縮進和冒號來清晰表達數據之間的關系,這也是它在配置文件(如 Ansible、Docker Compose 等)中被廣泛使用的原因
YAML 列表
一組按次序排列的值,又稱為序列(sequence)和數組(array)。
以縮進塊的形式編寫的鍵值對集合,如下方所示:
- name: latest version of httpd and firewalld installedyum:name:- httpd- firewalldstate: latest
- name: test html page is installedcopy:content: "Welcome to the example.com intranet!\n"dest: /var/www/html/index.html
以上有兩個任務,每個任務都是多個鍵值對描述。其中yum模塊操作的軟件包是一個簡單的名稱列表。
內聯格式:
name: [httpd, firewalld]
盡量避免內聯格式。
可以把 YAML 列表想象成 “一串帶編號的收納盒”,或者 “排隊的隊伍”—— 每個盒子 / 隊伍里的人都是獨立的,但都屬于同一串 / 同一隊,沒有專屬名字(不像字典的 “鍵”),只能靠 “位置” 來區分。
比如你去超市買水果,裝了一袋蘋果、一串葡萄、一個橙子,這袋水果就是一個列表:里面每樣水果都是獨立項,按順序排著,要找葡萄就知道是 “袋子里的第二個”。
1. 基礎樣子:用 “-” 開頭的 “隊伍”
YAML 里用 -
(減號 + 空格)表示列表里的一個項,所有項對齊縮進,就像隊伍站成一列:
# 水果列表
fruits:- apple # 第1項:蘋果- grape # 第2項:葡萄- orange # 第3項:橙子
就像在 “fruits” 這個袋子里,按順序放了蘋果、葡萄、橙子三個獨立的水果,沒有誰屬于誰,只是 “湊在一起的一組東西”。
2. 列表里也能裝 “抽屜柜”(嵌套字典)
列表的每個項不只能是簡單的文字,還能裝之前說的 “字典抽屜柜”。比如記錄幾個人的信息,每個人都是一個 “抽屜柜”,再把這些 “抽屜柜” 排成一隊:
# 人員列表(每個項是一個字典)
people:- name: Alice # 第1個人的抽屜柜age: 30- name: Bob # 第2個人的抽屜柜age: 25- name: Charlie# 第3個人的抽屜柜age: 35
這就像 “people” 這個隊伍里,站了三個帶抽屜的人:第一個人(Alice)的抽屜里有 “name”“age”,第二個人(Bob)也有自己的抽屜,互不干擾,只按排隊順序區分。
3. 一行寫完的 “緊湊隊伍”
如果列表項少,也能像 “擠在一起排隊” 一樣寫在一行,用方括號 []
把所有項包起來,項之間用逗號隔開:
# 一行式列表
colors: [red, green, blue] # 相當于:- red; - green; - blue
4. 在 Ansible 里的實際用法
你之前看的 Playbook 里,tasks
就是一個列表 —— 要執行的多個任務,按順序排成一隊:
tasks:- name: 確保newbie用戶存在 # 第1個任務(列表項)user:name: newbie- name: 給newbie加sudo權限 # 第2個任務(列表項)copy:src: sudoers.d/newbiedest: /etc/sudoers.d/
這就像 “任務清單”,先做 “創建用戶”,再做 “加 sudo 權限”,按列表順序一個接一個執行,沒有跳過的道理。
總結來說,YAML 列表的核心就是 “按順序排的一組東西”,不管里面裝的是簡單文字,還是復雜的 “字典抽屜柜”,都靠 -
標識 “這是隊伍里的一個”,靠順序確定 “先誰后誰”。
Playbook 運行
[yy@controller ~ 16:16:47 web]$ ansible-playbook playbook.yaml
第一次執行劇本,任務狀態全是黃色。
第二次執行劇本,任務狀態全是綠色。
語法檢查
選項–syntax-check,只檢查劇本語法,不執行劇本。
ansible-playbook playbook.yaml --syntax-check
空運行
空運行,是指模擬運行,并不是真正執行。
ansible-playbook playbook.yaml -C
提高輸出詳細程度
- -v,顯示任務結果。一般情況使用 -v 即可。
- -vv,任務結果和任務配置都會顯示。
- -vvv,包含關于與受管主機連接的信息。
- -vvvv,增加了連接插件相關的額外詳細程度選項,包括受管主機上用于執行腳本的用戶,以及所執行的腳本。
Playbook 提權
在playbook中指定此關鍵字將覆蓋/etc/ansible/ansible.cfg文件中的設置特權升級屬性
-
remote_user,指定ssh用戶
-
become,啟用或禁用特權升級
-
become_method,啟用特權升級的方法
-
become_user,特殊升級的帳戶
---
- name: Enable intranet serviceshosts: node1remote_user: laomabecome: truebecome_method: sudobecome_user: roottasks:- name: latest version of httpd and firewalld installedyum:name:- httpd- firewalldstate: latest
在 Ansible 中,Playbook 提權主要是通過become
關鍵字來實現的,它可以讓任務以另一個用戶(通常是root
)的身份執行。以下是具體的提權方法:
- 任務級提權:只在需要提權的任務上加上
become: yes
。例如:
- name: 需要root權限的任務copy:src: app.confdest: /etc/app.confbecome: yes
- Play 級提權:在
hosts
同級加上become: yes
,則這個 Play 里的所有任務都會默認提權。示例如下:
- name: 提權示例hosts: allbecome: yestasks:- name: 安裝軟件包apt:name: nginxstate: present
- 命令行提權:運行 playbook 時加上
-b
或--become
參數,優先級最高,可以臨時強制提權,適合調試或一次性任務。如ansible -playbook my_playbook.yml --become
。
此外,還有一些與提權相關的指令:
become_method
:用于指定提權方法,默認是sudo
。對于 Windows 系統是runas
,網絡設備(交換機、路由器等)是enable
,容器則可使用machinectl
。例如,當管理網絡設備時,需設置become_method: enable
。become_flags
:可給提權命令添加額外參數。比如使用su
命令提權時,若需要切換環境變量,可設置become_flags: '--login'
。--ask - become - pass
或-K
:運行 playbook 時,如果提權需要輸入密碼,可用這個參數讓 Ansible 提示輸入密碼,以確保安全。
想象一下,Ansible Playbook 就像一個 “辦事員”,平時只能做些普通權限的活兒(比如整理自己抽屜里的文件)。但有時候需要處理重要文件(比如修改系統配置、安裝軟件),這些活兒普通權限干不了,得有 “管理員” 身份才行。
“提權” 就像是給這個辦事員開了張 “臨時通行證”:
- 任務級提權:就像特定事情才亮通行證 —— 比如 “只有給 /etc 目錄拷貝文件時,才用管理員身份”
- Play 級提權:相當于全天通行證 ——“今天所有活兒都用管理員身份干”
- 命令行提權:好比臨時加急授權 ——“這次特殊情況,強制用管理員身份處理”
而 become_method 就像通行證的類型:用 sudo 是 “找 sudo 管理員簽字”,用 su 是 “直接切換成管理員本人”,給網絡設備提權則是 “申請進入特權模式”。
簡單說,提權就是讓 Playbook 在需要時 “穿上管理員的馬甲”,干完活兒再脫下來,既安全又高效