首页 文章

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

提问于
浏览
175

我正在使用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运行限制为单台机器的最佳实践?理想情况下,如果省略一些重要细节,剧本应该是无害的 .

11 回答

  • 0

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

  • 67

    事实证明可以直接在剧本中输入主持人姓名,因此使用 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
    
  • 1

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

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

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

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

  • 6

    如果通过检查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!'
    

    Run playbook with no host filters

    $ 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 playbook on single host

    $ 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!"
    }
    
  • 0

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

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

    为了扩展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*
    

    即 . 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
    
  • 167

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

    ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts
    

    这是因为库存脚本creates default groups .

  • 5

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

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

    [ansible-dummy-group]
    dummy-server
    

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

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

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

  • 19

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

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

    echo 'Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'
    echo '  bootstrap - Bootstrap servers ssh port and initial security provisioning'
    echo '  dev - Provision localhost for development and control'
    echo '  TARGET - specify specific host or group of hosts'
    echo '  all - provision all servers'
    echo '  vagrant - Provision local vagrant machine (environment vars only)'
    echo
    echo 'Environment VARS'
    echo '  BOOTSTRAP - use cloud providers default user settings if set'
    echo '  TAGS - if TAGS env variable is set, then only tasks with these tags are run'
    echo '  SKIP_TAGS - only run plays and tasks whose tags do not match these values'
    echo '  START_AT_TASK - start the playbook at the task matching this name'
    echo
    ansible-playbook --help | sed -e '1d
        s#=/etc/ansible/hosts# set by bin/provision argument#
        /-k/s/$/ (use for fresh systems)/
        /--tags/s/$/ (use TAGS var instead)/
        /--skip-tags/s/$/ (use SKIP_TAGS var instead)/
        /--start-at-task/s/$/ (use START_AT_TASK var instead)/
    '
    
  • 16

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

    ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check
    

    检查模式允许您在干运行模式下运行,无需进行任何更改 .

  • 139

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

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

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

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

    [localhost]
    127.0.0.1  ansible_connection=local
    

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

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

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

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

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

    skipping: no hosts matched
    

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

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

    或者像这样的组:

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

相关问题