【问题标题】:Define `become=yes' per role with Ansible使用 Ansible 为每个角色定义 `become=yes'
【发布时间】:2017-01-04 02:50:18
【问题描述】:

在我使用 Ansible 进行系统配置时,我不想在每个任务中都指定 become=yes,因此我在项目主目录中创建了以下 ansible.cfg,Ansible 会自动运行所有内容作为根:

[privilege_escalation]
become = True

但随着项目的不断发展,一些新角色不应该以 root 身份运行。我想知道是否有可能在角色内部有一些指令,即该角色内的所有任务都应以 root 身份运行(例如 vars/ 中的某些内容),而不是全局 ansible.cfg上面的解决方案!

【问题讨论】:

标签: ansible


【解决方案1】:

我找到了解决方案,但我认为 Ansible 团队应该实施更好的解决方案。将 ma​​in.yml 重命名为 tasks.yml,然后将以下内容写入 ma​​in.yml

---
- { include: tasks.yml, become: yes }

另一种解决方案是直接在site.yml中传递参数,但问题的主要思想是在其他项目中重用角色而不忘记它需要root:

---
- hosts: localhost
  roles:
    - { role: name, become: yes }

【讨论】:

  • 这实际上看起来是一个很好的方法,它不会带来与我的解决方案相同的问题,即冒着ansible_become var 传播太远的风险。但是,包含对性能有影响。我不确定它在多大程度上得到了解决,但截至去年年底,由于 Ansible 评估它们的方式,使用包含比不使用包含的时间要长得多。
  • @smiller171 感谢您的 cmets!我还没有时间测试你的答案,但我会在接下来的几个小时内尝试一下,并同时为两个答案计时!
  • @smiller171 我没有注意到任何解决方案(ansible.cfg、include:、roles: 和 defaults/main.yml)之间的任何性能差异。但我的大部分角色都很小,虽然我有相当数量的角色。
  • 在特定角色中提供成为选项是恕我直言的最佳解决方案。谢谢。
【解决方案2】:

您还可以将任务包装在一个块中,并将become: yes 放在该块上。所以,在你的 roles/role_name/tasks/main.yml 中,你会这样做:

- block:

  - name: Tasks go here as normal
    ...

  become: yes

这将以 root 身份运行块内的所有任务。 Ansible 块的更多详细信息here (latest docs)。

【讨论】:

  • 我认为这是最好的答案 - 链接的文档甚至使用这个确切的用例作为它的第一个示例!
  • 为什么“成为”必须出现在块的末尾?我希望能够将它放在“-name”之前的开头,但随后出现 YAML 语法错误。
  • 我认为如果你这样做,它可能会假设该块已经结束,然后你用一个严重缩进的任务跟随它 - 这是一个 yaml 语法错误。
  • 虽然我比我更喜欢这种方法,但我发现块有一些限制:you can't use blocks inside blocksyou can't loop blocks,这两者都可以通过包含来完成。
【解决方案3】:

并不是一个根本不同的答案,而是对已经说过的内容进行了外观重新格式化。在我看来,它是最短、最干净、最符合 YAML 的:

- name: My play
  hosts: myhosts
  roles:
    - role: role1
      become: yes

    - role: role2

角色 1 将以 root 身份运行,而角色 2 不会。

【讨论】:

    【解决方案4】:

    Ansible documentation for 2.4中可以找到定义连接变量的方法,比如ansible_becomeansible_user。它们被定义为通常的变量。下面是一个sn-p。

    第一个角色 prepare_user 使用没有提升权限的用户 root 连接到 hosts。第二个角色register 使用通过ansible.cfg 设置的remote_user 连接到hosts(在defined order 中查找;搜索“按以下顺序”)。

    ---
    - hosts: all
      name: Prepare VMs for cluster
      roles:
        - role: prepare_user
          vars:
            - ansible_become: false
            - ansible_user: root
    
        - role: register
    ...
    

    【讨论】:

    • 要回答这个问题,请提供一个如何在角色内部设置的示例(而不是在全局 site.yml 中),因此 become 指令可以例如包含在Ansible Galaxy 角色。 smiller171 的回答说,如果您尝试从角色中设置ansible_become,它将被所有其他角色继承。
    【解决方案5】:

    有一种方法可以满足您的要求,但您需要谨慎使用它,因为 Ansible 在运行任何任务之前会评估大多数变量。如果你使用这个技巧,你必须确保始终如一地使用它,否则你可能会在你不想使用的地方无意中使用become

    在后台,Ansible 使用变量 ansible_become 来确定是否使用 become 来执行该任务。在您的角色中,您可以创建defaults/main.yml 并设置ansible_become: [true/false] 这将导致整个角色接受该值,除非被更高优先级的定义覆盖(理解variable precedence 很重要)

    这里的关键“陷阱”是,如果您使用定义了 this 的角色,它将影响剧中在它下面调用的所有其他角色,除非他们也定义了它。

    例子:

    role_default_become_trueansible_become: true 默认定义为 true role_default_become_falseansible_become: false 默认定义为 true role_no_default 没有默认的 ansible_become

    ---
    - name: test1
      hosts: localhost
      connection: local
      roles:
      - role_default_become_true
      - role_default_become_false
      - role_no_default
    
    - name: test2
      hosts: localhost
      connection: local
      roles:
      - role_default_become_false
      - role_default_become_true
      - role_no_default
    
    - name: test3
      hosts: localhost
      connection: local
      roles:
      - role_default_become_false
      - role_default_become_true
      - { role: role_no_default, become: false }
    

    在 test1 中,role_no_default 会在没有成为的情况下运行,因为之前的角色将其定义为 false,并且它没有自己的定义。

    在 test2 中,role_no_default 将与 become 一起运行,因为之前的角色将其定义为 true,并且它没有自己的定义。

    在 test3 中,role_no_default 不会成为,因为它有自己的定义。

    【讨论】:

    • 从你的回答中我可以理解,变量传播不被认为是一个错误,因为ansible_become 是一个内部变量,用户不应该改变,对吧?如果是这样的话,虽然它完全符合我的要求,而且我认为我可以在角色末尾放置一个解决方法来重置变量,但我宁愿避免它,以免将来破坏任何角色!
    • 正确,它使用了一个不打算以这种方式使用的变量(尽管如果您需要特定于主机的设置,它被记录在库存中使用)我认为您的答案是优越的,应该被标记为接受的答案。
    猜你喜欢
    • 1970-01-01
    • 2014-01-17
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    相关资源
    最近更新 更多