天天看點

ansible之變量一、變量 variables二、變量實戰三、 Ansible Register五、Ansible Facts Variables六、 Ansible task control

文章目錄

  • 一、變量 variables
    • 1.1 什麼是變量
    • 1.2 定義變量的幾種方式
  • 二、變量實戰
    • 2.1 在playbook中定義變量
    • 2.2 在 vars_files 檔案中定義變量
    • 2.3 在Inventory中定義變量
      • 2.3.1 在Inventory檔案中定義變量
      • 2.3.2 使用host_vars定義變量
      • 2.3.3 使用group_vars定義變量
    • 2.4 通過執行Playbook傳遞變量
    • 2.5 變量的優先級
    • 2.6 nfs 服務端和用戶端實作變量方式寫法
  • 三、 Ansible Register
    • 3.1 什麼是Register
    • 3.2 register批量修改主機名稱
    • 3.3 使用register 完成jumpserver key 的建立
  • 五、Ansible Facts Variables
    • 5.1 什麼是facts Ansible
    • 5.2 facts 應用場景
    • 5.3 示例
    • 5.4 根據不同的ip位址生成不同的Redis配置檔案
    • 5.5 根據不同的主機cup數生成不同的nginx配置檔案
    • 5.6 根據主機記憶體生成Memcached配置
    • 5.6 批量修改主機名稱
    • 5.7 facts變量優化
  • 六、 Ansible task control
    • 6.1 when
      • 6.1.1 根據不同作業系統安裝相同的軟體
      • 6.1.2 為特定的主機添加Nginx倉庫
      • 6.1.3 判斷服務是否正常運作
      • 6.1.4 判斷是否安裝nginx 未按裝可以執行不同的操作,例如安裝nginx
    • 6.2 loop循環
      • 6.2.1 使用循環批量啟動服務與安裝軟體
      • 6.2.2 使用loop循環批量建立使用者
      • 6.2.3 使用loop循環copy檔案
    • 6.3.Handlers與Notify
    • 6.4 tags 任務标簽
    • 6.5 include任務複用
      • 6.5.1 多個項目同時需要重新開機nginx
      • 6.5.2 Inlcude結合tags應用 安裝tomcat
    • 6.7 Playbook異常處理
    • 6.8 change狀态
    • 6.9 changed_when檢查任務結果

一、變量 variables

1.1 什麼是變量

變量提供了便捷的方式來管理 ansible 項目中的動态值。 比如 nginx-1.12,可能後期會反複的使用到這個版本的值,那麼如果将此值設定為變量,後續使用和修改都将變得非常友善。

1.2 定義變量的幾種方式

  1. 通過指令行傳遞變量參數定義
  2. 在play檔案中定義變量

    2.1 通過vars定義變量

    2.2 通過vars_files定義變量

  3. 通過inventory在主機組或單個主機中設定變量

    3.1 通過host_vars對主機進行定義

    3.2 通過group_vars對主機組進行定義

二、變量實戰

2.1 在playbook中定義變量

在 playbook 的檔案中開頭通過 vars 關鍵字進行變量定義

[[email protected] playbook_vars]# cat playbook_vars1.yml 
- hosts: localhost
  vars:
    - web_server: httpd
    - nfs_server: nfs

  tasks:
    - name: Output vaiables
      debug:
        msg:
          - "{{ web_server }}"
          - "{{ nfs_server }}"




[[email protected] playbook_vars]# ansible-playbook playbook_vars1.yml 

PLAY [localhost] *****************************************************************************************************************************

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

TASK [Output vaiables] ***********************************************************************************************************************
ok: [localhost] => {
    "msg": [
        "httpd", 
        "nfs"
    ]
}

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


           

2.2 在 vars_files 檔案中定義變量

在 playbook 中使用 vars_files 指定檔案作為變量檔案,好處就是其他的 playbook 也可以調用;

ansible之變量一、變量 variables二、變量實戰三、 Ansible Register五、Ansible Facts Variables六、 Ansible task control

1.準備vars_file檔案

[[email protected] playbook_vars]# cat vars_file.yml 
web_server: httpd
nfs_serve: nfs 
           

2.在playbook中play階段調用

[[email protected] playbook_vars]# cat playbook_vars2.yml 
- hosts: localhost
  vars_files: ./vars_file.yml

  tasks:
    - name: Output vaiables
      debug:
        msg:
          - "{{ web_server }}"
          - "{{ nfs_server }}"
           

2.3 在Inventory中定義變量

2.3.1 在Inventory檔案中定義變量

1.定義
[[email protected] playbook_vars]# cat hosts 

