使用Ansible Vault来优化playbook的性能调整?
首先
Ansible Vault非常慢。
當清單中有很多主機且host_vars下有很多主機對應的Ansible Vault加密文件時,這種情況就很明顯了。
让我们看看实际上有多慢。
在VirtualBox上,我安装了一个1CPU、1GB内存的CentOS 7.1虚拟机,并安装了Ansible 1.9.2进行检查。根据在/proc/cpuinfo中使用grep aes命令的结果来看,似乎可以使用AES-NI,但我没有研究它的实际意义。
在host_vars目录下创建100个名为host00.yml到host99.yml的文件,并使用Ansible Vault进行加密。
$ mkdir host_vars
$ ansible-vault create host_vars/host00.yml # 中身を「key1: val1」にする
$ for n in {01..99}; do cp host_vars/host00.yml host_vars/host${n}.yml; done
$ vi vault # ansible-vault実行時に設定したパスワードを記述する
使用以下内容创建清单文件。也就是说,将从host00到host99共100个主机。
[test]
host[00:99]
用以下的内容创建playbook。
- hosts: host00
connection: local
gather_facts: no
tasks:
- debug: var=key1
正如你所看到的,所指的主机只是在清单文件中写的host00,而不是所有的主机。
此外,debug模块在本地主机上执行,因此”connection: local”只是为了更好理解,没有特别的意义。无论如何,在清单中描述的主机实际上不需要存在。
好吧,让我们试着执行一下。
$ time ansible-playbook -i hosts --vault-password-file vault read1.yml
PLAY [host00] *****************************************************************
TASK: [debug var=key1] ********************************************************
ok: [host00] => {
"var": {
"key1": "val1"
}
}
PLAY RECAP ********************************************************************
host00 : ok=1 changed=0 unreachable=0 failed=0
real 1m30.620s
user 1m30.475s
sys 0m0.052s
仅仅这个就需要90秒时间。
假设将库存只限于host00,则它将在1秒左右完成。
[test]
host00
$ time ansible-playbook -i hosts.1 --vault-password-file vault read1.yml
real 0m1.314s
user 0m1.150s
sys 0m0.030s
即使目标主机只有一个,该动作似乎是遍历主机变量文件夹下的所有文件并打开它们,只要它们存在于清单中。
那么我们该怎么办呢?
因此,首先要讨论的是,在只需要从Ansible Vault中获取一个主机的情况下如何加速操作。
一种方法是将每个Playbook的清单文件分开,并尽量减少在清单文件中列出的主机数量,这可能是一种选择,但在后续处理上可能会有些麻烦。
在这里,我们将努力尝试在Playbook内部只获取一个主机。
首先,将先前创建的host_vars重命名,确保不将使用Ansible Vault创建的文件放置在host_vars文件夹中。
$ mv host_vars/ _host_vars
使用lookup插件之一pipe来执行ansible-vault view,并通过set_fact模块将所需主机的内容提取出来并传递。
- hosts: host00
connection: local
gather_facts: no
tasks:
- set_fact: "key1={{ lookup('pipe', 'ansible-vault view _host_vars/' + inventory_hostname + '.yml --vault-password-file vault | grep \"key1: \" | sed \"s/key1: //\"') }}"
- debug: var=key1
我来试试执行这个playbook。
$ time ansible-playbook -i hosts read1a.yml
PLAY [host00] *****************************************************************
TASK: [set_fact key1={{ lookup('pipe', 'ansible-vault view _host_vars/' + inventory_hostname + '.yml --vault-password-file vault | grep "key1: " | sed "s/key1: //"') }}] ***
ok: [host00]
TASK: [debug var=key1] ********************************************************
ok: [host00] => {
"var": {
"key1": "val1"
}
}
PLAY RECAP ********************************************************************
host00 : ok=2 changed=0 unreachable=0 failed=0
real 0m0.819s
user 0m0.732s
sys 0m0.066s
我变得更加迅速,就像我预期的那样。
顺便提一下,如果设置ansible_ssh_pass的值,就可以按预期进行SSH密码登录了。
然而,必须在gather_facts之前设置才能实现,因此playbook会变成以下的样子。
- hosts: host00
gather_facts: no
tasks:
- set_fact: "ansible_ssh_pass={{ lookup('pipe', 'ansible-vault view _host_vars/' + inventory_hostname + '.yml --vault-password-file vault | grep \"ansible_ssh_pass: \" | sed \"s/ansible_ssh_pass: //\"') }}"
- hosts: host00
gather_facts: yes
tasks:
- file: dest=/tmp/1 state=touch
首先,我认为不需要像Ansible Vault这样的东西。
如果不仅需要一个主机,而是需要100个主机会怎么样呢?
- hosts: test
gather_facts: no
serial: 1
tasks:
- set_fact: "key1={{ lookup('pipe', 'ansible-vault view _host_vars/' + inventory_hostname + '.yml --vault-password-file vault | grep \"key1: \" | sed \"s/key1: //\"') }}"
- hosts: test
gather_facts: no
tasks:
- debug: var=key1
这是因为将「serial: 1」增加数量并不会增加速度,而且增加太多会导致读取失败并出现错误。
试一试。
$ time ansible-playbook -i hosts read100a.yml -f 100
real 1m5.342s
user 0m58.082s
sys 0m4.108s
当然会花费时间。
但既然我们只是在执行命令并获取值,为什么不使用其他更快的方式而不是使用Ansible Vault呢?因此,我尝试使用openssl enc。我将使用256位AES,以满足与Ansible Vault相同的条件。
$ mkdir openssl
$ echo "key1: val1" | openssl enc -aes256 -e -kfile vault -out openssl/host00
$ for n in {01..99}; do cp openssl/host00 openssl/host${n}; done
只需更改playbook的set_fact部分。
- hosts: test
gather_facts: no
serial: 1
tasks:
- set_fact: "key1={{ lookup('pipe', 'openssl enc -aes256 -d -kfile vault -in openssl/' + inventory_hostname + ' | grep \"key1: \" | sed \"s/key1: //\"') }}"
- hosts: test
gather_facts: no
tasks:
- debug: var=key1
去试试看吧。
$ time ansible-playbook -i hosts read100b.yml -f 100
real 0m5.489s
user 0m1.956s
sys 0m1.427s
这个是非常十分的。如果主机数量很多的话,或许无需使用Ansible Vault,直接使用这个就可以了吧。
嗯,为了提高安全性,或许可以使用Ansible Vault来获取openssl enc解密密码。这样一来,由于Ansible Vault只被使用一次,对性能影响几乎可以忽略不计,可以在执行playbook时输入密码并运行。
在这种情况下,openssl enc将使用-k选项来设置密码,而不是-kfile选项。
如果你想在playbook中获取其他主机的变量,可以使用hostvars。
“`
debug: var=hostvars[‘host99’].key1
“`
顺便提一下,如果在host_vars文件夹下放置了使用Ansible Vault创建的文件,并且运行了read100.yml(用于读取100个主机的普通操作),那么执行时间为98秒。
- hosts: test
connection: local
gather_facts: no
tasks:
- debug: var=key1
参考:使用其他版本的Ansible时,使用Ansible Vault
尝试使用开发版
如果使用开发版的话,是否不需要进行这样的操作而可以直接常规地使用Ansible Vault呢?
$ sudo yum install git gcc python-devel python-pip
$ sudo pip install paramiko PyYAML Jinja2 httplib2 six
$ git clone git://github.com/ansible/ansible.git --recursive
$ cd ansible/
$ source hacking/env-setup
$ ansible-playbook --version
ansible-playbook 2.0.0 (devel 6154ed1dda) last updated 2015/08/30 20:17:52 (GMT +900)
lib/ansible/modules/core: (detached HEAD 66288d48a2) last updated 2015/08/30 20:18:02 (GMT +900)
lib/ansible/modules/extras: (detached HEAD 8d8f1c510d) last updated 2015/08/30 20:18:16 (GMT +900)
config file =
configured module search path = None
让我们尝试执行一个playbook(read1.yml),该playbook只会获取第一个创建的主机。
$ time ansible-playbook -i hosts --vault-password-file vault read1.yml
real 0m47.208s
user 0m46.656s
sys 0m0.180s
执行时间缩短了大约一半,但还是很慢。
不过据说,如果事先在pip上安装cryptography,速度会更快。
$ sudo yum install libffi-devel openssl-devel
$ sudo pip install cryptography
执行read1.yml。
$ time ansible-playbook -i hosts --vault-password-file vault read1.yml
real 0m7.779s
user 0m7.022s
sys 0m0.156s
还算可以。
获取100个主机的playbook(read100.yml)怎么样?
$ time ansible-playbook -i hosts --vault-password-file vault read100.yml -f 10
real 0m31.422s
user 0m27.608s
sys 0m0.660s
这个问题耗费时间的原因不是Ansible Vault,而是debug模块的输出耗时。
当设置为”-f 100″时,输出失败并报错。
如果将debug模块的部分注释掉,时间大约只需要7秒左右。
顺便说一下,管道插件也出现了错误,无法工作。
Ansible 1.6.10 可以改写为 “Ansible 1.6.10” 或 “Ansible 版本 1.6.10″。
事实上,从1.7版本开始,已经实现了读取在库存中定义的所有主机。
$ sudo yum install gcc python-devel python-pip
$ sudo pip install ansible==1.6.10
读取1.yml当然是快的。
$ time ansible-playbook -i hosts --vault-password-file vault read1.yml
real 0m1.008s
user 0m0.669s
sys 0m0.091s
阅读100个.yml文件可能会花费一些时间,但比1.9.2版本更快。
$ time ansible-playbook -i hosts --vault-password-file vault read100.yml -f 100
real 0m48.760s
user 0m46.572s
sys 0m0.753s