使用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
广告
将在 10 秒后关闭
bannerAds