ansible-playbook(3)


我叫張賀,貪財好色。一名合格的LINUX運維工程師,專注於LINUX的學習和研究,曾負責某中型企業的網站運維工作,愛好佛學和跑步。
個人博客:傳送陣
筆者微信:zhanghe15069028807,非誠勿擾。

ansible-playbook其實就是把ad-hoc寫成腳本的方式,一定要注意格式,playbook的格式非常嚴格

一、playbook基礎

語法

縮進:使用固定的網絡表示層級結構,每個縮進兩個空格,不能用tab

冒號:以冒號結尾除外,其他的冒號后面必須要有空格

短橫線:表示列表項,使用一個短橫加一個空格,多個項使用同樣的縮進級別作為同一列表

模塊在描述的下面就行,不能同級或超過,我們最好用兩個空格

示例

//示例
[root@ansible ansible]# vim test1.yml
- hosts: nfs   #頂格杠,空格,hosts,冒號,空格,nfs
  tasks:   #開頭兩空格
    - name: Install NFS  #四空格
      yum: name=nfs-utils state=present  #六個空格

    - name: Copy File exports
      copy: src=/root/exports.template dest=/etc/exports

    - name: Start Nfs Server
      service: name=nfs-server state=started enabled=yes

//語法檢查
[root@ansible ansible]# ansible-playbook --syntax-check test1.yml
playbook: test1.yml

//模擬執行
[root@ansible ansible]# ansible-playbook -C test1.yml  #+C模擬執行

//正式執行
[root@ansible ansible]# ansible-playbook test2.yml  #這樣才會執行

PLAY [nfs] **************************************************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************************************
ok: [192.168.80.188]

TASK [Create New File] **************************************************************************************************************************
changed: [192.168.80.188]

PLAY RECAP **************************************************************************************************************************************
192.168.80.188             : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

示例2

一個play單個任務

[root@ansible ansible]# vim test2.yml

- hosts: nfs
  tasks:
    - name: Create New File
      file: path=/tmp/test.txt state=touch owner=root group=root mode=400
      
//檢查語法,如果什么都不提示,那就說明沒有錯誤
[root@ansible ansible]# ansible-playbook --syntax-check test2.yml   
playbook: test2.yml  #只檢查語法,不會檢測內容

一個play多個任務

[root@ansible ansible]# cat test2.yml 
- hosts: nfs
  tasks:
    - name: Create New File
      file: path=/tmp/test.txt state=touch owner=root group=root mode=400

    - name: Create New Directory
      file: path=/tmp/oldboy_dir state=directory owner=root group=root mode=700

多個play,多個任務(不建議這樣用,建立多建一個文件)

[root@ansible ansible]# cat test2.yml
- hosts: nfs
  tasks:
    - name: Create New File
      file: path=/tmp/test.txt state=touch owner=root group=root mode=400

    - name: Create New Directory
      file: path=/tmp/oldboy_dir state=directory owner=root group=root mode=700

- hosts: web
  tasks:
    - name: Create Web New File
      file: path=/opt/test.txt owner=root group=root mode=400 state=touch

    - name: Create Web New Directory
      file: path=/opt/oldboy_dir state=directory owner=root group=root mode=700
[root@ansible ansible]# ansible-playbook --syntax-check test2.yml 

playbook: test2.yml

二、playbook變量

變量定義

像上面,我們寫的腳本太長了,關鍵是因為路徑太長了,我們可以把路徑定義到變量,然后下面再引用, 這樣就好看多了。

變量的定義有三種方式:

  • 在playbook文件里面定義;

  • 外部定義,然后傳進來;

  • 在hosts主機清單里面定義

  • 單獨定義一個變量文件

在playbook文件里面定義:

[root@ansible ansible]# vim test2.yml    #路徑變量
- hosts: nfs
  vars:                             #這里定義了一個變量
    file_name: /tmp/tt
  tasks:
    - name: Create New File
      file: path={{ file_name }} state=touch owner=root group=root mode=400   #在這里引用了一下,雙花括號,兩邊有空格,注意這個格式

    - name: Create New Directory        #在name里面也可以引用變量,在執行的時候也會翻譯出來
      file: path=/tmp/tt.dir state=directory owner=root group=root mode=700

主機清單里面定義:

[root@ansible ansible]# cat hosts      #在主機清單里面的web再定一個同樣的變量
[web]
192.168.80.166
[web:vars]                               #注意這個格式,很少在這里定義,知道即可
file_name=temp.hosts

