zoukankan      html  css  js  c++  java
  • Ansible Playbooks 介绍 和 使用 二

    handlers

    接上一篇文章 Ansible Playbooks 介绍 和 使用 一 继续说明

    用于当关注的资源发生变化时采取一定的操作。

    notify这个 action可用于在每个play的最后被处罚,这样可以避免多次有改变时每次都执行指定的操作,取而代之,尽在所有的变化发生完成后一次性执行指定的操作。在notify中列出的操作成为handler。

    例如:

    - name: template configuration file
      template: src=template.j2 dest=/etc/foo.conf
      notify:
      - restart memcached
      - restart apache
    

    handler是task列表,这些task与前述task并没有本质上的不同。

    handlers:
    - name: restart memcached
      service: name=memcached state=restarted
    - name: restart apache
      service: name=httpd state=restarted
    

    playbook 案例 2 handlers

    应用场景

    在webservs组安装httpd服务,默认启动httpd监听的是80端口

    步骤

    1. 创建一个配置安装httpd服务的playbook,并配置开机器启动等相关操作
    2. 执行httpd.yml
    3. 修改配置文件httpd.conf中的端口为8080
    4. 再次执行httpd的playbook文件

    首先创建httpd.yml文件

    [root@node01 ansible]# pwd
    /etc/ansible
    [root@node01 ansible]# cat httpd.yml 
    - hosts: webservs
      remote_user: root
      tasks:
      - name: install httpd packge
        yum: name=httpd state=present
      - name: configuration file for httpd
        copy: src=/etc/ansible/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
      - name: start httpd service
        service: name=httpd enabled=true state=started
    

    创建配置文件目录,并拷贝httpd.conf

    [root@node01 ansible]# pwd
    /etc/ansible
    [root@node01 ansible]# mkdir conf
    [root@node01 ansible]# cp /etc/httpd/conf/httpd.conf conf/
    [root@node01 ansible]# vim conf/httpd.conf
    

    执行httpd.yuml的playbook

    [root@node01 ansible]# ansible-playbook httpd.yml 
    
    PLAY [webservs] ***********************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    
    TASK [install httpd packge] ***********************************************************************************************
    changed: [10.0.0.65]
    
    TASK [configuration file for httpd] ***************************************************************************************
    ok: [10.0.0.65]
    
    TASK [start httpd service] ************************************************************************************************
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=4    changed=2    unreachable=0    failed=0
    

    验证:

    [root@node01 ansible]# ansible webservs -a 'rpm -qa httpd'
    10.0.0.65 | CHANGED | rc=0 >>
    httpd-2.4.6-80.el7.centos.1.x86_64
    
    [root@node01 ansible]# ansible webservs -m shell -a 'netstat -lntup | grep 80'
    10.0.0.65 | CHANGED | rc=0 >>
    tcp6       0      0 :::80                   :::*                    LISTEN      31354/httpd
    

    修改ansible服务端下httpd.conf配置文件中的端口为8080,然后重新执行

    [root@node01 ansible]# egrep '^Listen' conf/httpd.conf 
    Listen 8080
    [root@node01 ansible]# ansible-playbook httpd.yml 
    
    PLAY [webservs] ***********************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    
    TASK [install httpd packge] ***********************************************************************************************
    ok: [10.0.0.65]
    
    TASK [configuration file for httpd] ***************************************************************************************
    changed: [10.0.0.65]
    
    TASK [start httpd service] ************************************************************************************************
    ok: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=4    changed=1    unreachable=0    failed=0   
    
    [root@node01 ansible]# ansible webservs -m shell -a 'netstat -lntup | grep httpd'
    10.0.0.65 | CHANGED | rc=0 >>
    tcp6       0      0 :::80                   :::*                    LISTEN      31354/httpd       
    
    [root@node01 ansible]# ansible webservs -m shell -a 'egrep "^Listen" /etc/httpd/conf/httpd.conf'
    10.0.0.65 | CHANGED | rc=0 >>
    Listen 8080
    

    最后可以看到,虽然远程主机的配置文件中的端口修改了,但实际监听的端口没有变,说明httpd没有重启

    此时就需要用handlers,来监听当有类似于这样的配置文件操作变更的时候,就需要重启这样的操作,

    下面修改httpd.yml中的内容

    [root@node01 ansible]# cat httpd.yml 
    - hosts: webservs
      remote_user: root
      tasks:
      - name: install httpd packge
        yum: name=httpd state=present
      - name: configuration file for httpd
        copy: src=/etc/ansible/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
        notify: 
        - restart httpd
      - name: start httpd service
        service: name=httpd enabled=true state=started
      handlers:
      - name: restart httpd
        service: name=httpd state=restarted
    

    再次把httpd.conf中的端口改成808,然后再次执行

    [root@node01 ansible]# egrep '^Listen' conf/httpd.conf 
    Listen 808
    [root@node01 ansible]# ansible-playbook httpd.yml 
    
    PLAY [webservs] ***********************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    
    TASK [install httpd packge] ***********************************************************************************************
    ok: [10.0.0.65]
    
    TASK [configuration file for httpd] ***************************************************************************************
    changed: [10.0.0.65]
    
    TASK [start httpd service] ************************************************************************************************
    ok: [10.0.0.65]
    
    RUNNING HANDLER [restart httpd] *******************************************************************************************
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=5    changed=2    unreachable=0    failed=0   
    
    [root@node01 ansible]# ansible webservs -m shell -a 'netstat -lntup | grep httpd'
    10.0.0.65 | CHANGED | rc=0 >>
    tcp6       0      0 :::808                  :::*                    LISTEN      32212/httpd
    

    最后可以看到,远程主机的httpd服务监听的端口已经变成了808。

    vars 变量

    在playbook中使用变量,可以直接在playbook中直接定义变量,也可以在其他模板中定义变量,在playbook文件中饮用

    下面以httpd.yml为例,在文件中增加vars变量

    [root@node01 ansible]# cat httpd.yml 
    - hosts: webservs
      remote_user: root
      vars:
      - package: httpd
      - service: httpd
      tasks:
      - name: install httpd package
        yum: name={{ package }} state=present
      - name: configuration file for httpd
        copy: src=/etc/ansible/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
        notify: 
        - restart httpd
      - name: start httpd service
        service: name={{ service }} enabled=true state=started
      handlers:
      - name: restart httpd
        service: name={{ service }} state=restarted
    

    从上面的定义可以看出,变量的引用是通过{{ }} 两个大括号来的
    下面看下重新执行一下,看下效果

    [root@node01 ansible]# ansible-playbook httpd.yml 
    
    PLAY [webservs] ***********************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    
    TASK [install httpd package] **********************************************************************************************
    ok: [10.0.0.65]
    
    TASK [configuration file for httpd] ***************************************************************************************
    ok: [10.0.0.65]
    
    TASK [start httpd service] ************************************************************************************************
    ok: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=4    changed=0    unreachable=0    failed=0 
    

    可以看到都是OK,说明变量引用成功了

    setup facts 变量使用

    playbook也可以直接引用facts中获取的远程主机信息的变量来使用

    案例

    首先来查看

    [root@node01 ansible]# ansible webservs -m setup | head 
    10.0.0.65 | SUCCESS => {
        "ansible_facts": {
            "ansible_all_ipv4_addresses": [
                "10.0.0.65"
            ], 
            "ansible_all_ipv6_addresses": [
                "fe80::20c:29ff:fe07:47f6"
            ], 
            "ansible_apparmor": {
                "status": "disabled"
    

    这里就使用变量:ansible_all_ipv4_addresses 来调用使用

    [root@node01 ansible]# cat test.yml 
    - hosts: webservs
      remote_user: root
      tasks:
      - name: copy file
        copy: content="{{ ansible_all_ipv4_addresses }}" dest=/tmp/vars.ans
    [root@node01 ansible]# ansible-playbook test.yml 
    
    PLAY [webservs] ***********************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    
    TASK [copy file] **********************************************************************************************************
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=2    changed=1    unreachable=0    failed=0   
    
    [root@node01 ansible]# ansible webservs -a 'cat /tmp/vars.ans'
    10.0.0.65 | CHANGED | rc=0 >>
    ["10.0.0.65"]
    

    从上面最后输出的结果来看,变量的调用成功。

    inventory 中定义变量

    同样也可以在inventory中定义变量,然后在playbook中引用

    案例

    修改inventory文件hosts

    [root@node01 ansible]# cat hosts
    # This is the default ansible 'hosts' file.
    #
    # It should live in /etc/ansible/hosts
    #
    #   - Comments begin with the '#' character
    #   - Blank lines are ignored
    #   - Groups of hosts are delimited by [header] elements
    #   - You can enter hostnames or ip addresses
    #   - A hostname/ip can be a member of multiple groups
    
    [webservs]
    10.0.0.65 testvars="10.0.0.65"
    
    [dbservs]
    10.0.0.66 testvars="10.0.0.66"
    

    上面给个主机定义了 testvars变量

    下面来引用,修改playbook文件

    [root@node01 ansible]# cat test.yml 
    - hosts: webservs, dbservs
      remote_user: root
      tasks:
      - name: copy file
        copy: content="{{ ansible_all_ipv4_addresses }}
    {{ testvars }}" dest=/tmp/vars.ans
    [root@node01 ansible]# ansible-playbook test.yml 
    
    PLAY [webservs, dbservs] **************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    ok: [10.0.0.66]
    
    TASK [copy file] **********************************************************************************************************
    changed: [10.0.0.66]
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=2    changed=1    unreachable=0    failed=0   
    10.0.0.66                  : ok=2    changed=1    unreachable=0    failed=0   
    
    [root@node01 ansible]# ansible all -a 'cat /tmp/vars.ans'
    10.0.0.66 | CHANGED | rc=0 >>
    [u'10.0.0.66']
    10.0.0.66
    
    10.0.0.65 | CHANGED | rc=0 >>
    [u'10.0.0.65']
    10.0.0.65
    
    

    从上面最后的输出结果可以看出,引用成功。

    条件测试

    如果需要根据变量、facts或此前任务的执行结果来为某task执行与否的前提时要用到条件测试。

    when 语句

    在task后面添加when子句即可使用条件测试;when语句支持jinja2表达式语法,例如:

    tasks:
    - name: "shutdown Debian flavored systems"
      command: /sbin/shutdown -h now
      when: ansible_os_family == "Debian"
    

    when 语句中还可以使用jinja2的太多filter,例如要忽略此前某语句的错误并基于其结果(failed或者sucess)运行后面指定的语句,可使用类似如下的形式:

    tasks:
    - command: /bin/false
      register: result
      ignore_errors: True
    - command: /bin/something
      when: result | failed
    - command: /bin/something_else
      when: result | success
    - command: /bin/still/something_else
      when: result | skipped
    

    此外 when语句中还可以使用facts或playbook中定义的变量。

    案例

    判断当主机名为node02的时候,添加一个node02的新用户,否则其他机器不添加

    首先使用ansible查看所有主机的主机名:

    [root@node01 ansible]# ansible all -m setup | grep ansible_fqdn
            "ansible_fqdn": "node02", 
            "ansible_fqdn": "node03",
    

    定义和执行playbook文件

    [root@node01 ansible]# cat cond.yml 
    - hosts: all
      remote_user: root
      vars:
      - username: node02
      tasks:
      - name: create {{ username }} user
        user: name={{ username }}
        when: ansible_fqdn == "node02"
    [root@node01 ansible]# ansible-playbook cond.yml 
    
    PLAY [all] ****************************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.65]
    ok: [10.0.0.66]
    
    TASK [create node02 user] *************************************************************************************************
    skipping: [10.0.0.66]
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=2    changed=1    unreachable=0    failed=0   
    10.0.0.66                  : ok=1    changed=0    unreachable=0    failed=0   
    
    [root@node01 ansible]# ansible all -a 'grep node02 /etc/passwd'
    10.0.0.66 | FAILED | rc=1 >>
    non-zero return code
    
    10.0.0.65 | CHANGED | rc=0 >>
    node02:x:1002:1002::/home/node02:/bin/bash
    

    从上最后执行的结果来看,when的条件测试判断成功。

    迭代

    当有需要重复性执行的任务时,可以使用迭代机制,其使用格式为将需要迭代的内容定义为item变量,并通过with_items语句来指明迭代的元素列表即可。例如:

    - name: add several users
      user: name={{ item }} state=present groups=wheel
      with_items:
      - testuser1
      - testuser2
    

    事实上,with_items中可以使用元素还可以为hashes,例如:

    - name: add several users
      user: name={{ item }} state=present groups={{ item.groups }}
      with_items:
      - { name: 'testuser1', group: 'wheel' }
      - { name: 'testuser2', group: 'root' }
    

    templates 模板

    在某个服务的配置文件中,预先定义好需要变更的变量,然后在执行playbook的时候,向定义好的配置文件中传入参数,可灵活修改;
    如http服务,一个http监听80端口,另一个监听8080端口,则可以使用

    案例

    以httpd的配置文件为例,对其进行修改

    [root@node01 ansible]# pwd
    /etc/ansible
    [root@node01 ansible]# mkdir templates
    [root@node01 ansible]# cp /etc/httpd/conf/httpd.conf templates/httpd.conf.j2
    [root@node01 ansible]# egrep "^Listen|^ServerName" templates/httpd.conf.j2 
    Listen {{ http_port }}
    ServerName {{ ansible_fqdn }}
    

    然后修改inventory文件中增加变量

    [root@node01 ansible]# cat /etc/ansible/hosts
    # This is the default ansible 'hosts' file.
    #
    # It should live in /etc/ansible/hosts
    #
    #   - Comments begin with the '#' character
    #   - Blank lines are ignored
    #   - Groups of hosts are delimited by [header] elements
    #   - You can enter hostnames or ip addresses
    #   - A hostname/ip can be a member of multiple groups
    
    [webservs]
    10.0.0.65 http_port=80
    
    [dbservs]
    10.0.0.66 http_port=8080
    

    定义playbook文件

    [root@node01 ansible]# cat apache.yml 
    - hosts: webservs dbservs
      remote_user: root
      vars:
      - package: httpd
      - service: httpd
      tasks:
      - name: install httpd package
        yum: name={{ package }} state=present
      - name: configuration file for httpd
        template: src=/etc/ansible/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
        notify: 
        - restart httpd
      - name: start httpd service
        service: name={{ service}} enabled=true state=started
      handlers:
      - name: restart httpd
        service: name={{ service }} state=restarted
    

    执行

    [root@node01 ansible]# ansible-playbook apache.yml 
    
    PLAY [webservs dbservs] ***************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.66]
    ok: [10.0.0.65]
    
    TASK [install httpd package] **********************************************************************************************
    ok: [10.0.0.65]
    ok: [10.0.0.66]
    
    TASK [configuration file for httpd] ***************************************************************************************
    changed: [10.0.0.65]
    changed: [10.0.0.66]
    
    TASK [start httpd service] ************************************************************************************************
    changed: [10.0.0.65]
    changed: [10.0.0.66]
    
    RUNNING HANDLER [restart httpd] *******************************************************************************************
    changed: [10.0.0.66]
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=5    changed=3    unreachable=0    failed=0   
    10.0.0.66                  : ok=5    changed=3    unreachable=0    failed=0   
    
    [root@node01 ansible]# ansible all -m shell -a 'egrep "^Listen|^ServerName" /etc/httpd/conf/httpd.conf'
    10.0.0.65 | CHANGED | rc=0 >>
    Listen 80
    ServerName node02
    
    10.0.0.66 | CHANGED | rc=0 >>
    Listen 8080
    ServerName node03
    
    [root@node01 ansible]# ansible all -m shell -a 'netstat -lntup | grep httpd'
    10.0.0.65 | CHANGED | rc=0 >>
    tcp6       0      0 :::80                   :::*                    LISTEN      34619/httpd         
    
    10.0.0.66 | CHANGED | rc=0 >>
    tcp6       0      0 :::8080                 :::*                    LISTEN      29274/httpd
    

    从上个最后的执行结果可以看出,template中定义的端口已经生效了。

    tags

    当一个playbook需要运行多次是,可以在playbook文件中的一个tasks中,定义一个tags,在第二次运行时,可以指定tags,只运行其中一个tasks。

    案例

    重新定义playbook文件

    [root@node01 ansible]# cat apache.yml 
    - hosts: webservs dbservs
      remote_user: root
      vars:
      - package: httpd
      - service: httpd
      tasks:
      - name: install httpd package
        yum: name={{ package }} state=present
      - name: configuration file for httpd
        template: src=/etc/ansible/templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
        tags:
        - conf
        notify: 
        - restart httpd
      - name: start httpd service
        service: name={{ service}} enabled=true state=started
      handlers:
      - name: restart httpd
        service: name={{ service }} state=restarted
        
    [root@node01 ansible]# cat hosts
    # This is the default ansible 'hosts' file.
    #
    # It should live in /etc/ansible/hosts
    #
    #   - Comments begin with the '#' character
    #   - Blank lines are ignored
    #   - Groups of hosts are delimited by [header] elements
    #   - You can enter hostnames or ip addresses
    #   - A hostname/ip can be a member of multiple groups
    
    [webservs]
    10.0.0.65 http_port=808
    
    [dbservs]
    10.0.0.66 http_port=800
    

    运行:

    [root@node01 ansible]# ansible-playbook apache.yml --tags="conf"
    
    PLAY [webservs dbservs] ***************************************************************************************************
    
    TASK [Gathering Facts] ****************************************************************************************************
    ok: [10.0.0.66]
    ok: [10.0.0.65]
    
    TASK [configuration file for httpd] ***************************************************************************************
    changed: [10.0.0.65]
    changed: [10.0.0.66]
    
    RUNNING HANDLER [restart httpd] *******************************************************************************************
    changed: [10.0.0.66]
    changed: [10.0.0.65]
    
    PLAY RECAP ****************************************************************************************************************
    10.0.0.65                  : ok=3    changed=2    unreachable=0    failed=0   
    10.0.0.66                  : ok=3    changed=2    unreachable=0    failed=0
    

    从上面运行的结果来看,安装和启动没有运行,只运行了配置修改和重启。

    说明

    特殊的 tags: always 表示无论指定或者不指定,都会运行对应的tasks

  • 相关阅读:
    2019南昌网络赛-I(单调栈+线段树)
    poj3250(单调栈模板题)
    poj2528(线段树+离散化)
    poj2828(线段树查找序列第k小的值)
    Seikimatsu Occult Tonneru(网络流,状态数(建不建边)不多时,可考虑直接进行枚举
    A. Coffee Break(思维题,类似于邻接表的head数组用法)
    E. Paint the Tree(树形dp)
    cdq分治学习
    2018SEERC Points and Rectangles (CDQ分治)
    SEERC 2018 Inversion
  • 原文地址:https://www.cnblogs.com/winstom/p/9804694.html
Copyright © 2011-2022 走看看