Ansible 最佳实践不重复常见角色
Posted
技术标签:
【中文标题】Ansible 最佳实践不重复常见角色【英文标题】:Ansible best practice do not repeat common role 【发布时间】:2015-12-23 09:14:13 【问题描述】:在 Ansible 最佳实践页面上:http://docs.ansible.com/ansible/playbooks_best_practices.html#top-level-playbooks-are-separated-by-role 它显示了一个示例,其中主 playbook site.yml 包含几个其他*** playbook webservers.yml 和 dbservers.yml。在这些剧本中,它们每个都包含共同的角色。一些库存文件我的所有组都在一台主机上运行。另一个清单文件我每组有一个主机。对于任何组位于一台主机上的情况,如果我运行 site.yml,您可以看到共同角色被扮演了两次,一次用于 webservers.yml,另一次用于 dbservers.yml。
有什么办法可以避免这种情况?我想你可以从 webservers.yml 和 dbservers.yml 中取出公共角色,而是在 site.yml 中有一个针对公共角色的任务。但是我不能单独配置一个 webserver 或 dbserver 。
【问题讨论】:
“一些清单文件我的所有组都在一个主机上运行。另一个清单文件我每个组都有一个主机。”是什么意思? 【参考方案1】:我使用角色目录中的meta
文件确定角色依赖关系。角色依赖关系允许您在使用角色时自动拉入其他角色。角色依赖项存储在角色目录中的 meta/main.yml 文件中。
角色依赖总是在包含它们的角色之前执行,并且是递归的。默认情况下,角色也只能作为依赖项添加一次 - 如果另一个角色也将其列为依赖项,它将不会再次运行。可以通过将 allow_duplicates: yes 添加到 meta/main.yml 文件来覆盖此行为。
See an example in the Ansible documentation.
【讨论】:
我喜欢这种方法,似乎对我来说最有意义。但是,当我实际尝试实现它时,它不起作用。我的共同角色仍然运行多次。我明确尝试设置 allow_duplicates: no 无效。好像还有其他人有同样的问题? github.com/ansible/ansible/issues/5971【参考方案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.yml
、ansible-playbook site.yml -l common
、ansible-playbook site.yml -l db
、ansible-playbook db.yml
、...)
让您决定是否要重复执行共同点
如果您不想重复 role: common, when: isdef_common_role is not defined
,可以使用以下语句将条件放入 common 角色中:
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"'
【讨论】:
【参考方案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
希望对你有帮助
【讨论】:
【参考方案4】:我的方法是不在剧本中包含剧本。至少在这样做会导致角色在单个作业中执行多次时不会。
我需要包含在超过 1 个剧本中的任何内容都会转换为一个角色,并且该角色可以包含在许多剧本中。如果我最终得到几个包含重复角色系列的剧本,我可以将这些角色组合成一个角色,该角色仅依赖于其他角色以避免重复。
【讨论】:
【参考方案5】:我的方法是在服务器上为每个角色创建一个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
正如您在上面的示例中看到的,如果 playbook 已经运行,它将跳过所有任务。
【讨论】:
【参考方案6】:您还可以使用 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.
【讨论】:
【参考方案7】:正如 Ansible Documentation 中所述:
Ansible 只允许角色执行一次,即使已定义 多次,如果在角色上定义的参数不是 每个定义都不同。
(...)
要让角色多次运行,有两种选择: 1.在每个角色定义中传递不同的参数。 2. 在角色的 meta/main.yml 文件中添加 allow_duplicates: true 。
还要考虑 dynamic vs. static 内容重用的不同方面:Including and Importing
请记住,剧本是在库存项目的基础上运行的,所有角色架构和代码重用都是为了组织和简化将该基础架构作为代码进行维护。并且对于每次运行,任务都应该在同一主机上生效,并产生幂等的结果。
也就是说,首先运行同一组任务(即一个角色)两次是没有意义的,因为任何后续执行都没有实际效果(由于幂等性)。
例外情况是角色调用具有不同的参数(变量、标签等),因此在执行上存在实际差异,可能会影响幂等性并导致有些不同的结果。在这些情况下,多次运行同一组任务是有意义的,这就是发生的情况。
根据经验,特别是关于静态内容,所有将被执行的代码就像一个独立的剧本(即使在包含两个或多个“子”剧本的“站点”剧本中),范围是不过是全球性的。
【讨论】:
以上是关于Ansible 最佳实践不重复常见角色的主要内容,如果未能解决你的问题,请参考以下文章
Ansible最佳实践之Playbook高级循环任务如何操作