一、 playbook介紹
1、Playbook 組成
一個 playbook(劇本)檔案是一個YAML語言編寫的文字檔案
通常一個playbook只包括一個play
一個 play的主要包括兩部分: 主機和tasks. 即實現在指定一組主機上執行一個tasks定義好的任務列表。
一個tasks中可以有一個或多個task任務
每一個Task本質上就是呼叫ansible的一個module
在複雜場景中,一個playbook中也可以包括多個play,實現對多組不同的主機執行不同的任務
2、Playbook 與 Ad-Hoc 對比
Playbook是對多個 AD-Hoc 的一種編排組合的實現方式
Playbook能控制任務執行的先後順序
Playbook可以持久儲存到檔案中從而方便多次呼叫執行,而Ad-Hoc只能臨時執行。
Playbook適合複雜的重複性的任務,而Ad-Hoc適合做快速簡單的一次性任務
二、YAML 語言
1、YAML 語言介紹
YAML:YAML Ain't Markup Language,即YAML不是標記語言。不過,在開發的這種語言時,YAML的意思其實是:"Yet Another Markup Language"(仍是一種標記語言)
YAML是一個可讀性高的用來表達資料序列的格式。
YAML參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822等。
Clark Evans在2001年在首次發表了這種語言,另外Ingy döt Net與Oren Ben-Kiki也是這語言的共同設計者
目前很多最新的軟體比較流行採用此格式的檔案存放配置資訊,如:ubuntu,anisble,docker,kubernetes等
YAML 官方網站:
http://www.yaml.org
2、YAML 語言特性
YAML的可讀性好
YAML和指令碼語言的互動性好
YAML使用實現語言的資料型別
YAML有一個一致的資訊模型
YAML易於實現
YAML可以基於流來處理
YAML表達能力強,擴充套件性好
3、YAML語法簡介
在單一檔案第一行,用連續三個連字號"-" 開始,還有選擇性的連續三個點號( ... )用來表示檔案的結尾
次行開始正常寫Playbook的內容,一般建議寫明該Playbook的功能
使用#號註釋程式碼
縮排的級別也必須是一致的,同樣的縮排代表同樣的級別,程式判別配置的級別是透過縮排結合換行來實現的
縮排不支援tab,必須使用空格進行縮排
縮排的空格數不重要,只要相同層級的元素左對齊即可
YAML檔案內容是區別大小寫的,key/value的值均需大小寫敏感
多個key/value可同行寫也可換行寫,同行使用,分隔
key後面冒號要加一個空格 比如: key: value
value可是個字串,也可是另一個列表
YAML副檔名通常為yml或yaml
4、支援的資料型別
YAML 支援以下常用幾種資料型別:
標量:單個的、不可再分的值
物件:鍵值對的集合,又稱為: 字典(dictionary)/ 雜湊(hashes) / 對映(mapping)
陣列:一組按次序排列的值,又稱為: 列表(list)/ 序列(sequence)
(1)scalar 標量
key對應value
name: wang age: 18
使用縮排的方式
name: wang age: 18
(2)Dictionary 字典
一個字典是由一個或多個key與value構成
key和value之間用冒號 :分隔
冒號 : 後面有一個空格
所有 k/v 可以放在一行,,每個 k/v 之間用逗號分隔
所有每個 k/v 也可以分別放在不同行,一對k/v放在獨立的一行
格式
account: { name: wang, age: 30 }
使用縮排方式
account: name: wang age: 18
(3)List 列表
列表由多個元素組成
每個元素放在不同行,每個元素一行,且元素前均使用中橫線 - 開頭,並且中橫線 - 和元素之間有一個空格
也可以將所有元素用 [ ] 括起來放在同一行,每個元素之間用逗號分隔
格式
course: [ linux , golang , python ]
也可以寫成以 - 開頭的多行
- linux - golang - pytho
5、三種常見的資料格式
XML:Extensible Markup Language,可擴充套件標記語言,可用於資料交換和配置
JSON:JavaScript Object Notation, JavaScript 物件表記法,主要用來資料交換或配置,不支援註釋
YAML:YAML Ain't Markup Language YAML 不是一種標記語言, 主要用來配置,大小寫敏感,不支援tab
可以用工具互相轉換,參考網站:
https://www.json2yaml.com/
http://www.bejson.com/json/json2yaml/
三、Playbook 核心元件
官方文件
https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords. html#playbook-keywords
一個playbook 中由多個元件組成,其中所用到的常見元件型別如下:
Hosts 執行的遠端主機列表
Tasks 任務集,由多個task的元素組成的列表實現,每個task是一個字典,一個完整的程式碼塊功能需最少元素需包括 name 和 task,一個name只能包括一個task
Variables 內建變數或自定義變數在playbook中呼叫
Templates 模板,可替換模板檔案中的變數並實現一些簡單邏輯的檔案
Handlers 和 notify 結合使用,由特定條件觸發的操作,滿足條件方才執行,否則不執行
tags 標籤 指定某條任務執行,用於選擇執行playbook中的部分程式碼。ansible具有冪等性,因此會自動跳過沒有變化的部分,即便如此,有些程式碼為測試其確實沒有發生變化的時間依然會非常地長。此時,如果確信其沒有變化,就可以透過tags跳過此些程式碼片斷
1、hosts 元件
Hosts:playbook中的每一個play的目的都是為了讓特定主機以某個指定的使用者身份執行任務。hosts
用於指定要執行指定任務的主機,須事先定義在主機清單中
one.example.com one.example.com:two.example.com 192.168.1.50 192.168.1.* Websrvs:dbsrvs #或者,兩個組的並集 Websrvs:&dbsrvs #與,兩個組的交集 webservers:!dbsrvs #在websrvs組,但不在dbsrvs組
2、remote_user 元件
remote_user: 可用於Host和task中。也可以透過指定其透過sudo的方式在遠端主機上執行任務,其可用於play全域性或某任務;此外,甚至可以在sudo時使用sudo_user指定sudo時切換的使用者
- hosts: websrvs remote_user: root tasks: - name: test connection ping: remote_user: magedu sudo: yes #預設sudo為root sudo_user:wang #sudo為wang
3、task列表和action元件
play的主體部分是task list,task list中有一個或多個task,各個task 按次序逐個在hosts中指定的所有主機上執行,即在所有主機上完成第一個task後,再開始第二個task
task的目的是使用指定的引數執行模組,而在模組引數中可以使用變數。模組執行是冪等的,這意味著多次執行是安全的,因為其結果均一致
每個task都應該有其name,用於playbook的執行結果輸出,建議其內容能清晰地描述任務執行步驟。
如果未提供name,則action的結果將用於輸出
task兩種格式:
action: module arguments #示例: action: shell wall hello
module: arguments #建議使用 #示例: shell: wall hello
注意:shell和command模組後面跟命令,而非key=value
4、其它元件說明
某任務的狀態在執行後為changed時,可透過"notify"通知給相應的handlers任務
還可以透過"tags"給task 打標籤,可在ansible-playbook命令上使用-t指定進行呼叫
四、playbook 命令
格式
ansible-playbook <filename.yml> ... [options]
常見選項
--syntax,--syntax-check #語法檢查,功能相當於bash -n -C --check #模擬執行dry run ,只檢測可能會發生的改變,但不真正執行操作 --list-hosts #列出執行任務的主機 --list-tags #列出tag --list-tasks #列出task --limit 主機列表 #只針對主機列表中的特定主機執行 -i INVENTORY, --inventory INVENTORY #指定主機清單檔案,通常一個項對應一個主機清單檔案 --start-at-task START_AT_TASK #從指定task開始執行,而非從頭開始,START_AT_TASK為任務的 name -v -vv -vvv #顯示過程
五、Playbook 案例
1、利用 playbook 建立 mysql 使用者
--- - hosts: dbsrvs remote_user: root gather_facts: no tasks: - {name: create group, group: name=mysql system=yes gid=306} - name: create user user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no
2、利用 playbook 安裝 nginx
--- # install nginx - hosts: websrvs remote_user: root gather_facts: no tasks: - name: add group nginx group: name=nginx state=present - name: add user nginx user: name=nginx state=present group=nginx - name: Install Nginx yum: name=nginx state=present - name: web page copy: src=files/index.html dest=/usr/share/nginx/html/index.html - name: Start Nginx service: name=nginx state=started enabled=yes
3、利用 playbook 安裝和解除安裝 httpd
[root@centos8 ansible]#cat install_httpd.yml --- #install httpd - hosts: websrvs remote_user: root gather_facts: no tasks: - name: Instal1 httpd yum: name=httpd - name: Modify config list port lineinfile: path: /etc/httpd/conf/httpd.conf regexp: '^Listen' line: 'Listen 8080' - name: Modify config data1 lineinfile: path: /etc/httpd/conf/httpd.conf regexp: '^DocumentRoot "/var/www/html"' line: 'DocumentRoot "/data/html"' - name: Modify config data2 lineinfile: path: /etc/httpd/conf/httpd.conf regexp: '^<Directory "/var/www/html">' line: '<Directory "/data/html">' - name: Mkdir website dir file: path=/data/html state=directory - name: Web html copy: src=files/index.html dest=/data/html/ - name: Start service service: name=httpd state=started enabled=yes ansible-playbook install_httpd.yml --limit 10.0.0.8
4、忽略錯誤 ignore_errors
如果一個task出錯,預設將不會繼續執行後續的其它task
利用 ignore_errors: yes 可以忽略此task的錯誤,繼續向下執行playbook其它task
[root@ansible ansible]#cat test_ignore.yml --- - hosts: websrvs tasks: - name: error command: /bin/false ignore_errors: yes - name: continue command: wall continue
5、Playbook中使用handlers和notify
(1)handlers和notify
Handlers本質是task list ,類似於MySQL中的觸發器觸發的行為,其中的task與前述的task並沒有本質上的不同,只有在關注的資源發生變化時,才會採取一定的操作。
Notify對應的action 在所有task都執行完才會最後被觸發,這樣可避免多個task多次改變發生時每次都觸發執行指定的操作,Handlers僅在所有的變化發生完成後一次性地執行指定操作。
在notify中列出的操作稱為handler,也即notify中呼叫handler中定義的操作
注意:
如果多個task通知了相同的handlers, 此handlers僅會在所有task結束後執行一 次。
只有notify對應的task發生改變了才會通知handlers, 沒有改變則不會觸發handlers
handlers 是在所有前面的tasks都成功執行才會執行,如果前面任何一個task失敗,會導致handler跳過執行
(2)force_handlers
如果不論前面的task成功與否,都希望handlers能執行, 可以使用force_handlers: yes 強制執行handler
範例: 強制呼叫handlers
- hosts: websrvs force_handlers: yes #無論task中的任何一個task失敗,仍強制呼叫handlers tasks: - name: config file copy: src=nginx.conf dest=/etc/nginx/nginx.conf notify: restart nginx - name: install package yum: name=no_exist_package handlers: - name: restart nginx service: name=nginx state=restarted
六、Playbook中使用tags元件
預設情況下, Ansible 在執行一個 playbook 時,會執行 playbook 中所有的任務
在playbook檔案中,可以利用tags元件,為特定 task 指定標籤,當在執行playbook時,可以只執行特定tags的task,而非整個playbook檔案
可以一個task對應多個tag,也可以多個task對應同一個tag
還有另外3個特殊關鍵字用於標籤, tagged, untagged 和 all,它們分別是僅執行已標記,只有未標記和所有任務。
tags 主要用於除錯環境
vim httpd.yml --- # tags example - hosts: websrvs remote_user: root gather_facts: no tasks: - name: Install httpd yum: name=httpd state=present - name: Install configure file copy: src=files/httpd.conf dest=/etc/httpd/conf/ tags: [ conf,file ] #寫在一行 - conf #寫成多行 - file - name: start httpd service tags: service service: name=httpd state=started enabled=yes #列出標籤 [root@ansible ~]#ansible-playbook --list-tags httpd.yml #執行有指定標籤的任務 [root@ansible ~]#ansible-playbook -t conf,service httpd.yml #忽略執行指定標籤的task [root@ansible ~]#ansible-playbook --skip-tags conf httpd.yml #忽略執行沒有標籤的任務,即只執行有標籤的任務 [root@ansible ~]#ansible-playbook httpd.yml --skip-tags untagged