[webservers]
172.16.1.7 state=MASTER
172.16.1.8 state=BACKUP

[webservers:vars]
port=80



2.調用
[[email protected] playbook_vars]# cat playbook_vars3.yml 
- hosts: webservers
  tasks:
    - name: Output variables
      debug:
        msg:
          - " {{ state }} {{ port }}"




3.輸出
[[email protected] playbook_vars]# ansible-playbook playbook_vars3.yml 
TASK [Output variables] 
*****************************************************
ok: [172.16.1.7] => {
    "msg": [
        " MASTER 80"
    ]
}
ok: [172.16.1.8] => {
    "msg": [
        " BACKUP 80"
    ]
}

           

2.3.2 使用host_vars定義變量

1.在項目目錄中建立 host_vars目錄,然後在建立一個檔案,檔案的檔案名稱要與 inventory 清單中的主機名稱要保持完全一緻,如果是ip位址,則建立相同ip位址的檔案即可

1.建立host_vars目錄
[[email protected] playbook_vars]# mkdir host_vars

2.編寫相同主機名的檔案
[[email protected] playbook_vars]# touch host_vars/172.16.1
name: bertwu
age: 18

3.調用
[[email protected] playbook_vars]# cat playbook_vars4.yml 
- hosts: 172.16.1.7
  tasks:
    
    - name: Output variables
      debug:
        msg: "{{ name }} {{ age }}"

4.執行測試
[[email protected] playbook_vars]# ansible-playbook playbook_vars4.yml 
*******************************************************************
ok: [172.16.1.7] => {
    "msg": "bertwu 18"
}

如果主機清單中的其他主機區調用,會報錯
           

2.3.3 使用group_vars定義變量

1.在項目目錄中建立 group_vars目錄,然後在建立一個檔案,檔案的檔案名稱要與 inventory 清單中的組名稱保持完全一緻;

2.在 group_vars 目錄中建立 webservers檔案,為 webservers主機組設定變量;

[[email protected] group_vars]# cat webservers 
name: Jay
age:30
           

3.編寫 playbook,隻需在 playbook 檔案中使用變量即可

[[email protected] playbook_vars]# cat playbook_vars5.yml 
- hosts: webservers
  tasks:

    - name: Output varibles
      debug:
        msg:
          - "{{ name }} {{ age }}"

           

4.調用

[[email protected] playbook_vars]# ansible-playbook playbook_vars5.yml 
TASK [Output varibles] *************************************************
ok: [172.16.1.7] => {
    "msg": [
        "bertwu 18"
    ]
}
ok: [172.16.1.8] => {
    "msg": [
        "Jay 30"
    ]
}

           

5.測試其他組能否使用 webservers 組中定義的變量;測試後會發現無法調用;

6.系統提供了特殊的 all 組,也就說在 group_vars 目錄下建立一個 all 檔案,定義變量對所有的主機組都生效;

2.4 通過執行Playbook傳遞變量

在執行Playbook時,可以通過指令行

--extra-vars

-e

外置傳參設定變量;

[[email protected] playbook_vars]# cat vars6.yml 
- hosts: localhost
  tasks:
    - name: Output variables
      debug:
        msg:
          - "{{ user }} {{ uid }}"
           

執行,并且傳遞多個參數

[[email protected] playbook_vars]# ansible-playbook vars6.yml -e "user=tom" -e "uid=666"


TASK [Output variables] ***********************************************************
ok: [localhost] => {
    "msg": [
        "tom 666"
    ]
}

           

2.5 變量的優先級

1)在plabook中定義vars變量

2)在playbook中定義vars_files變量

3)在host_vars中定義變量

4)在group_vars中定義變量

5)通過執行指令傳遞變量

結果:

1.指令行傳參

2.play中的vars_files

3.play中的vars

4.invetory主機清單中的vars

5.host_vars

6.group_vars

7.group_vars/all

8.inventory 組變量

2.6 nfs 服務端和用戶端實作變量方式寫法

[[email protected] playbook_vars]# tree -L 1
.
├── ansible.cfg
├── exports.j2
├── hosts
├── nfs_varibles.yml
└── vars_file.yml

           

1.vars_flle變量檔案

[[email protected] playbook_vars]# cat vars_file.yml 

## nfs
webservers: test
group_name: xxx
user_name: xxx
nfs_gid: 555
nfs_uid: 555
nfs_share_directory: /nfs_data
local_mount_directory: /opt
nfs_ip_range: 172.16.1.0/24

           

2.nfs配置檔案

[[email protected] playbook_vars]# cat exports.j2 

{{ nfs_share_directory }} {{ nfs_ip_range }}(rw,sync,all_squash,anonuid={{nfs_uid }},anongid={{ nfs_gid }})
           

