Ansible实践心得
以下针对Ansible 2.1.1.0
,对其他版本的Ansible可能不适用。
-
Ansible是的执行原理是将python代码传输到远端,然后在远端执行。因此:
-
如果你要写Ansible的module,想要对远端的某个文件写入,只需要在module的代码里:
with open(file_path, 'w') as f: f.write(content)
像上述这样就可以了。
-
如果你写的module需要使用一些外部的资源,要注意这些外部资源Ansible是不会自动帮你传输到远端的。比如我曾经想调用一个python文件:
remote_hostname | FAILED! => { "changed": false, "failed": true, "module_stderr": "", "module_stdout": "File \"/tmp/ansible_C9llBm/ansible_module_mymodule.py\", line 10, in <module>\r\n import default\r\nImportError: No module named default\r\n", "msg": "MODULE FAILURE", "parsed": false }
-
-
Ansible现在不支持从一个module中调用其他module。所以如果是用到多个module的组合的话,还是写在playbook里吧。
If you are asking ‘how can I have a module execute other modules’ … you want to write a role.
-
Ansible是可以对每个host使用不同的password等设置的。例子如下:
[real_group] remote_host1 ansible_connection=ssh ansible_ssh_user=root1 ansible_ssh_pass=password1 remote_host2 ansible_connection=ssh ansible_ssh_user=root2 ansible_ssh_pass=password2
如果你觉得上述方式不直观,也可以把每个机器单独设为一个group,再把所有机器用一个group包起来,就像这样:
[remote_host1] remote_hostname1 [remote_host1:vars] ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=password1 [remote_host2] remote_hostname2 [remote_host2:vars] ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=password2 [real_group:children] remote_host1 remote_host2
-
Ansible的module只能获取传递进去的参数,而没法知道hosts里面定义的内容,即如果想要module根据host的信息来搞事情,也必须要通过参数传递进去(这个design的module开发体验很差!)。
-
想要在python代码里执行Ansible的playbook,可参考How to use Ansible 2.0 Python API to run a Playbook?。
-
Ansible的playbook可以插入Jinja2的template,template的变量的内容会被playbook里面的
vars
里面的对应变量给替代(vars
也可以定义在inventory里面)。例如: In hosts:[remote_host1] remote_hostname1 [remote_host1:vars] ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=password1 check_dir=/tmp
In playbook.yml:
--- - hosts: remote_host1 tasks: - name: List files in given dir command: ls {{check_dir}} register: out - name: stdout debug: msg=out.stdout_lines
使用
ansible-playbook playbook.yml -i hosts
执行结果如下:➜ demo_ansible git:(master) ✗ ansible-playbook playbook.yml -i hosts PLAY [remote_host1] ************************************************************ TASK [setup] ******************************************************************* ok: [remote_hostname1] TASK [List files in given dir] ************************************************* changed: [remote_hostname1] TASK [stdout] ****************************************************************** ok: [remote_hostname1] => { "out.stdout_lines": [ "ansible_NOelFI", "ansible.txt", "DataDir_-usr-local-staf-data-STAF.tmp", "hsperfdata_root", "jffi3823846495174998735.tmp", "ssh-2Rbtrunh1OaM", "STAFIPC_STAF", "STAF.tmp", "systemd-private-06v5Nw", "yum_save_tx.2016-09-23.14-37.2smryq.yumtx" ] } PLAY RECAP ********************************************************************* remote_hostname1 : ok=3 changed=1 unreachable=0 failed=0
-
使用Ansible中的
local_action
模块来在本地执行自定义的模块,需要注意在hosts中设置正确的ansible_python_interpreter
(我这里把所有额外的dependencies都放在了本地,所以其他的远程机器没有做过多的设置)。 -
在playbook中添加
strategy: debug
的设置可以在程序抛出异常时进入debug模式(有点像pdb),但只能看到playbook那一层的stack(官方文档),通常用来看vars
,比如:--- - hosts: remote_host1 strategy: debug gather_facts: no tasks: - include: generate_template.yml vars: templates: server/pipeline_set: parallelIngestionPipelines: 4
-
在playbook中include另一个yml文件,并且要传递一些参数时,最好像上面的例子那样添加一个section
vars
再在里面添加参数,否则Ansible会有Warning message的提示(以后的版本可能非法)。 -
在自定义的module中可以存储一些内容到
vars
里面:
module.exit_json(
ansible_facts={
"generate_template_path": generate_template_path
}
)
- Ansible的
fetch
模块只能对单个文件进行操作(为啥copy
模块就可以复制整个文件夹,差评!),如果想要拿整个文件夹,则可以使用synchronize
模块。如果要避免synchronize
模块需要手动填写password的问题(synchronize
模块和Ansible用的是不同的socket,所以还需要输密码,再次差评!),我用的是下面这种work around:
- shell: (cd ; find . -maxdepth 10 -type f) | cut -b 3-
register: files_to_copy
- fetch: src=/ dest=
with_items: ''
Comments