Ansible最佳实践不重复共同的作用

时间:2015-09-25 13:57:01

标签: ansible roles ansible-playbook organization

在Ansible最佳实践页面上:http://docs.ansible.com/ansible/playbooks_best_practices.html#top-level-playbooks-are-separated-by-role它显示了一个示例,其中主playbook site.yml包含一些其他顶级playbooks webservers.yml和dbservers.yml。在这些剧本中,他们每个人都有共同的角色。我将所有组的一些库存文件在一台主机上运行。另一个库存文件我每个组都有一个主机。对于组中一个主机的情况,如果我运行site.yml,您可以看到共同角色正在播放两次,一个用于webservers.yml,另一个用于dbservers.yml。

避免这种情况的解决方案是什么?我想你可以从webservers.yml和dbservers.yml中取出共同的角色,而在site.yml中有一个任务,它既针对共同角色,也针对公共角色。但是我不能单独使用common。来配置web服务器或dbserver。

7 个答案:

答案 0 :(得分:6)

我在我的角色目录中使用meta文件确定角色依赖关系。角色依赖性允许您在使用角色时自动引入其他角色。角色依赖关系存储在角色目录中包含的meta / main.yml文件中。

角色依赖项始终在包含它们的角色之前执行,并且是递归的。默认情况下,角色也只能作为依赖项添加一次 - 如果另一个角色也将其列为依赖项,则不会再次运行。可以通过向meta / main.yml文件添加allow_duplicates:yes来覆盖此行为。

See an example in the Ansible documentation.

答案 1 :(得分:3)

@ user1087973您使用的是标签吗? 如果您使用的是标签,则不同标签的共同角色会被视为不同:

例如:

  

role_common

     

角色1:       主机SRV tag_role_1依赖于role_common

     

角色2:主机SRV tag_role_2依赖于role_common

您的共同角色将被执行两次,因为它因标记而被视为不同

查看--list-tasks,您会看到

使用不同的yml文件而不是使用标签的正确解决方案是将其包含在您的site.yml中

http://docs.ansible.com/ansible/playbooks_best_practices.html#top-level-playbooks-are-separated-by-role

希望这可以提供帮助

答案 2 :(得分:2)

我的方法是不在剧本中包含剧本。至少在这样做时不会导致角色在单个作业中多次执行。

我需要将超过1个剧本中包含的内容转换为角色,并且该角色可以包含在许多剧本中。如果我最终得到几个包含一系列重复角色的剧本,我可以将这些角色组合成一个角色,这个角色只取决于其他角色,以避免重复。

答案 3 :(得分:2)

与其他人一样,我遇到了这个问题,即使角色是幂等的,也需要时间来执行,所以我们可能只想执行一次。

我使用的方法与@Vor类似,但我选择facts而不是创建文件。

提醒:

  

事实在Ansible运行期间在游戏之间存在,但即使您使用事实缓存,也不会在执行中保存。

实施例

<强> site.yml

---
- hosts: all
  roles: [common]
- include: db.yml
- include: web.yml

<强> db.yml

---
- hosts: db
  roles:
    - { role: common, when: isdef_common_role is not defined }
    - db

<强> web.yml

---
- hosts: web
  roles:
    - { role: common, when: isdef_common_role is not defined }
    - web

<强> roles/common/tasks/main.yml

---
- debug: 'msg="{{ inventory_hostname }} common"'
- set_fact: isdef_common_role=1

这确实有点多余(因为你必须每次都有条件包括),但具有以下优点:

  • 适用于我能想到的大多数情况(ansible-playbook site.ymlansible-playbook site.yml -l commonansible-playbook site.yml -l dbansible-playbook db.yml,...)
  • 让您决定是否要重复执行常见的

如果您不想重复{ role: common, when: isdef_common_role is not defined },可以使用以下条件将条件置于公共角色中:

site.yml :无变化

db.yml web.yml :从角色中移除条件

<强> roles/common/tasks/main.yml

---
- include: tasks.yml
  when: isdef_common_role is not defined
- set_fact: isdef_common_role=1

<强> roles/common/tasks/tasks.yml

---
- debug: 'msg="{{ inventory_hostname }} common"'

答案 4 :(得分:1)

我的方法是在服务器上为每个角色创建一个lock文件。这很有效。

例如,我有一个名为common的角色,就是我tasks/main.yml的样子:

- name: check lock file exist
  stat: path=/tmp/ansible-common-role
  ignore_errors: true
  register: lock_file

- name: install apt packages
  apt: name={{ item }} state=present 
  with_items:
    - python-setuptools
  when: lock_file.stat.exists == false

.....
# other tasks with 
#    when: lock_file.stat.exists == false
.....

- name: Create lock file
  file: path=/tmp/ansible-common-role state=touch
  when: lock_file.stat.exists == false

正如您在上面的示例中所看到的,如果已经运行,则该手册将跳过所有任务。

答案 5 :(得分:0)

您还可以使用add_host构建临时组,例如:

1. target: webservers--> add hosts to group "common_roles"
2. target: dbservers --> add hosts to gruop "common_roles"
3. Target: common_roles --> execute whatever common roles you need
4. regular group by group execution.

答案 6 :(得分:0)

如Ansible Documentation中所述:

Ansible仅允许角色执行一次,即使已定义 多次,如果角色上定义的参数不是 每个定义都不同。

(...)

要使角色多次运行,有两种选择:
1.在每个角色定义中传递不同的参数。
2.在角色的meta / main.yml文件中添加allow_duplicates:true。

还要考虑dynamic vs. static内容重用的不同方面:Including and Importing

请记住,剧本是在清单项目的基础上运行的,所有这些角色架构和代码重用都旨在以代码形式组织和简化该基础架构的维护。并且对于每次运行,任务应该在同一主机上生效,并产生幂等结果。

也就是说,一开始两次运行同一组任务(即一个角色)是没有意义的,因为任何后续执行都不会产生实际效果(由于幂等)。

例外情况是角色调用具有不同的参数(变量,标签等)时,因此对执行的实际差异可能会影响幂等性并导致结果有所不同。在这些情况下,多次执行同一组任务很有意义,这就是发生的情况。

根据经验,特别是关于静态内容,将要执行的所有代码就像一个单一且独立的剧本(即使在包含两个或多个“子”剧本的“站点”剧本中),范围也是仍然是全球性的。