3.nfs用戶端和服務端:

[[email protected] playbook_vars]# cat nfs_varibles.yml 

- hosts: "{{ webservers }}"
  vars_files: ./vars_file.yml 
  tasks:

    - name: Installed nfs servers
      yum:
        name: nfs-utils
        state: present

    - name: Configure nfs
      template:
        src: ./exports.j2
        dest: /etc/exports          
        backup: yes
      notify: Restart nfs server

    - name: Create group
      group:
        name: "{{ group_name }}"
        gid: "{{ nfs_gid }}"
        system: yes
        state: present

    - name: Create user
      user:
        name: "{{ user_name }}"
        uid: "{{ nfs_uid }}"
        group: "{{ group_name }}"
        system: yes

    - name: Create share directory
      file:
        path: "{{ nfs_share_directory }}"
        owner: "{{ user_name }}"
        group: "{{ group_name }}"
        mode: 0755
        state: directory
        recurse: yes



    - name: start nfs
      systemd:
        name: nfs
        state: started
        enabled: yes


  handlers: 
    - name: Restart nfs server
      systemd:
        name: nfs
        state: restarted

- hosts: localhost
  vars_files: ./vars_file.yml
  tasks:
    - name: Remote Mount
      mount:
        src: "172.16.1.99:{{ nfs_share_directory }}"
        path: "{{ local_mount_directory }}"
        state: mounted
        fstype: nfs
        opts: defaults

           

三、 Ansible Register

3.1 什麼是Register

register 可以将 task 執行的任務結果存儲至某個變量中,便于後續的引用;

[[email protected] playbook_vars]# cat register1.yml 
- hosts: webservers
  tasks:

    - name: check netstat
      shell: netstat -lntp
      register: system_status


    - name: print state
      debug:
        msg:
          - "{{ system_status.cmd }}"
          - "{{ system_status.stdout_lines }}"


[[email protected] playbook_vars]# ansible-playbook register1.yml 

TASK [print state] ***************************************************************************************************************************
ok: [172.16.1.7] => {
    "msg": [
        "netstat -lntp", 
        [
            "Active Internet connections (only servers)", 
            "Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    ", 
            "tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN      -                   ", 
            "tcp        0      0 0.0.0.0:50565           0.0.0.0:*               LISTEN      911/rpc.statd       ", 
            "tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      3553/php-fpm: maste ", 
            "tcp        0      0 0.0.0.0:873             0.0.0.0:*               LISTEN      555/rsync           ", 
            "tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      551/rpcbind         ", 
            "tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      3591/nginx: master  ", 
            "tcp        0      0 0.0.0.0:20048           0.0.0.0:*               LISTEN      924/rpc.mountd      ", 
            "tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      905/sshd            ", 
            "tcp        0      0 0.0.0.0:36696           0.0.0.0:*               LISTEN      -                   ", 
            "tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1100/master         ", 
            "tcp6       0      0 :::36673                :::*                    LISTEN      -                   ", 
            "tcp6       0      0 :::2049                 :::*                    LISTEN      -                   ", 
            "tcp6       0      0 127.0.0.1:8005          :::*                    LISTEN      1238/java           ", 
            "tcp6       0      0 :::873                  :::*                    LISTEN      555/rsync           ", 
            "tcp6       0      0 :::56394                :::*                    LISTEN      911/rpc.statd       ", 
            "tcp6       0      0 :::111                  :::*                    LISTEN      551/rpcbind         ", 
            "tcp6       0      0 :::8080                 :::*                    LISTEN      1238/java           ", 
            "tcp6       0      0 :::20048                :::*                    LISTEN      924/rpc.mountd      ", 
            "tcp6       0      0 :::22                   :::*                    LISTEN      905/sshd            ", 
            "tcp6       0      0 ::1:25                  :::*                    LISTEN      1100/master         "
        ]
    ]
}
           

3.2 register批量修改主機名稱

[[email protected] playbook_vars]# cat register2.yml 
- hosts: test
  tasks:

    - name: check netstat
      shell: echo echo $RANDOM | md5sum | cut -c 1-8 # 生成8位随機數
      register: random_name


    - name: print state
      debug:
        msg:
          - "{{ random_name.stdout }}"


    - name: Change hostname
      hostname:
        name: "{{ random_name.stdout}}"

           

3.3 使用register 完成jumpserver key 的建立

