Skip to content

04.2 playbooks roles

本文参考:https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html

1. 目录结构

site.yml
webservers.yml
fooservers.yml
roles/
   common/
     tasks/
     handlers/
     files/
     templates/
     vars/
     defaults/
     meta/
   webservers/
     tasks/
     defaults/
     meta/
  • tasks:包含主要的被执行的tasks列表
  • handlers:包含可以被所有的roles使用的handlers
  • defaults:对于这个role来说的默认变量
  • vars:对于这个role来说的其它变量
  • files:包含可以被这个role部署的文件
  • templates:包含可以被这个role部署的模版文件(遵循Jinja2规范)
  • meta:定义这个role的一些元数据

2. 使用 roles

在 playbook 文件中编写:

---
- hosts: webservers
  roles:
    - common
    - webservers

这为每个角色x指定了以下行为:

  • 若存在roles/x/tasks/main.yml,会将其中的 tasks 加入到 play 中
  • roles/x/handlers/main.yml,加入
  • roles/x/vars/main.yml,加入
  • roles/x/defaults/main.yml,加入
  • roles/x/meta/main.yml,加入
  • roles/x/{files,templates,tasks}/中的文件可以被copy、script、template或此role中导入的tasks都可以被引用。无需写相对或绝对路径。

playbook 的执行顺序:

  1. 在 play 中定义的任何pre_tasks
  2. 运行迄今为止被触发的 handlers。
  3. 依次执行roles中的每个 role。在meta/main.yml中依赖的 role 会先被运行,受标签过滤和条件限制。
  4. 任何在play中定义的tasks
  5. 运行迄今为止被触发的 handlers。
  6. 在play中定义的任何post_tasks
  7. 运行迄今为止被触发的 handlers。

从 2.4 开始,可以使用 import_role or include_role来与其他 tasks 一起工作:

---
- hosts: webservers
  tasks:
    - debug:
        msg: "before we run our role"
    - import_role:
        name: example
    - include_role:
        name: example
    - debug:
        msg: "after we ran our role"

2.1 Role 的搜索路径

  • 相对于 playbook 文件的 roles/ 文件夹;
  • 默认的 /etc/ansible/roles/文件夹。

可以设置环境变量 ANSIBLE_ROLES_PATH 来指定 role 的路径,或者在配置文件/etc/ansible/ansible.cfg中设置roles_path变量。可以指定多个roles目录,使用冒号分隔即可。

[root@dev playbooks]# cat /etc/ansible/ansible.cfg | grep roles_path
roles_path    = /usr/share/ansible/playbooks/roles:/etc/ansible/roles

2.2 导入 role

role 的名字可以是一个简单的名字或者是完整的路径:

---
- hosts: webservers
  roles:
    - common
    # or
    - role: '/path/to/my/roles/common'

roles 也能接收其他的关键字:

---
- hosts: webservers
  roles:
    - common
    - role: foo_app_instance
      vars:
        dir: '/opt/a'
        app_port: 5000
    - role: foo_app_instance
      vars:
        dir: '/opt/b'
        app_port: 5001

或者使用最新的语法:

---
- hosts: webservers
  tasks:
    - include_role:
        name: foo_app_instance
      vars:
        dir: '/opt/a'
        app_port: 5000
  ...

还可以有条件地导入 role 并执行其 tasks:

---
- hosts: webservers
  tasks:
    - include_role:
        name: some_role
      when: "ansible_facts['os_family'] == 'RedHat'"

2.3 为 role 中的 tasks 分配 tags

tags 被分配给 tasks ,用途是可以只执行一部分 tasks。

---
- hosts: webservers
  roles:
    - role: foo
      tags:
        - bar
        - baz
    # using YAML shorthand, this is equivalent to the above:
    - { role: foo, tags: ["bar", "baz"] }

最新语法:

---
- hosts: webservers
  tasks:
    - import_role:
        name: foo
      tags:
        - bar
        - baz

注意:没有在导入 roles 的时候就指定执行的 tags 的功能。

2.4 Role 的重复定义与执行

在一个 play 中,即使多次定义一个 role,也只会执行一次。例如:

---
- hosts: webservers
  roles:
    - foo
    - foo

有两种方式可以达成多次执行的目的:

  1. 在每个 role 定义时传递不同的参数;
  2. meta/main.yml 文件中添加 allow_duplicates: true

例1:

---
- hosts: webservers
  roles:
    - role: foo
      vars:
        message: "first"
    - { role: foo, vars: { message: "second" } }

例2:

# playbook.yml
---
- hosts: webservers
  roles:
    - foo
    - foo

# roles/foo/meta/main.yml
---
allow_duplicates: true

2.5 Role 默认变量

默认变量允许你在导入(included)和依赖(dependent)时设置默认变量。这些变量拥有最低的权限,可以被任何其它类型的变量或 inventory 的变量覆盖。

编写defaults/main.yml即可创建默认变量。

2.6 Role 依赖

role 的依赖在 meta/main.yml 文件中定义,只能使用经典语法进行定义

# roles/myapp/meta/main.yml
---
dependencies:
  - role: common
    vars:
      some_parameter: 3
  - role: apache
    vars:
      apache_port: 80
  - role: postgres
    vars:
      dbname: blarg
      other_parameter: 12

role 的依赖总是在导入地 role 之前被递归地执行。依赖也遵循上文中提到地重复定义规则。

Important

当你使用 allow_duplicates: true时,它需要在被依赖的 role 中配置。

2.6.1 例子

car依赖wheel

# roles/car/meta/main.yml
---
dependencies:
  - role: wheel
    vars:
      n: 1
  - role: wheel
    vars:
      n: 2

wheel依赖tirebrake

# roles/wheel/meta/main.yml
---
dependencies:
  - role: tire
  - role: brake

tirebrake配置可重复定义:

# roles/{tire,brake}/meta/main.yml
---
allow_duplicates: true

执行结果:

tire(n=1)
brake(n=1)
wheel(n=1)
tire(n=2)
brake(n=2)
wheel(n=2)
...
car

3. playbook 例子

3.1 使用普通的 playbook 文件

目录结构:

[root@linux files]# tree
.
├── rpms
│   ├── qemu-kvm-ev-2.3.0-31.x86_64.rpm
│   └── qemu-kvm-tools-ev-2.3.0-31.x86_64.rpm
└── upgrade-nodes.yml

playbook文件:

[root@linux playbooks]# cat upgrade-nodes.yml
---
- hosts: nodes
  tasks:
  - name: remove rpms firstly
    file:
      state: absent
      path: /root/test/rpm/
  - name: copy rpms to nodes
    copy:
      src: rpms/
      dest: /root/test/rpm/
    notify:
    - list rpms
  handlers:
    - name: list rpms
      command: ls -l /root/test/rpm/

3.2 使用 roles 结构

inventory文件:

[root@linux playbooks]# cat /etc/ansible/hosts
[nodes]
192.168.216.41
192.168.216.42

目录结构:

[root@linux playbooks]# pwd
/usr/share/ansible/playbooks
[root@linux playbooks]# tree .
.
├── roles
│   └── upgrade-nodes
│       ├── files
│          └── rpms
│              ├── qemu-kvm-ev-2.3.0-31.x86_64.rpm
│              └── qemu-kvm-tools-ev-2.3.0-31.x86_64.rpm
│       ├── handlers
│          └── main.yml
│       └── tasks
│           └── main.yml
└── upgrade-nodes.yml

playbook文件:

[root@linux playbooks]# cat upgrade-nodes.yml
---
- hosts: nodes
  roles:
    - upgrade-nodes

tasks文件:

[root@linux playbooks]# cat roles/upgrade-nodes/tasks/main.yml
---
- name: remove rpms firstly
  file:
    state: absent
    path: /root/test/rpm/

- name: copy rpms to nodes
  copy:
    src: rpms/
    dest: /root/test/rpm/
  notify:
    - list rpms

handlers文件:

[root@linux playbooks]# cat roles/upgrade-nodes/handlers/main.yml
- name: list rpms
  command: ls -l /root/test/rpm/

使用-C选项时,可能不会触发handlers。