Ansible的role

环境

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

role

目录结构

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

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

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

powershell 复制代码
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

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

例:创建目录结构如下:

powershell 复制代码
➜  testRole1 tree
.
├── roles
│   ├── role1
│   │   └── tasks
│   │       └── main.yml
│   ├── role2
│   │   └── tasks
│   │       └── main.yml
│   └── role3
│       └── tasks
│           └── main.yml
└── test.yml

其中, test.yml 内容如下:

yaml 复制代码
---
- hosts: all
  roles:
    - role1
    - role2

注:此处也可以写为:

yaml 复制代码
---
- hosts: all
  roles:
    - role: role1
    - role: role2

两种方式甚至可以混用。

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

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

yaml 复制代码
---
- name: role1 task1
  debug:
    msg: "I am role1 task1"
- name: role1 task2
  debug:
    msg: "I am role1 task2"

运行结果如下:

powershell 复制代码
➜  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   

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

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

  • 在collections里
  • roles 目录下,即本例所示
  • 配置 roles_path ,其缺省的查找路径为 ~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
  • 在playbook文件同级,即省略 roles 目录,对于本例,可变为:
powershell 复制代码
➜  testRole2 tree
.
├── role1
│   └── tasks
│       └── main.yml
├── role2
│   └── tasks
│       └── main.yml
├── role3
│   └── tasks
│       └── main.yml
└── test.yml

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

  • 直接在playbook中指定role路径,比如:
yaml 复制代码
---
- hosts: all
  roles:
    - role: '/path/to/my/roles/common'

使用role

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

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

在play级别使用role

比如:

yaml 复制代码
---
- hosts: webservers
  roles:
    - common
    - webservers

可以给 roles 添加 tagsvars 等选项。

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

yaml 复制代码
---
- name: role1 task1
  debug:
    msg: "I am role1 task1 {{ var1 }}"
- name: role1 task2
  debug:
    msg: "I am role1 task2"

创建 test.yml 如下:

yaml 复制代码
---
- hosts: all
  roles:
    - role1
    - role: role2
      vars:
        var1: "hello"
      tags: tag1

运行结果如下:

powershell 复制代码
➜  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   

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

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

powershell 复制代码
➜  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   

在task级别include_role

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

yaml 复制代码
---
- hosts: all
  tasks:
    - name: task1
      debug:
        msg: "I am task1"
    - name: task2
      include_role:
        name: role3
    - name: task3
      debug:
        msg: "I am task3"

运行结果如下:

powershell 复制代码
➜  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   

include_role 可以添加 tagsvarswhen 等选项。

例如:

yaml 复制代码
......
    - name: task2
      include_role:
        name: role3
      when: "ansible_facts['os_family'] == 'RedHataa'"
......

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

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

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

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

例如,创建 test.yml 如下:

yaml 复制代码
---
- 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"

role1/task/main.yml 如下:

yaml 复制代码
---
- name: role1 task1
  debug:
    msg: "I am role1 task1"
- name: role1 task2
  debug:
    msg: "I am role1 task2"

role3/task/main.yml 如下:

yaml 复制代码
---
- name: role3 task1
  debug:
    msg: "I am role3 task1"
  tags: tag1
- name: role3 task2
  debug:
    msg: "I am role3 task2"
  tags: tag2

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

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

powershell 复制代码
➜  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   

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

powershell 复制代码
➜  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   

在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 ,如下:

yaml 复制代码
---
- 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"

role1和role3同上例。

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

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

powershell 复制代码
➜  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   

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

powershell 复制代码
➜  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   

include_role和import_role的tag

二者区别总结如下:

include_role 满足tag条件 include_role 不满足tag条件
task满足tag条件 Y N
task不满足tag条件 N N
import_role 满足tag条件 import_role 不满足tag条件
task满足tag条件 Y Y
task不满足tag条件 Y N

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

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

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

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

yaml 复制代码
---
- hosts: all
  tasks:
    - name: task1
      include_role:
        name: role1
powershell 复制代码
➜  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  

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

powershell 复制代码
➜  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   

可见,前者的输出结果中,有一行 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
相关推荐
lbb 小魔仙17 小时前
【Linux】Ansible 自动化运维实战:2000+ 节点配置标准化教程
linux·运维·ansible
扑火的小飞蛾4 天前
【Ansible学习笔记01】 批量执行 shell 命令
笔记·学习·ansible
oMcLin4 天前
如何在 Red Hat Linux 服务器上使用 Ansible 自动化部署并管理多节点 Hadoop 集群?
linux·服务器·ansible
linux修理工7 天前
vagrant ubuntu 22.04 ansible 配置
ubuntu·ansible·vagrant
biubiubiu07068 天前
Ansible自动化
运维·自动化·ansible
秋4278 天前
ansible配置与模块介绍
ansible
秋4279 天前
ansible剧本
linux·服务器·ansible
码农101号10 天前
Ansible - Role介绍 和 使用playbook部署wordPress
android·ansible
2301_8000509911 天前
Ansible
运维·ansible
阎*水13 天前
Ansible 核心要点总结
ansible