我使用Ansible对一小群计算机执行一些简单的用户管理任务。目前,我把我的剧本设置为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
但这似乎有点脆弱,尤其是对于一个潜在的破坏性剧本来说。省略限制标志意味着剧本将在任何地方运行。因为这些工具只是偶尔被使用,所以似乎有必要采取措施进行万无一失的回放,这样我们就不会在几个月后意外地破坏一些东西。
是否有将剧本运行限制在一台机器上的最佳实践?理想情况下,如果遗漏了一些重要的细节,剧本应该是无害的。
我有一个名为provision的包装器脚本强制您选择目标,因此我不必在其他地方处理它。
对于那些好奇的人,我使用ENV vars为我的vagrantfile使用的选项(为云系统添加相应的ansible arg),并让其余的ansible arg通过。当我一次创建和配置超过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)/
'
如果通过检查play_hosts变量提供了多个主机,则该方法将退出。fail模块用于在不满足单主机条件时退出。下面的例子使用一个包含两个主机alice和bob的hosts文件。
用户。yml(剧本)
---
- 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
在单台主机上运行剧本
$ 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!"
}
事实证明,可以直接在剧本中输入主机名,因此使用主机运行剧本:imac-2。本地就可以了。但它有点笨拙。
更好的解决方案可能是使用变量定义剧本的主机,然后通过——extra-vars传入特定的主机地址:
# file: user.yml (playbook)
---
- hosts: '{{ target }}'
user: ...
运行剧本:
ansible-playbook user.yml --extra-vars "target=imac-2.local"
如果{{target}}没有定义,playbook什么也不做。如果需要,还可以传递来自hosts文件的组。总的来说,这似乎是一种更安全的方式来构建一个潜在的破坏性剧本。
针对单个主机的攻略:
$ 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
一群主持人的剧本:
$ 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