文章目录

  • 一、变量 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 关键字进行变量定义

[root@manager 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 }}"




[root@manager 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 groups ansible groups变量_ansible


1.准备vars_file文件

[root@manager playbook_vars]# cat vars_file.yml 
web_server: httpd
nfs_serve: nfs

2.在playbook中play阶段调用

[root@manager 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.定义
[root@manager playbook_vars]# cat hosts 

[webservers]
172.16.1.7 state=MASTER
172.16.1.8 state=BACKUP

[webservers:vars]
port=80



2.调用
[root@manager playbook_vars]# cat playbook_vars3.yml 
- hosts: webservers
  tasks:
    - name: Output variables
      debug:
        msg:
          - " {{ state }} {{ port }}"




3.输出
[root@manager 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目录
[root@manager playbook_vars]# mkdir host_vars

2.编写相同主机名的文件
[root@manager playbook_vars]# touch host_vars/172.16.1
name: bertwu
age: 18

3.调用
[root@manager playbook_vars]# cat playbook_vars4.yml 
- hosts: 172.16.1.7
  tasks:
    
    - name: Output variables
      debug:
        msg: "{{ name }} {{ age }}"

4.执行测试
[root@manager playbook_vars]# ansible-playbook playbook_vars4.yml 
*******************************************************************
ok: [172.16.1.7] => {
    "msg": "bertwu 18"
}

如果主机清单中的其他主机区调用,会报错

2.3.3 使用group_vars定义变量

1.在项目目录中创建 group_vars目录,然后在创建一个文件,文件的文件名称要与 inventory 清单中的组名称保持完全一致;

[root@manager playbook_vars]# mkdir group_vars

2.在 group_vars 目录中创建 webservers文件,为 webservers主机组设定变量;

[root@manager group_vars]# cat webservers 
name: Jay
age:30

3.编写 playbook,只需在 playbook 文件中使用变量即可

[root@manager playbook_vars]# cat playbook_vars5.yml 
- hosts: webservers
  tasks:

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

4.调用

[root@manager 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外置传参设定变量;

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

执行,并且传递多个参数

[root@manager 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 服务端和客户端实现变量方式写法

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

1.vars_flle变量文件

[root@manager 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配置文件

[root@manager playbook_vars]# cat exports.j2 

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

3.nfs客户端和服务端:

[root@manager 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 执行的任务结果存储至某个变量中,便于后续的引用;

[root@manager 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 }}"


[root@manager 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批量修改主机名称

[root@manager 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 的创建

[root@manager 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] }}"
root@manager 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 示例

查看本机状态信息

[root@manager playbook_vars]# ansible localhost -m  setup
[root@manager 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}}" # 主机名


[root@manager 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 变量是非常慢的。

[root@manager 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配置文件

[root@manager 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

配置文件写成动态的

[root@manager 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配置文件如下
[root@ansible 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 批量修改主机名称

[root@manager 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
[root@manager playbook_vars]# yum install python-pip
[root@manager 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 根据不同操作系统安装相同的软件

[root@manager 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仓库

[root@manager 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 是否启动, 启动则重启,否则不做处理

[root@manager 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

[root@manager 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 使用循环批量启动服务与安装软件

[root@manager 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循环批量创建用户

[root@manager ~]# 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文件

[root@manager 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 标签之外的所有任务

例:

[root@manager 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 使用逗号隔开即可

[root@manager loop]# ansible-playbook -t install_mariadb,start_httpd loop_service.yml 
[root@manager 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阶段信息

[root@manager loop]# cat restart_nginx.yml 
- name: Restart nginx server
  systemd:
    name: nginx
    state: restarted

2.project_1 如下

[root@manager loop]# cat restart_nginx.yml 
- name: Restart nginx server
  systemd:
    name: nginx
    state: restarted

[root@manager 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 如下

[root@manager loop]# cat project_2.yml 
- hosts: webservers
  tasks:
    
    - name: echo b
      shell: echo 'b project'


    - name: Restart nginx server
      include: ./restart_nginx.yml
[root@manager 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.总入口文件

[root@web_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

[root@web_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 只需要指定参数即可

[root@web_62 loop]# ansible-playbook  -t install_tomcat9 main.yml -e "tomcat_version=9.0.53" -e "tomcat_name=tomcat9"

方式2
直接在main.yml写一个tasks , 只需一个install_tomcat.yml文件,默认安装的是tomcat8 ,安装tomcat需要指定版本号及目录。

[root@web_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
[root@web_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:

[root@web_62 loop]# ansible-playbook  -t install_tomcat main.yml

安装tomcat9:

[root@web_62 loop]# ansible-playbook  -t install_tomcat main.yml -e "tomcat_version=9.0.53" -e "tomcat_name=tomcat9"

tomcat.service配置文件如下:

[root@web_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 继续执行。

[root@manager ~]# 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状态

[root@web_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来抑制这个改变

[root@web_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检查任务结果

如果结果正确,则正常往下执行,否则退出执行。

[root@web_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