第三十七天:Ansible playbook基礎

djyhello發表於2024-03-26
一、 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

相關文章