[[email protected] playbook_vars]# cat key.yml 
- hosts: localhost
  tasks:
    
    - name: Create jumpserver key
      shell: 'if grep "BOOTSTRAP_TOKEN" ~/.bashrc;then
          echo $BOOTSTRAP_TOKEN;
          else
              BOOTSTRAP_TOKEN=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 24`;                                                                       
              echo "BOOTSTRAP_TOKEN=$BOOTSTRAP_TOKEN" >> ~/.bashrc ;
              echo $BOOTSTRAP_TOKEN                  
              fi'
      register: JMS_BOOTSTRAP_TOKEN 

    - name: Create jumpserver key
      shell: 'if grep "SECRET_KEY" ~/.bashrc;then
          echo $SECRET_KEY;
          else
              SECRET_KEY=`cat /dev/urandom | tr -dc A-Za-z0-9 | head -c 49`;                                                                       
              echo "SECRET_KEY=$SECRET_KEY" >> ~/.bashrc ;
              echo $SECRET_KEY                 
              fi'
      register: JMS_SECRET_KEY

    - name: Output test
      debug:
        msg: 
          - "{{ JMS_BOOTSTRAP_TOKEN.stdout.split('=')[-1] }}"
          - "{{ JMS_SECRET_KEY.stdout.split('=')[-1] }}"

           
[email protected] playbook_vars]# ansible-playbook key.yml 

TASK [Output test] ****************************************************
ok: [localhost] => {
    "msg": [
        "ecUjA0BytELzk2zAOBJfni86dguxhWGEnV4ZLPVZklhwWheXA", 
        "QTZwLs7uG1TO0jVCBSM6XeTU7uxY1XFiDdxFPAOhUNfvr10KZ"
    ]
}
           

五、Ansible Facts Variables

5.1 什麼是facts Ansible

裝置管理控制與時間排程程式:Facilities Administration Control and Time Schedule

facts 變量主要用來自動采集”被控端主機“ 自身的狀态資訊。比如:被控端的,主機名、IP位址、系統版本、CPU數量、記憶體狀态、磁盤狀态等等。

5.2 facts 應用場景

1.通過facts變量檢查被控端硬體CPU資訊,進而生成不同的Nginx配置檔案。

2.通過facts變量檢查被控端記憶體狀态資訊,進而生成不同的memcached的配置檔案。

3.通過facts變量檢查被控端主機名稱資訊,進而生成不同的Zabbix配置檔案。

4.通過facts變量檢查被控端主機IP位址資訊,進而生成不同的redis配置檔案。

5.3 示例

檢視本機狀态資訊

[[email protected] playbook_vars]# ansible localhost -m  setup
           
[[email protected] playbook_vars]# cat facts_print_information.yml 
- hosts: localhost
  tasks:

    - name: Print the basic information of centos
      debug:
         msg: 
          - "{{ ansible_eth0.ipv4.address }}" 
          - "{{ ansible_eth1.ipv4.address }}"
          - "{{ ansible_distribution }}"  # 平台資訊 centos 或ubuntu
          - "{{ ansible_fqdn}}"   # 主機名稱
          - "{{ ansible_processor_count }}"
          - "{{ansible_hostname}}" # 主機名


[[email protected] playbook_vars]# ansible-playbook facts_print_information.yml 
TASK [Print the basic information of centos] *******************************************************
ok: [localhost] => {
    "msg": [
        "10.0.0.62", 
        "172.16.1.62", 
        "CentOS", 
        "manager", 
        1
    ]
}

           

如果沒有使用facts變量需求,可以關閉其功能,加速ansible執行性能;

在play階段定義

gather_facts: no

,因為擷取後端的facts 變量是非常慢的。

[[email protected] playbook_vars]# cat facts_print_information.yml 
- hosts: localhost
  gather_facts: no
  tasks:

    - name: Print the basic information of centos
      debug:
           

5.4 根據不同的ip位址生成不同的Redis配置檔案

[[email protected] playbook_vars]# cat redis.yml 
- hosts: webservers
  tasks:

    - name: install redis server
      yum:
        name: redis
        state: present


    - name: configure redis server
      template:
        src: ./redis.conf.j2
        dest: /etc/redis.conf
      notify: restart redis server


    - name: start redis server
      systemd:
        name: redis
        state: started
        enabled: yes


  handlers: 
    - name: restart redis server
      systemd:
        name: redis
        state: restarted

           

配置檔案寫成動态的

[[email protected] playbook_vars]# cat redis.conf.j2
bind 127.0.0.0 {{ ansible_eth1.ipv4.address }}
           

5.5 根據不同的主機cup數生成不同的nginx配置檔案

"ansible_processor_cores": 3,  # 每個處理器的核心數
"ansible_processor_count": 2,  # 處理器cpu總數
"ansible_processor_threads_per_core": 1,  # 每個線程需要的核心數
"ansible_processor_vcpus": 6,  # 總核心數
           
worker_processes {{ ansible_processor_vcpus * 2 }};
           

5.6 根據主機記憶體生成Memcached配置

# memcached配置檔案如下
[[email protected] project1]# cat memcached.j2 PORT="11211"
USER="memcached"
MAXCONN="1024"#根據記憶體狀态生成不同的配置(支援+-*/運算)
CACHESIZE="{{ ansible_memtotal_mb //2 }}"      # 總記憶體/2# 
CACHESIZE="{{ ansible_memtotal_mb * 0.8 }}" # 使用記憶體80%
OPTIONS=""
           

5.6 批量修改主機名稱

[[email protected] playbook_vars]# cat change_hostname.yml 
- hosts: localhost
  tasks:

    - name: Change hostname
      hostname:
        name: "web_{{ ansible_eth1.ipv4.address.split(".")[-1] }}"

           

5.7 facts變量優化

當我們使用 gather_facts: no 關閉 facts,确實能加速 Ansible 執行,但是有時候又需要使用 facts 中的内容,還希望執行的速度快一點,這時候可以設定 facts 的緩存存入redis中;

修改ansibl.cfg配置檔案

# smart 表示預設收集 facts,但 facts 已有的情況下不會收集,即使用緩存 facts
# implicit 表示預設收集 facts,要禁止收集,必須使用 gather_facts: False;
# explicit 則表示預設不收集,要顯式收集,必須使用 gather_facts: Ture。
host_key_checking = False
gathering = smart  
fact_caching_timeout = 86400
fact_caching = redis
fact_caching_connection = 172.16.1.41:6379:1
# 若 redis 設定了密碼# fact_caching_connection = 172.16.1.41:6379:1:passwd
           
[[email protected] playbook_vars]# yum install python-pip
[[email protected] playbook_vars]# pip install redis # 安裝redis子產品


# 檢視redis伺服器庫,看是否緩存成功。
127.0.0.1:6379[1]> select 1  #選擇1号庫
OK
127.0.0.1:6379[1]> keys *
1) "ansible_cache_keys"
2) "ansible_factslocalhost"
127.0.0.1:6379[1]> 
           

六、 Ansible task control

6.1 when

when 關鍵字主要針對 TASK 任務進行判斷,對于此前我們使用過的 yum 子產品是可以自動檢測軟體包是否已被安裝,無需人為幹涉;但對于有些任務則是需要進行判斷才可以實作的。

  • 比如:web 節點都需要配置 nginx 倉庫,但其他節點并不需要,此時就會用到 when 判斷。
  • 比如: Centos 與 Ubuntu 都需要安裝 Apache,而 Centos 系統軟體包為 httpd,而 Ubuntu系統軟體包為httpd2,那麼此時就需要判斷主機系統,然後為不同的主機系統安裝不同的軟體包。

6.1.1 根據不同作業系統安裝相同的軟體

[[email protected] playbook_vars]# cat when_system.yml 
- hosts: webservers
  tasks:


    - name: centos Install httpd
      yum:
        name: httpd
        state: present
      when: (ansible_distribution == "CentOS")



    - name: ubuntu install apache2
      yum:
        name: httpd2
        state: present
      when: (ansible_distribution == "Ubuntu")

           

6.1.2 為特定的主機添加Nginx倉庫

為主機名為web或lb開頭的主機添加nginx yum倉庫

[[email protected] playbook_vars]# cat when_nginx.yml 
- hosts: all
  tasks:

    - name: add ningx yum repository
      yum_repository:
        name: nginx
        description: add nginx yum repository
        baseurl: http://nginx.org/packages/centos/7/$basearch/
        gpgcheck: no
      when: (ansible_hostname is match("web*")) or (ansible_hostname is match("lb*"))

           

6.1.3 判斷服務是否正常運作

判斷httpd 是否啟動, 啟動則重新開機,否則不做處理

[[email protected] playbook_vars]# cat when_isactive.yml 
- hosts: webservers
  tasks:

    - name: Check service is active
      shell:  systemctl is-active httpd
      ignore_errors: yes
      register: check_service

    - name: Output debug
      debug:
        msg:
          - "{{check_service}}"

    - name: httpd restarted
      systemd:
        name: httpd
        state: restarted

      when: (check_service.rc == 0)

           

6.1.4 判斷是否安裝nginx 未按裝可以執行不同的操作,例如安裝nginx

[[email protected] playbook_vars]# cat when_is_install_nginx.yml 
#- hosts: webservers
- hosts: localhost
  tasks:

    - name: Check is_install nginx
      shell: yum list installed | grep nginx
      ignore_errors: yes
      register: check_service

    - name: Output debug
      debug:
        msg:
          - "{{check_service}}"

    - name: install nginx
      yum:
        name: nginx
        state: present
        enablerepo: nginx
      when: (check_service.rc == 1)

           

6.2 loop循環

在寫 playbook 的時候發現了很多 task 都要重複引用某個相同的子產品,比如一次啟動10個服務,或者一次拷貝10個檔案,如果按照傳統的寫法最少要寫10次,這樣會顯得 playbook 很臃腫。如果使用循環的方式來編寫 playbook,這樣可以減少重複編寫 task 帶來的臃腫;

6.2.1 使用循環批量啟動服務與安裝軟體

[[email protected] loop]# cat loop_service.yml 
- hosts: test
  tasks:

    - name: install mariadb maraidb-server httpd
      yum:
        name: "{{ item }}"
        state: present

      loop:
        - mariadb
        - mariadb-server
        - httpd

    - name : start all
      systemd:
        name: "{{ item }}"
        state: started

      loop:
        - httpd
        - mariadb

           

6.2.2 使用loop循環批量建立使用者

[[email protected] ~]# cat loop-user.yml
- hosts: webservers
  tasks:    
    - name: Add Users
      user:
        name: {{ item.name }}        
        groups: {{ item.groups }}           
      loop:        
        - { name: 'testuser1', groups: 'bin' }      
        - { name: 'testuser2', groups: 'root' }

           

6.2.3 使用loop循環copy檔案

[[email protected] loop]# cat loop_copy.yml 
- hosts: test
  tasks:
    - name: Copy rsync file
      copy:
        src: "{{ item.src }}"
        dest: "{{ item.dest }}"
        mode: "{{ item.mode}}"
        owner: root
        group: root

      loop:
        - { src: ./rsync.conf,dest: /etc/rsync.conf,mode: "0644" } 
        - { src: ./rsync.pass,dest: /etc/rsypc.pass, mode: "0600" }
           

6.3.Handlers與Notify

Handlers 是一個觸發器,同時是一個特殊的 tasks,它無法直接運作,它需要被 tasks 通知後才會運作。比如:httpd 服務配置檔案發生變更,我們則可通過 Notify 通知給指定的 handlers 觸發器,然後執行相應重新開機服務的操作,如果配置檔案不發生變更操作,則不會觸發 Handlers 任務的執行。

handlers 注意事項

  1. 無論多少個 task 通知了相同的 handlers, handlers 僅會在所有 tasks 結束後運作一次。
  2. 隻有 task 發生改變了才會通知 handlers ,沒有改變則不會觸發handlers
  3. 不能使用 handlers 替代 tasks、因為 handlers 是一個特殊的tasks

6.4 tags 任務标簽

預設情況下,Ansible 在執行一個 playbook 時,會執行 playbook 中所有的任務。而标簽功能是用來指定要運作 playbook 中的某個特定的任務;

  1. 為 playbook 添加标簽的方式有如下幾種:

    對一個 task 打一個标簽

    對一個 task 打多個标簽

    對多個 task 打一個标簽

  2. task打完标簽使用的幾種方式

    -t 執行指定tag标簽對應的任務

    –skip-tags 執行除 --skip-tags 标簽之外的所有任務

例:

[[email protected] loop]# cat loop_service.yml 
- hosts: test
  tasks:

    - name: install mariadb maraidb-server httpd
      yum:
        name: "{{ item }}"
        state: present


      loop:
        - mariadb
        - mariadb-server
        - httpd
      tags:  # 為一個任務打多個标簽
        - install_mariadb
        - install_httpd



    - name : start all
      systemd:
        name: "{{ item }}"
        state: started

      loop:
        - httpd
        - mariadb
      tags:  # 為一個任務打多個标簽
        - start_httpd
        - start_mariadb

           

使用

-t

指定 tags 标簽對應的任務, 多個 tags 使用逗号隔開即可

使用

--skip-tags

指定要排除的 tags 标簽對應的任務, 多個 tags 使用逗号隔開即可

[[email protected] loop]# ansible-playbook -t install_mariadb,start_httpd loop_service.yml 
[[email protected] loop]# ansible-playbook --skip-tags  install_mariadb, loop_service.yml
           

6.5 include任務複用

有時,我們發現大量的 Playbook 内容需要重複編寫,各 Tasks 之間功能需互相調用才能完成各自功能,Playbook 龐大到維護困難,這時我們需要使用include比如:A項目需要用到重新開機 httpd,B項目需要重新開機 httpd,那麼我們可以使用 Include來減少重複編寫。

6.5.1 多個項目同時需要重新開機nginx

1.編寫 restart_nginx.yml 檔案

不包含任何play階段資訊

[[email protected] loop]# cat restart_nginx.yml 
- name: Restart nginx server
  systemd:
    name: nginx
    state: restarted

           

2.project_1 如下

[[email protected] loop]# cat restart_nginx.yml 
- name: Restart nginx server
  systemd:
    name: nginx
    state: restarted

[[email protected] loop]# cat project_1.yml 
- hosts: webservers
  tasks:
    
    - name: echo a
      shell: echo 'a project'


    - name: Restart nginx server
      include: ./restart_nginx.yml

           

3.project_2 如下

[[email protected] loop]# cat project_2.yml 
- hosts: webservers
  tasks:
    
    - name: echo b
      shell: echo 'b project'


    - name: Restart nginx server
      include: ./restart_nginx.yml
[[email protected] loop]# cat project_2.yml 
- hosts: webservers
  tasks:
    
    - name: echo b
      shell: echo 'b project'


    - name: Restart nginx server
      include: ./restart_nginx.yml

           

6.5.2 Inlcude結合tags應用 安裝tomcat

1.下載下傳jdk解壓到remote

2.yum本地安裝jdk

3.遠端建立/soft 目錄

4.遠端解壓tomcat到/soft目錄

5.制作軟連接配接

6.推送tomcat啟停檔案

7.推送配置檔案 權限0600

8.啟動tomcat

方式1

1.總入口檔案

[[email protected]_62 loop]# cat main.yml 
- hosts: test
 
  vars :     
    - src_jdk_path: /root/jdk-8u281-linux-x64.rpm
    - dest_jdk: /root
    - tomcat_dir: /soft
    - tomcat_version: 8.5.71
    - tomcat_service: ./tomcat.service
    - tomcat_name: tomcat8 
  
  tasks:
   
    - name: install tomcat8
      include: ./install_tomcat8.yml
      tags: install_tomcat8

    - name: install tomcat9
      include: ./install_tomcat9.yml
      tags: install_tomcat9

  handlers:                                                                                                                                      
    - name: reload tomcat
      systemd:
        name: tomcat
        state: restarted

           

2.install_tomcat8.yml

[[email protected]_62 loop]# cat install_tomcat8.yml 
- name: copy jdk_rpm to remote
  copy:
    src: "{{ src_jdk_path }}" 
    dest: "{{ dest_jdk }}"


- name: install_jdk_rpm
  yum:
    name: "{{ src_jdk_path }}" 
    state: present


- name: create /soft to remote host
  file:
    path: "{{ tomcat_dir }}"
    state: directory


- name: unarchive tomcat package to remote /soft
  unarchive:
    src: "{{ dest_jdk }}/apache-tomcat-{{ tomcat_version }}.tar.gz"
    dest: "{{ tomcat_dir}}"


- name: make tomcat link
  file: 
    src: "{{ tomcat_dir }}/apache-tomcat-{{ tomcat_version }}"
    dest: "{{ tomcat_dir }}/{{tomcat_name}}"
    state: link

- name: copy systemd start file
  template: 
    src: "{{ tomcat_service }}"
    dest: /usr/lib/systemd/system/tomcat.service
 


- name: copy tomcat configure file
  copy:
    src: ./server.xml.j2
    dest: "{{tomcat_dir}}/{{tomcat_name}}/conf/server.xml"
  notify: reload tomcat



- name: start tomcat
  systemd:
    name: tomcat
    state: restarted
    
           

3.install_tomcat9.yml 檔案與8一模一樣

預設會裝8 ,如果裝tomcat9 隻需要指定參數即可

方式2

直接在main.yml寫一個tasks , 隻需一個install_tomcat.yml檔案,預設安裝的是tomcat8 ,安裝tomcat需要指定版本号及目錄。

[[email protected]_62 loop]# cat main.yml 
- hosts: localhost
 
  vars :     
    - src_jdk_path: /root/jdk-8u281-linux-x64.rpm
    - dest_jdk: /root
    - tomcat_dir: /soft
    - tomcat_version: 8.5.71
    - tomcat_service: ./tomcat.service
    - tomcat_name: tomcat8 
  
  tasks:
   
    - name: install tomcat
      include: ./install_tomcat.yml
      tags: install_tomcat

  handlers:                                                                                                                                      
    - name: reload tomcat
      systemd:
        name: tomcat
        state: restarted

           
[[email protected]_62 loop]# cat install_tomcat.yml 
#- hosts: test
#  vars:     
#    - src_jdk_path: /root/jdk-8u281-linux-x64.rpm
#    - dest_jdk: /root
#    - tomcat_dir: /soft
#    - tomcat_version: 8.5.71
#    - tomcat_service: ./tomcat.service
#    - tomcat_name: tomcat8 
#
#  tasks:

- name: copy jdk_rpm to remote
  copy:
    src: "{{ src_jdk_path }}" 
    dest: "{{ dest_jdk }}"


- name: install_jdk_rpm
  yum:
    name: "{{ src_jdk_path }}" 
    state: present


- name: create /soft to remote host
  file:
    path: "{{ tomcat_dir }}"
    state: directory


- name: unarchive tomcat package to remote /soft
  unarchive:
    src: "{{ dest_jdk }}/apache-tomcat-{{ tomcat_version }}.tar.gz"
    dest: "{{ tomcat_dir}}"


- name: make tomcat link
  file: 
    src: "{{ tomcat_dir }}/apache-tomcat-{{ tomcat_version }}"
    dest: "{{ tomcat_dir }}/{{tomcat_name}}"
    state: link

- name: copy systemd start file
  template: 
    src: "{{ tomcat_service }}"
    dest: /usr/lib/systemd/system/tomcat.service
 


- name: copy tomcat configure file
  copy:
    src: ./server.xml.j2
    dest: "{{tomcat_dir}}/{{tomcat_name}}/conf/server.xml"
  notify: reload tomcat



- name: start tomcat
  systemd:
    name: tomcat
    state: restarted

           

預設安裝tomcat8:

[[email protected]_62 loop]# ansible-playbook  -t install_tomcat main.yml

           

安裝tomcat9:

tomcat.service配置檔案如下:

[[email protected]_62 loop]# cat tomcat.service 
[Unit]
Description=tomcat - high performance web server
Documentation=https://tomcat.apache.org/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
#Environment=JAVA_HOME=/usr/local/jdk
Environment=CATALINA_HOME=/soft/{{ tomcat_name }}
Environment=CATALINA_BASE=/soft/{{ tomcat_name }}

ExecStart=/soft/{{ tomcat_name }}/bin/startup.sh
ExecStop=/soft/{{ tomcat_name }}/bin/shutdown.sh


[Install]
WantedBy=multi-user.target

           

6.7 Playbook異常處理

在 playbook 執行的過程中,難免會遇到一些錯誤。由于 playbook 遇到錯誤後,不會執行之後的任務,不便于調試,此時,可以在tasks中使用

ignore_errors: yes

來暫時忽略錯誤,使得 playbook 繼續執行。

[[email protected] ~]# cat ignore.yml
- hosts: all
  tasks:
    - name: Ignore False
      command: /bin/false     
      ignore_errors: yes
           

通常情況下,當 task 失敗後,play将會終止,任何在前面已經被 tasks notify 的 handlers 都不會被執行。如果你在 play 中設定了

force_handlers: yes

參數,被通知的 handlers 就會被強制執行。(有些特殊場景可能會使用到)

- hosts: web 
  force_handlers: yes #強制調用handlers
  tasks:    
    - name: Touch File
      file:
        path=/tmp/bgx_handlers 
        state=touch
      notify: Restart Httpd Server
      ....
           

6.8 change狀态

[[email protected]_62 loop]# cat change.yml 
- hosts: webservers
  tasks:


    - name: get nginx port
      shell: netstat -lntp | grep nginx
      register: nginx_port


    - name: output nginx port
      debug:
        msg:
          - "{{ nginx_port.stdout_lines }}"


           

執行 playbook 會發現第一個 task 運作 shell 子產品報告的改變,即使它沒有真正的在遠端系統做出改變,如果你一直運作,它會一直處在改變狀态。

shell 任務不應該每次都報告 changed 狀态,因為它沒有在被管理主機執行後發生變化。添加

changed_when: false

來抑制這個改變

[[email protected]_62 loop]# cat change.yml 
- hosts: webservers
  tasks:


    - name: get nginx port
      shell: netstat -lntp | grep nginx
      register: nginx_port
      changed_when: false


    - name: output nginx port
      debug:
        msg:
          - "{{ nginx_port.stdout_lines }}"

           

6.9 changed_when檢查任務結果

如果結果正确,則正常往下執行,否則退出執行。

[[email protected]_62 loop]# cat change_when.yml 
- hosts: webservers
  tasks:
    - name: check ningx server
      shell: /usr/sbin/nginx -t
      register: check_nginx
      changed_when: 
        - check_nginx.stdout.find('successful')
        - false


    - name: start nginx server
      systemd:
        name: nginx
        state: restarted