外部定義

 //執行的時候會有一個報警,提示讓你不要用shell模塊 
 [root@ansible ansible]# ansible-playbook test4.yml --extra-vars "file_name=temp_extra"   

在web上查看,外置優先生效,共次是playbook生效,最后才是主機清單生效

單獨用一個文件定義

[root@ansible ansible]# cat vars.yml 
file_name: temp.vars
[root@ansible ansible]# cat test4.yml 
- hosts: web
  vars_files:                          #用關鍵字引用一下,在大型項目當中很常見
    ./vars.yml
  tasks:
    - name: Create New File name:{{ file_name }}
      file: name=/opt/{{ file_name }} state=touch

變量注冊

假設我想在ansible上通過playbook查看web服務器當中開了哪些端口,怎么寫呢?先寫一個簡單的,如下所示:

[root@ansible ansible]# cat test5.yml
---
- hosts: web
  tasks:
    - name: show "ss -tnlp"
      shell: ss -tnlp
[root@ansible ansible]# ansible-playbook test5.yml    #並沒有輸出結果,只是顯示執行成功了。。

沒有輸入結果,只是顯示執行成功了,那怎么辦呢?其實方法很簡單,就將結果賦值給一個變量,然后我們把變量打印出來就好了,如下所示:

[root@ansible ansible]# cat test5.yml
---
- hosts: web
  tasks:
    - name: show "ss -tnlp"
      shell: ss -tnlp | grep 22
      register: Net_Status            #將結果保存在Net_Status變量當中

    - name: Output Status
      debug: msg={{ Net_Status }}    #debug模塊用於輸出函數

下面這是輸出,通過輸出我們看到還是比較亂的:

我們可以僅將標准輸出打印出來,別的東西都不要打印了,就在debug模塊后面的變量當中加一個stdout即可,如下所示:

[root@ansible ansible]# cat test5.yml
---
- hosts: web
  tasks:
    - name: show "ss -tnlp"
      shell: ss -tnlp | grep 22
      register: Net_Status

    - name: Output Status
      debug: msg={{ Net_Status.stdout }}    #加在了這里

下面是輸出,沒有那么難看復雜了,但還是看着有點難看,如下所示:

再加一個按行顯示:

[root@ansible ansible]# cat test5.yml 
---
- hosts: web
  tasks:
    - name: show "ss -tnlp"
      shell: ss -tnlp | grep 22
      register: Net_Status

    - name: Output Status
      debug: msg={{ Net_Status.stdout_lines }}    #debug不是調試的意思,而是輸出的意思

用到什么地方呢?我們在啟動服務了之后,用這種方法檢查端口是否起來了

三、條件語句

playbook中的條件判斷用when

[root@ansible ansible]# ansible nfs -m setup #在ansible上取其它主機的變量
[root@ansible ansible]# vim test6.yml 
---
- hosts: all
  tasks:
  - name: Create a File
    file: path=/tmp/this_is_{{ ansible_hostname }} state=touch
    when: (ansible_hostname == 'BACKUP') or (ansible_hostname == 'web1')    #只有兩台主機才會執行

四、循環

假設說現在我們要安裝兩個軟件,給web1這個服務器上,怎樣用ansible-playbook寫呢?

[root@ansible ansible]# cat test7.yml     #安裝兩個軟件,這么寫有點亂,我們下面再換一種寫法
---
- hosts: web
  tasks:
    - name: Install Wget Tree
      yum: 
        name:
          - wget
          - tree
        state: present
[root@ansible ansible]# cat test8.yml    #這么寫看着舒服一點
---
- hosts: web
  tasks:
    - name: Install Wget Tree
      yum: name=wget,tree state=present

除了這兩種寫法,我們還可以使用循環的方式去寫:

[root@ansible ansible]# cat test9.yml
---
- hosts: web
  tasks:
    - name: Install Wget Tree
      yum: name={{ item }} state=present
      with_items:   #軟件可以專門用一個列表
        - wget
        - tree
---
- hosts: web
  remote_user: root
  tasks:
    - name: Add Users
      user: name={{ item.name }} groups={{ item.groups }} state=present
      with_items:
        - { name: 'test1',groups: 'bin' }
        - { name: 'test2',groups: 'root' }

五、異常處理

默認playbook會檢查命令和模塊的返回狀態,如果遇到錯誤就中斷執行,加入參數ignore_errors:yes會忽略錯誤,繼續向下執行。

