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

问题描述 投票:192回答:11

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

# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local

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

ansible-playbook --limit imac-2.local user.yml

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

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

ansible ansible-playbook
11个回答
186
投票

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

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

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

运行剧本:

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

如果没有定义{{ 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

与一组主持人的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

忘记定义主机是安全的!

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

playbook: user.yml

  play #1 ({{target}}): host count=0

2
投票

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

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

在(所有)剧本中有主机:行设置为:

- 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'

在inventory hosts文件中,为localhost添加一个条目,该条目将连接设置为local:

- hosts: "{{ target | default('no_hosts')}}"

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

[localhost]
127.0.0.1  ansible_connection=local

这在使用ansible-pull时也会起作用:

$ ansible-playbook --extra-vars "target=localhost" test.yml

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

$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml

如上所述,您可以使用以下命令定位单个计算机(只要它位于主机文件中):

skipping: no hosts matched

或者像下面这样的组:

$ ansible-playbook --extra-vars "target=server.domain" test.yml

0
投票

我有一个名为provision的包装脚本强制您选择目标,所以我不必在别处处理它。

对于那些好奇的人,我使用ENV vars作为我的vagrantfile使用的选项(为云系统添加相应的ansible arg)并让其余的ansible args通过。我一次创建和配置超过10台服务器的地方我在失败的服务器上包含自动重试(只要正在取得进展 - 我发现在一次创建100个左右的服务器时,经常会有一些服务器在第一次失败时失败)。

$ ansible-playbook --extra-vars "target=web-servers" test.yml

157
投票

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

ansible-playbook -i "imac1-local," user.yml

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

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


75
投票

如果通过检查play_hosts变量提供多个主机,则此方法将退出。如果不满足单个主机条件,则使用fail module退出。以下示例使用带有两个主机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!'

运行没有主机过滤器的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

在单个主机上运行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!"
}

26
投票

有恕我直言,更方便的方式。您确实可以通过vars_prompt以交互方式提示用户他想要应用剧本的机器:

---

- hosts: "{{ setupHosts }}"
  vars_prompt:
    - name: "setupHosts"
      prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]

16
投票

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

与其他答案相同的剧本:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

我们有以下主机:

imac-10.local
imac-11.local
imac-22.local

现在,要在所有设备上运行该命令,您必须将目标变量显式设置为“all”

ansible-playbook user.yml --extra-vars "target=all"

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

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

--limit imac-1*

府。 Ku zxsw指出

这导致:

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

8
投票

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

playbook: user.yml

  play #1 (office): host count=2
    imac-10.local
    imac-11.local

这是因为库存脚本ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts


5
投票

我真的不明白所有的答案是如此复杂,这样做的方法很简单:

creates default groups

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check 模式允许您在干运行模式下运行,而无需进行任何更改。


4
投票

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


3
投票

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

要强制某人调用playbook来指定要运行的组,我们会在playbook的顶部播种一个虚拟条目:

run_once

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

[ansible-dummy-group]
dummy-server

如果虚拟服务器出现在主机列表中,则该游戏手册被安排运行(ansible_play_batch),则调用者没有指定组,并且playbook执行将失败。

© www.soinside.com 2019 - 2024. All rights reserved.