• Ansible的role


    环境

    • 控制节点:Ubuntu 22.04
    • Ansible 2.10.8
    • 管理节点:CentOS 8

    role

    目录结构

    role的文件结构中,包含了8个标准目录:

    • tasks
    • handlers
    • templates
    • files
    • vars
    • defaults
    • meta
    • library

    例如,下面是 common 这个role的目录结构:

    roles/
        common/               # this hierarchy represents a "role"
            tasks/            #
                main.yml      #  <-- tasks file can include smaller files if warranted
            handlers/         #
                main.yml      #  <-- handlers file
            templates/        #  <-- files for use with the template resource
                ntp.conf.j2   #  <------- templates end in .j2
            files/            #
                bar.txt       #  <-- files for use with the copy resource
                foo.sh        #  <-- script files for use with the script resource
            vars/             #
                main.yml      #  <-- variables associated with this role
            defaults/         #
                main.yml      #  <-- default lower priority variables for this role
            meta/             #
                main.yml      #  <-- role dependencies
            library/          # roles can also include custom modules
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Ansible默认会在每个目录下查找 main.yml (或者 main.yaml / main )文件。

    例:创建目录结构如下:

    ➜  testRole1 tree
    .
    ├── roles
    │   ├── role1
    │   │   └── tasks
    │   │       └── main.yml
    │   ├── role2
    │   │   └── tasks
    │   │       └── main.yml
    │   └── role3
    │       └── tasks
    │           └── main.yml
    └── test.yml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    其中, test.yml 内容如下:

    ---
    - hosts: all
      roles:
        - role1
        - role2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注:此处也可以写为:

    ---
    - hosts: all
      roles:
        - role: role1
        - role: role2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    两种方式甚至可以混用。

    本例中,指定为只包含 role1role2 的内容。

    roles/role1/tasks/main.yml 的内容如下(role2和role3类似):

    ---
    - name: role1 task1
      debug:
        msg: "I am role1 task1"
    - name: role1 task2
      debug:
        msg: "I am role1 task2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    运行结果如下:

    ➜  testRole1 ansible-playbook testRole_1.yml
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [role1 : role1 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task1"
    }
    
    TASK [role1 : role1 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task2"
    }
    
    TASK [role2 : role2 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role2 task1"
    }
    
    TASK [role2 : role2 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role2 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    可见,ansible只运行了指定的role。本例中,运行了role1和role2的所有task。

    Ansible有以下几种方式来查找role:

    • 在collections里
    • roles 目录下,即本例所示
    • 配置 roles_path ,其缺省的查找路径为 ~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
    • 在playbook文件同级,即省略 roles 目录,对于本例,可变为:
    ➜  testRole2 tree
    .
    ├── role1
    │   └── tasks
    │       └── main.yml
    ├── role2
    │   └── tasks
    │       └── main.yml
    ├── role3
    │   └── tasks
    │       └── main.yml
    └── test.yml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    虽然可以省略 roles 目录,但显然加上这一级目录会更清晰一些。

    • 直接在playbook中指定role路径,比如:
    ---
    - hosts: all
      roles:
        - role: '/path/to/my/roles/common'
    
    • 1
    • 2
    • 3
    • 4

    使用role

    可通过以下几种方式使用role:

    • 在play级别使用 roles :经典用法,静态引入
    • 在task级别使用 include_role :动态引入
    • 在task级别使用 import_role :静态引入

    在play级别使用role

    比如:

    ---
    - hosts: webservers
      roles:
        - common
        - webservers
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以给 roles 添加 tagsvars 等选项。

    修改role1,role2,role3的 tasks/main.yml ,打印 {{ var1 }} 变量。role1修改如下(role2,role3类似):

    ---
    - name: role1 task1
      debug:
        msg: "I am role1 task1 {{ var1 }}"
    - name: role1 task2
      debug:
        msg: "I am role1 task2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    创建 test.yml 如下:

    ---
    - hosts: all
      roles:
        - role1
        - role: role2
          vars:
            var1: "hello"
          tags: tag1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行结果如下:

    ➜  testRole3 ansible-playbook test.yml            
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [role1 : role1 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task1 hello"
    }
    
    TASK [role1 : role1 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task2"
    }
    
    TASK [role2 : role2 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role2 task1 hello"
    }
    
    TASK [role2 : role2 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role2 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    可见,在 role2 中定义的变量 var1 ,在 role1 中也可用(可通过 DEFAULT_PRIVATE_ROLE_VARS 来定制其行为)。

    但是,请注意 role2 中添加的tag tag1 ,只针对role2中的每个task都有效:

    ➜  testRole3 ansible-playbook test.yml --tags tag1
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [role2 : role2 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role2 task1 hello"
    }
    
    TASK [role2 : role2 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role2 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在task级别include_role

    修改role1,role2,role3的 tasks/main.yml ,去掉变量var1。修改 test.yml 如下:

    ---
    - hosts: all
      tasks:
        - name: task1
          debug:
            msg: "I am task1"
        - name: task2
          include_role:
            name: role3
        - name: task3
          debug:
            msg: "I am task3"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    运行结果如下:

    ➜  testRole4 ansible-playbook test.yml
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [task1] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am task1"
    }
    
    TASK [task2] ***************************************************************************************
    
    TASK [role3 : role3 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role3 task1"
    }
    
    TASK [role3 : role3 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role3 task2"
    }
    
    TASK [task3] ***************************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am task3"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=5    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    include_role 可以添加 tagsvarswhen 等选项。

    例如:

    ......
        - name: task2
          include_role:
            name: role3
          when: "ansible_facts['os_family'] == 'RedHataa'"
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    则只有满足 when 的条件时,才会生效。

    这里格外需要注意 tagsinclude_role 的tag只针对 include_role 自身有效。

    如果运行playbook时,指定了 --tags 选项,则:

    • 不满足tag条件的 include_role 都不会运行
    • 满足tag条件的 include_role 中,只有满足tag条件的task会运行

    例如,创建 test.yml 如下:

    ---
    - hosts: all
      tasks:
        - name: task1
          debug:
            msg: "I am task1"
    
        - name: task2
          include_role:
            name: role1
          tags: tag1
    
        - name: task3
          include_role:
            name: role3
          tags: tag2
    
        - name: task4
          debug:
            msg: "I am task4"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    role1/task/main.yml 如下:

    ---
    - name: role1 task1
      debug:
        msg: "I am role1 task1"
    - name: role1 task2
      debug:
        msg: "I am role1 task2"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    role3/task/main.yml 如下:

    ---
    - name: role3 task1
      debug:
        msg: "I am role3 task1"
      tags: tag1
    - name: role3 task2
      debug:
        msg: "I am role3 task2"
      tags: tag2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行playbook时,如果不指定 --tags ,则所有task都会运行。

    运行playbook时,如果指定 --tags tag1 ,则只有task2(即role1)满足tag条件,但是role1里的task都不满足tag条件,所以也都不会运行:

    ➜  testRole4 ansible-playbook test.yml --tags tag1
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [task2] ***************************************************************************************
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行playbook时,如果指定 --tags tag2 ,则只有task3(即role3)满足tag条件,而role3的task中,只有“role3 task2”同时满足tag条件,所以只有“role3 task2”会运行:

    ➜  testRole4 ansible-playbook test.yml --tags tag2
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [task3] ***************************************************************************************
    
    TASK [role3 : role3 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role3 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在task级别import_role

    其行为和 roles 选项是一样的。

    这里格外需要注意 tagsimport_role 的tag针对role里的所有task都有效。

    如果运行playbook时,指定了 --tags ,则:

    • 不满足tag条件的 import_role 中,满足tag条件的task会运行
    • 满足tag条件的 import_role 中,所有task都会运行

    例如,修改上例中的 test.yml ,把 include_role 改为 import_role ,如下:

    ---
    - hosts: all
      tasks:
        - name: task1
          debug:
            msg: "I am task1"
    
        - name: task2
          import_role:
            name: role1
          tags: tag1
    
        - name: task3
          import_role:
            name: role3
          tags: tag2
    
        - name: task4
          debug:
            msg: "I am task4"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    role1和role3同上例。

    运行playbook时,如果不指定 --tags ,则所有task都会运行。

    运行playbook时,如果指定 --tags tag1 ,则task2(即role1)满足tag条件,则role1里的所有task都会运行。同时task3(即role3)虽然不满足tag条件,但role3里满足tag条件的task会运行:

    ➜  testRole5 ansible-playbook test.yml --tags tag1
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [role1 : role1 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task1"
    }
    
    TASK [role1 : role1 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task2"
    }
    
    TASK [role3 : role3 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role3 task1"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    同理,如果运行playbook时,指定 --tags tag2 ,则task2(即role2)不满足tag条件,且role2里的所有task也都不满足tag条件,所以都不会运行。同时,task3(即role3)满足tag条件,则role3里所有的task都会运行:

    ➜  testRole5 ansible-playbook test.yml --tags tag2
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [role3 : role3 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role3 task1"
    }
    
    TASK [role3 : role3 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role3 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    include_role和import_role的tag

    二者区别总结如下:

    include_role 满足tag条件include_role 不满足tag条件
    task满足tag条件YN
    task不满足tag条件NN
    import_role 满足tag条件import_role 不满足tag条件
    task满足tag条件YY
    task不满足tag条件YN

    roles 的tag行为和import_role 一致(都是静态引入)。

    动态引入和静态引入的区别

    include_role是动态引入,import_role是静态引入。

    动态引入, include_task 本身也是一个task,例如:

    ---
    - hosts: all
      tasks:
        - name: task1
          include_role:
            name: role1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    ➜  testRole6 ansible-playbook test.yml            
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [task1] ***************************************************************************************
    
    TASK [role1 : role1 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task1"
    }
    
    TASK [role1 : role1 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    include_role 改为 import_role ,再次运行,如下:

    ➜  testRole6 ansible-playbook test.yml
    
    PLAY [all] *****************************************************************************************
    
    TASK [Gathering Facts] *****************************************************************************
    ok: [192.168.1.55]
    
    TASK [role1 : role1 task1] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task1"
    }
    
    TASK [role1 : role1 task2] *************************************************************************
    ok: [192.168.1.55] => {
        "msg": "I am role1 task2"
    }
    
    PLAY RECAP *****************************************************************************************
    192.168.1.55               : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    可见,前者的输出结果中,有一行 TASK [task1] ,而后者没有这一行输出。

    这是因为,静态引入,是在预编译期,已经把task1所代表的role1的task静态的引入进来了,在运行期也就没有task1了。而动态引入,在运行期保留了task1,运行到此处时,才把role1引入进来。

    这也能解释tag的行为为何会有不同,因为对于静态引入,运行期已经没有task1了,所以tag在预编译期已经被应用到role1实际的task上去了。而对于动态引入,tag确实是应用于task1上的。

    参考

    • https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_reuse_roles.html
  • 相关阅读:
    在线问题反馈模块实战(十六)​:实现查详情功能
    基于C++和QT实现的旅店管理系统 课程论文+项目源码
    数据库索引原理
    《设计模式》之代理模式
    【数组的中心位置】python实现-附ChatGPT解析
    TCP实现网络通信(多进程与多线程版本)
    SAP Dump:RFC callback call rejected by positive list
    【C++】栈和队列的模拟实现 & 经典题目解析
    计算机视觉 | 交通信号灯状态的检测和识别
    【数据结构与算法】之堆的应用——堆排序及Top_K问题!
  • 原文地址:https://blog.csdn.net/duke_ding2/article/details/134227563