[root@ansible ansible]# cat test8.yml   
---
- hosts: web
  tasks:
    - name: Ignore False
      command: /bin/false
      ignore_errors: yes
    
    - name: Service Nfs Server
      service: name=nfs-server state=started enabled=yes
      tags: start_nfs-server

六、打標記

假設說我們已經在playbook里面寫了20個任務,一執行在第15個報錯了,我們調試完了之后執行,又開始從頭開始執行,其實這樣沒有必要,我們只需要執行一下第15個就行了或者只需要從第15個之后開始執行,這就需要控制,這個控制就要通過打標記來實現。

[root@ansible ansible]# cat test8.yml   
---
- hosts: web
  tasks:
    - name: Install Nfs
      yum: name=nfs-utils state=present
      tags: install_nfs
    
    - name: Service Nfs Server
      service: name=nfs-server state=started enabled=yes
      tags: start_nfs-server
      
//正常執行
[root@ansible ansible]# ansible-playbook test8.yml

//使用-t指定tag執行,多個tag可以用逗號隔開
[root@ansible ansible]# ansible-playbook -t install_nfs test8.yml

//使用--skip-tags排除不執行的tags
[root@ansible ansible]# ansible-playbook --skip-tags install_nfs test8.yml

七、handlers

假如我們通過playbook給web更改了一個端口,更改端口當然是在配置文件里面更改,那么配置文件一更改,我們要通過cp模塊推送,推送過去之后因為當前目標服務已經是啟動狀態,並不會重啟,那你說我們直接在playbook里面寫一個重啟不就完了嗎?但是如果在playbook里面寫了重啟的話,以后每次觸發這個playbook都會重啟,這不合適,這時候就我們就需要通過notify模塊監控配置文件如果改變了的話,就會觸發handlers任務,如下所示:

[root@ansible ansible]# cat test8.yml   
---
- hosts: web
  tasks:
    - name: Install Httpd
      yum: name=httpd state=present
      tags: install_nfs
    
    - name: configure httpd
      copy: src=./httpd.conf.template dest=/etc/httpd/conf/httpd.conf backup=yes
      notify: Restart Httpd
      
    - name: Started Htttpd
      service: name=httpd state=started enabled=yes
     
  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted

八、template

上面我們是手工在ansible上面更改了httpd的配置文件的端口之后,然后推送到web,有沒有辦法使得我們不用手工更改,只需要在playbook里面定義一個變量,然后在在配置文件的端口的地方引用這個變量, 這時我們就要通過template模塊替換cp模塊,cp模塊是見什么推送什么,而template模塊就把配置文件里面的變量先翻譯過來,然后再推送到web端。

[root@ansible ansible]# cat test8.yml   
---
- hosts: web
#1、定義一個變量,在httpd的配置文件當中引用
  vars:
    http_port: 8080

#2.安裝httpd
  tasks:
    - name: Install Httpd
      yum: name=httpd state=present
      tags: install_nfs
      
#3、使用template模板,翻譯引用上述定義的變量    
    - name: configure httpd
      template: src=./httpd.conf.template dest=/etc/httpd/conf/httpd.conf backup=yes
      notify: Restart Httpd
      
#4、啟動httpd      
    - name: Started Htttpd
      service: name=httpd state=started enabled=yes
      
#5、檢查httpd的啟動和當前狀態
    - name: Get httpd status
      shell: netstat -tnlp|grep httpd
      register: Httpd_Port
 
#6、輸出變量到面板
    - name: output httpd status
      debug: msg={{ Httpd_Port.stdout_lines }}
      ignore_errors: yes
      
#7、如果配置文件發生變化會調用handlers下面的模板      
  handlers:
    - name: Restart Httpd
      service: name=httpd state=restarted
[root@ansible ansible]# vim ./httpd.conf.template
Listen {{ http_port }}

九、include

include是調用任務的方式,把多個playbook名字的引用到一個文件里面,這樣一執行這個文件,就會把引用到的所有的文件給執行了,如下所示:

[root@ansible ansible]# cat main.yml 
- hosts: all
  tasks:
    - include_tasks: test1.yml
    - include_tasks: test2.yml

[root@ansible ansible]# cat test1.yml 
- name: create file1
  command: touch file1
  
[root@ansible ansible]# cat test2.yml 
- name: create file2
  command: touch file2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM