安全地将Ansible剧本限制在一台机器上?

joe*_*ler 207 ansible ansible-playbook

我正在使用Ansible进行一些简单的用户管理任务和一小组计算机.目前,我将我的手册设置为hosts: all,我的主机文件只是一个列出了所有机器的组:

# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local
Run Code Online (Sandbox Code Playgroud)

我发现自己经常不得不针对一台机器.该ansible-playbook命令可以限制这样的播放:

ansible-playbook --limit imac-2.local user.yml
Run Code Online (Sandbox Code Playgroud)

但这似乎有点脆弱,特别是对于潜在的破坏性剧本.离开limit旗帜意味着剧本将在任何地方运行.由于这些工具偶尔会被使用,所以似乎值得采取措施来简化播放,因此我们不会在几个月后意外地进行核实操作.

是否有将playbook运行限制为单台机器的最佳实践?理想情况下,如果省略一些重要细节,剧本应该是无害的.

joe*_*ler 193

事实证明,可以直接在剧本中输入主持人名称,因此运行playbook hosts: imac-2.local可以正常工作.但它有点笨重.

更好的解决方案可能是使用变量定义playbook的主机,然后通过以下方式传递特定的主机地址--extra-vars:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...
Run Code Online (Sandbox Code Playgroud)

运行剧本:

ansible-playbook user.yml --extra-vars "target=imac-2.local"
Run Code Online (Sandbox Code Playgroud)

如果{{ target }}没有定义,则剧本不做任何事情.如果需要,也可以传递来自hosts文件的组.总的来说,这似乎是构建潜在破坏性剧本的更安全的方式.

针对单个主机的Playbook:

$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts

playbook: user.yml

  play #1 (imac-2.local): host count=1
    imac-2.local
Run Code Online (Sandbox Code Playgroud)

与一组主持人的Playbook:

$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts

playbook: user.yml

  play #1 (office): host count=3
    imac-1.local
    imac-2.local
    imac-3.local
Run Code Online (Sandbox Code Playgroud)

忘记定义主机是安全的!

$ ansible-playbook user.yml --list-hosts

playbook: user.yml

  play #1 ({{target}}): host count=0
Run Code Online (Sandbox Code Playgroud)

  • 这可以通过`--limit office [0]`在1.5.3中解决 (49认同)
  • 这是一个"失败安全"的答案,与其他一些答案不同 - 如果你留下一些东西,它将什么也不做.运行使用Ansible 1.7的``run_once``"只有"一台主机上可能仍然是破坏性所以这不是个好主意. (9认同)
  • 变量需要引用 - 即:`'{{target}}'` - 根据http://docs.ansible.com/playbooks_variables.html#hey-wait-a-yaml-gotcha (4认同)
  • 如果你想要一个更短的命令,`-e`相当于`--extra-vars` (4认同)
  • 如果您的 ansible 配置要求主机不能为空或未定义,则可以使用变量与 jinja 过滤器结合使用,例如:`hosts: "{{ target | default('no_hosts')}}"` (3认同)

小智 166

还有一个可爱的小技巧,可以让你在命令行上指定一个主机(或者我想是多个主机),没有中间库存:

ansible-playbook -i "imac1-local," user.yml
Run Code Online (Sandbox Code Playgroud)

注意末尾的逗号(,); 这表明它是一个列表,而不是一个文件.

现在,如果您不小心传递了真实的库存文件,这将无法保护您,因此它可能不是解决此特定问题的好方法.但这是一个方便的技巧!

  • 应该提到的是,要使其正常工作,主机必须在剧中设置为“全部”-我花了一段时间才弄清楚... (4认同)
  • 这个技巧应该使用hosts文件吗?我正在使用主机作为我们的AWS EC2系统的动态库存,它返回:"跳过:没有匹配的主机".也许这个技巧不再有效,因为`--limit`有效吗? (3认同)
  • 这个技巧对我不起作用。但这有效:`$ ansible-playbook -kK --limit=myhost1 myplaybook.yml`。请参阅马尔万的回答。 (3认同)
  • 棒极了。我经常使用-l标志,该标志可与etc / ansible / hosts(使用EC2发现API填充)一起使用,但是有时我真的只需要一台机器。谢谢! (2认同)

Mar*_*agh 77

如果通过检查play_hosts变量提供了多个主机,则此方法将退出.该故障模块用于退出,如果单个主机条件不满足.以下示例使用带有两个主机alice和bob的hosts文件.

user.yml(playbook)

---
- hosts: all
  tasks:
    - name: Check for single host
      fail: msg="Single host check failed."
      when: "{{ play_hosts|length }} != 1"
    - debug: msg='I got executed!'
Run Code Online (Sandbox Code Playgroud)

运行没有主机过滤器的playbook

$ ansible-playbook user.yml
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
failed: [alice] => {"failed": true}
msg: Single host check failed.
failed: [bob] => {"failed": true}
msg: Single host check failed.
FATAL: all hosts have already failed -- aborting
Run Code Online (Sandbox Code Playgroud)

在单个主机上运行playbook

$ ansible-playbook user.yml --limit=alice

PLAY [all] ****************************************************************

TASK: [Check for single host] *********************************************
skipping: [alice]

TASK: [debug msg='I got executed!'] ***************************************
ok: [alice] => {
    "msg": "I got executed!"
}
Run Code Online (Sandbox Code Playgroud)

  • `play_hosts`在Ansible 2.2中已弃用,并替换为`ansible_play_hosts`.要在一台主机上运行而不需要`--limit`,您可以使用`when:inventory_hostname == ansible_play_hosts [0]`. (7认同)
  • 绝对是最好的,“--limit”是最佳选择 (2认同)
  • `[警告]:条件语句不应包含 jinja2 模板分隔符,例如 {{ }} 或 {% %}。发现:在 Ansible 2.8.4 上 {{ play_hosts|length }} == ''`。 (2认同)
  • @Thomas——很好的调用,通过使用 `when: ansible_play_hosts|length != 1` 可以轻松修复 (2认同)

Buz*_*zut 28

有恕我直言,更方便的方式.您确实可以交互式地提示用户他想要应用剧本的机器,这要归功于vars_prompt:

---

- hosts: "{{ setupHosts }}"
  vars_prompt:
    - name: "setupHosts"
      prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]
Run Code Online (Sandbox Code Playgroud)

  • 很酷.这还具有以下优点:剧本不是特定于库存文件的. (2认同)
  • 感谢编辑!我实际上想知道为什么输入默认被视为"密码样式".我在文档中错过了:) (2认同)

dea*_*404 18

要扩展joemailer的答案,如果你想让模式匹配能力匹配远程机器的任何子集(就像ansible命令一样),但仍然想让所有机器上意外运行playbook变得非常困难,这是我想出了什么:

与其他答案相同的剧本:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...
Run Code Online (Sandbox Code Playgroud)

我们有以下主机:

imac-10.local
imac-11.local
imac-22.local
Run Code Online (Sandbox Code Playgroud)

现在,要在所有设备上运行该命令,您必须明确将目标变量设置为"all"

ansible-playbook user.yml --extra-vars "target=all"
Run Code Online (Sandbox Code Playgroud)

并且要将其限制为特定模式,您可以设置 target=pattern_here

或者,您可以离开target=all并附加--limit参数,例如:

--limit imac-1*
Run Code Online (Sandbox Code Playgroud)

即. ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

这导致:

playbook: user.yml

  play #1 (office): host count=2
    imac-10.local
    imac-11.local
Run Code Online (Sandbox Code Playgroud)


小智 8

一个稍微不同的解决方案是使用特殊变量ansible_limit,它是--limitAnsible 当前执行的CLI 选项的内容。

- hosts: "{{ ansible_limit | default(omit) }}"
Run Code Online (Sandbox Code Playgroud)

无需在这里定义额外的变量,只需运行带有--limit标志的剧本即可。

ansible-playbook --limit imac-2.local user.yml
Run Code Online (Sandbox Code Playgroud)


kno*_*cte 7

我真的不明白所有答案都那么复杂,方法很简单:

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check
Run Code Online (Sandbox Code Playgroud)

check模式允许您以空运行模式运行,而无需进行任何更改。

  • 可能是因为想知道答案,所以您错过了这个问题,该问题要求一种方法来防止错误地省略参数时运行。您建议添加更多违反要求的参数。 (5认同)
  • 啊,当然,但是如果人们给我点赞,那可能是因为他们是 Ansible 新手(就像我写答案时一样),他们甚至不知道 `--check` 标志,所以我想这仍然很有用文档方面,因为这个问题可能非常*谷歌搜索* (2认同)

Fra*_*ank 6

使用EC2外部清单脚本的AWS用户只需按实例ID进行过滤:

ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为库存脚本会创建默认组.

  • 选项--limit不限于EC2,可用于托管/分组库存的名称.谢谢. (4认同)

Ber*_*oer 6

由于1.7版ansible具有run_once选项.该部分还包含对各种其他技术的一些讨论.


mcd*_*stl 5

我们有一些通用的剧本可供大量团队使用。我们还有特定于环境的清单文件,其中包含多个组声明。

为了强制某人调用某个剧本来指定要与之对抗的小组,我们在剧本的顶部添加一个虚拟条目:

[ansible-dummy-group]
dummy-server
Run Code Online (Sandbox Code Playgroud)

然后,我们将以下检查作为共享剧本的第一步:

- hosts: all
  gather_facts: False
  run_once: true
  tasks:
  - fail:
      msg: "Please specify a group to run this playbook against"
    when: '"dummy-server" in ansible_play_batch'
Run Code Online (Sandbox Code Playgroud)

如果虚拟服务器显示在计划将其运行的主机列表中(ansible_play_batch),则调用者未指定组,则该运行将失败。


bai*_*y86 5

这显示了如何在目标服务器本身上运行剧本。

如果您想使用本地连接,这有点棘手。但是,如果您为主机设置使用变量并在主机文件中为 localhost 创建一个特殊条目,这应该没问题。

在(所有)剧本中,hosts: 行设置为:

- hosts: "{{ target | default('no_hosts')}}"
Run Code Online (Sandbox Code Playgroud)

在清单主机文件中,为 localhost 添加一个条目,将连接设置为本地:

[localhost]
127.0.0.1  ansible_connection=local
Run Code Online (Sandbox Code Playgroud)

然后在命令行上运行命令明确设置目标 - 例如:

$ ansible-playbook --extra-vars "target=localhost" test.yml
Run Code Online (Sandbox Code Playgroud)

这在使用 ansible-pull 时也有效:

$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml
Run Code Online (Sandbox Code Playgroud)

如果您忘记在命令行上设置变量,该命令将安全出错(只要您尚未创建名为“no_hosts”的主机组!)并显示以下警告:

skipping: no hosts matched
Run Code Online (Sandbox Code Playgroud)

如上所述,您可以使用以下命令定位一台机器(只要它在您的主机文件中):

$ ansible-playbook --extra-vars "target=server.domain" test.yml
Run Code Online (Sandbox Code Playgroud)

或一组类似的东西:

$ ansible-playbook --extra-vars "target=web-servers" test.yml
Run Code Online (Sandbox Code Playgroud)