优化Ansible速度
1. Ansible与SaltStack的对比
特点 | Ansible | SaltStack |
---|---|---|
语言 | 使用YAML语法编写Playbooks | 使用Python语法编写States |
是否有客户端 | 无 | 有 |
运行方式 | Push模式,通过SSH远程执行操作 | Push或Pull模式,通过ZeroMQ进行通信 |
应用范围 | 适用于配置管理、自动化部署、应用发布等 | 适用于配置管理、监控、自动部署 |
扩展性 | 插件丰富,易于扩展功能 | 拥有强大的扩展性,能够定制各种功能 |
管理和监控 | 简单易用,可直接在控制端执行操作 | 开箱即用,自带管理和监控功能 |
社区支持 | 拥有庞大的社区用户群 | 社区规模较小,但质量较高 |
学习曲线 | 相对较低,易上手 | 学习曲线较陡峭,需要一定的技术基础 |
安全可控 | 通过SSH加密传输数据,较为安全 | 通过ZeroMQ传输数据,也较为安全 |
有些人说Ansible的执行效率比SaltStack低,确实,使用默认的SSH方式通信,效率远低于SaltStack的zeromq消息队列。下面来介绍一些优化Ansible执行速度的方法。
1.1 VirtualBox虚拟机说明
使用以下环境进行测试。
序号 | 虚拟机 | 主机名 | IP | CPU | 内存 | 说明 |
---|---|---|---|---|---|---|
1 | ansible-master | ansible | 192.168.56.120 | 2核 | 4G | Ansible控制节点 |
2 | ansible-node1 | node1 | 192.168.56.121 | 2核 | 2G | Ansible工作节点1 |
3 | ansible-node2 | node2 | 192.168.56.122 | 2核 | 2G | Ansible工作节点2 |
4 | ansible-node3 | node3 | 192.168.56.123 | 2核 | 2G | Ansible工作节点3 |
1.2 测试剧本说明
你可以参考ansible role角色(4)--include的使用 我们使用该剧本来测试执行时间。
由于我之前多次执行过剧本,相关配置差不多都配置到呼工作节点了。此时执行一遍剧本文件,看看用时多久:
# 第一次统计输出时间
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
TASK [base : Set hostname] *******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.123]
ok: [192.168.56.121]
TASK [base : Get SELinux value] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.122]
ok: [192.168.56.121]
TASK [base : Set SELinux prints warnings instead of enforcing] *******************************************************************************************************************************************************************************************************************************
skipping: [192.168.56.121]
skipping: [192.168.56.122]
skipping: [192.168.56.123]
TASK [base : Ensure SELinux is set to disable mode] ******************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Get SELinux value] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Create a directory if it does not exist] ****************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Create backup directory] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.123]
ok: [192.168.56.122]
TASK [base : Backup old repo config] *********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
TASK [base : Create backup directory] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Copy repo and pypi config] ******************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.121] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
ok: [192.168.56.123] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
ok: [192.168.56.122] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
TASK [base : ensure a list of packages installed] ********************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [create base folder] ********************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121]
changed: [192.168.56.122]
changed: [192.168.56.123]
TASK [base : Extract safe-rm-0.12.tar.gz into /srv/safe-rm] **********************************************************************************************************************************************************************************************************************************
changed: [192.168.56.122]
changed: [192.168.56.121]
changed: [192.168.56.123]
TASK [base : Move safe-rm to /usr/bin] *******************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Delete temp folder] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.122]
changed: [192.168.56.121]
changed: [192.168.56.123]
TASK [base : Copy safe-rm config] ************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.123]
ok: [192.168.56.122]
TASK [base : Update pip command] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.123]
changed: [192.168.56.122]
changed: [192.168.56.121]
TASK [base : Install python package] *********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.123]
ok: [192.168.56.121]
TASK [base : Sync time at every 10 minutes] **************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.123]
ok: [192.168.56.121]
TASK [base : Sync time at 2:30 am] ***********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.123]
ok: [192.168.56.122]
TASK [base : Print the IP] *******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "HOST_IP: 192.168.56.121"
}
ok: [192.168.56.122] => {
"msg": "HOST_IP: 192.168.56.122"
}
ok: [192.168.56.123] => {
"msg": "HOST_IP: 192.168.56.123"
}
TASK [base : Remove sshkey file] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.122] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.123] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.121] => (item=/root/.ssh/id_rsa.pub)
changed: [192.168.56.122] => (item=/root/.ssh/id_rsa.pub)
changed: [192.168.56.123] => (item=/root/.ssh/id_rsa.pub)
TASK [base : Generate SSH key pair] **********************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121]
changed: [192.168.56.122]
changed: [192.168.56.123]
TASK [base : Copy alias config] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.121]
ok: [192.168.56.122]
TASK [base : Insert block to .bashrc] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m25.265s
user 0m9.161s
sys 0m4.371s
[root@ansible ansible_playbooks]#
时间输出结果说明:
real是程序的实际运行时间,从程序开始到程序执行结束时所消耗的时间,包括CPU的用时和所有延迟程序执行的因素的总和。CPU用时被划分为user和sys两块。
user是用户态的时间,表示程序本身,以及它所调用的库中的子例程使用的时间。
sys是内核态的时间,是由程序直接或间接调用的系统调用执行的时间。
单核情况,real远远大于user和sys之和。
real=CPU用时+其他因素时间。
CPU用时=user+sys。
因此,我们在此处主要关注real
用时输出。
重复再执行三次,看输出结果:
# 第2次执行,统计输出时间
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m16.135s
user 0m9.308s
sys 0m4.259s
[root@ansible ansible_playbooks]#
# 第3次执行,统计输出时间
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m15.673s
user 0m9.404s
sys 0m3.874s
[root@ansible ansible_playbooks]#
# 第4次执行,统计输出时间
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m15.562s
user 0m9.466s
sys 0m3.725s
[root@ansible ansible_playbooks]#
可以看到,后面3次实际用时差不多都是16秒钟。我们后面测试就来对比这个时间。
2. 优化策略
2.1 开启SSH长连接
在OpenSSH 5.6版本以后SSH就支持了Multiplexing。如果Ansible控制节点SSH版本高于5.6就可以开启SSH长连接。
我们来检查一下:
[root@ansible ~]# ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017
[root@ansible ~]#
可以看到,控制节点SSH版本为OpenSSH_7.4p1,满足要求。
直接在ansible.cfg
文件中设置SSH长连接即可。设置参数如下:
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
ControlPersist=5d
这个参数是设置整个长连接保持时间为5天。如果开启该功能,通过SSH连接过的的设备都会在当前~/.ansible/cp
目录下生成一个socket文件。
先来看看配置文件中有没有这个参数:
[root@ansible ~]# grep sh_args /etc/ansible/ansible.cfg
#ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
[root@ansible ~]#
可以看到,默认注释掉了该参数。
修改前,先备份一下原来的配置文件:
[root@ansible ~]# ll /etc/ansible/ansible.cfg*
-rw-r--r--. 1 root root 19985 Jan 16 2022 /etc/ansible/ansible.cfg
[root@ansible ~]# cp -p /etc/ansible/ansible.cfg /etc/ansible/ansible.cfg.default
然后使用vim编辑/etc/ansible/ansible.cfg配置文件,并增加ssh_args
参数,修改后查看配置信息:
[root@ansible ~]# grep -C5 sh_args /etc/ansible/ansible.cfg
[ssh_connection]
# ssh arguments to use
# Leaving off ControlPersist will result in poor performance, so use
# paramiko on older platforms rather than removing it, -C controls compression use
#ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
# The base directory for the ControlPath sockets.
# This is the "%(directory)s" in the control_path option
#
# Example:
[root@ansible ~]#
为了检查后面会不会连接长连接,先安装net-tools
包,然后使用netstat
命令查看当前连接信息:
[root@ansible ~]# yum install net-tools
Loaded plugins: fastestmirror
Determining fastest mirrors
base | 3.6 kB 00:00:00
epel | 4.7 kB 00:00:00
extras | 2.9 kB 00:00:00
updates | 2.9 kB 00:00:00
(1/5): epel/x86_64/group_gz | 100 kB 00:00:00
(2/5): epel/x86_64/updateinfo | 1.0 MB 00:00:00
(3/5): extras/7/x86_64/primary_db | 250 kB 00:00:00
(4/5): epel/x86_64/primary_db | 7.0 MB 00:00:01
(5/5): updates/7/x86_64/primary_db | 25 MB 00:00:08
Resolving Dependencies
--> Running transaction check
---> Package net-tools.x86_64 0:2.0-0.25.20131004git.el7 will be installed
--> Finished Dependency Resolution
Dependencies Resolved
==============================================================================================================================================================================================================================================================================================
Package Arch Version Repository Size
==============================================================================================================================================================================================================================================================================================
Installing:
net-tools x86_64 2.0-0.25.20131004git.el7 base 306 k
Transaction Summary
==============================================================================================================================================================================================================================================================================================
Install 1 Package
Total download size: 306 k
Installed size: 917 k
Is this ok [y/d/N]: y
Downloading packages:
net-tools-2.0-0.25.20131004git.el7.x86_64.rpm | 306 kB 00:00:00
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
Installing : net-tools-2.0-0.25.20131004git.el7.x86_64 1/1
Verifying : net-tools-2.0-0.25.20131004git.el7.x86_64 1/1
Installed:
net-tools.x86_64 0:2.0-0.25.20131004git.el7
Complete!
[root@ansible ~]# netstat -ato
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 localhost:smtp 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 ansible:37438 101.6.15.130:https TIME_WAIT timewait (41.86/0/0)
tcp 0 0 ansible:37436 101.6.15.130:https TIME_WAIT timewait (57.06/0/0)
tcp 0 0 ansible:37444 101.6.15.130:https TIME_WAIT timewait (49.59/0/0)
tcp 0 0 ansible:37446 101.6.15.130:https TIME_WAIT timewait (57.04/0/0)
tcp 0 48 ansible-master:ssh 192.168.56.1:8421 ESTABLISHED on (0.22/0/0)
tcp 0 0 ansible:37442 101.6.15.130:https TIME_WAIT timewait (43.11/0/0)
tcp 0 0 ansible:37439 101.6.15.130:https TIME_WAIT timewait (49.55/0/0)
tcp 0 0 ansible-master:ssh 192.168.56.1:8423 ESTABLISHED keepalive (4321.38/0/0)
tcp6 0 0 [::]:ssh [::]:* LISTEN off (0.00/0/0)
tcp6 0 0 localhost:smtp [::]:* LISTEN off (0.00/0/0)
[root@ansible ~]#
切换到剧本目录,再次执行剧本:
[root@ansible ~]# cd ansible_playbooks/
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
TASK [base : Set hostname] *******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Get SELinux value] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.122]
ok: [192.168.56.121]
TASK [base : Set SELinux prints warnings instead of enforcing] *******************************************************************************************************************************************************************************************************************************
skipping: [192.168.56.121]
skipping: [192.168.56.122]
skipping: [192.168.56.123]
TASK [base : Ensure SELinux is set to disable mode] ******************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.121]
ok: [192.168.56.122]
TASK [base : Get SELinux value] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Create a directory if it does not exist] ****************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.122]
ok: [192.168.56.121]
TASK [base : Create backup directory] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Backup old repo config] *********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
TASK [base : Create backup directory] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Copy repo and pypi config] ******************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.122] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
ok: [192.168.56.123] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
ok: [192.168.56.121] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
TASK [base : ensure a list of packages installed] ********************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [create base folder] ********************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.122]
changed: [192.168.56.121]
changed: [192.168.56.123]
TASK [base : Extract safe-rm-0.12.tar.gz into /srv/safe-rm] **********************************************************************************************************************************************************************************************************************************
changed: [192.168.56.123]
changed: [192.168.56.122]
changed: [192.168.56.121]
TASK [base : Move safe-rm to /usr/bin] *******************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Delete temp folder] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121]
changed: [192.168.56.123]
changed: [192.168.56.122]
TASK [base : Copy safe-rm config] ************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Update pip command] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.123]
changed: [192.168.56.122]
changed: [192.168.56.121]
TASK [base : Install python package] *********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.123]
ok: [192.168.56.121]
TASK [base : Sync time at every 10 minutes] **************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Sync time at 2:30 am] ***********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Print the IP] *******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "HOST_IP: 192.168.56.121"
}
ok: [192.168.56.122] => {
"msg": "HOST_IP: 192.168.56.122"
}
ok: [192.168.56.123] => {
"msg": "HOST_IP: 192.168.56.123"
}
TASK [base : Remove sshkey file] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.122] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.123] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.123] => (item=/root/.ssh/id_rsa.pub)
changed: [192.168.56.121] => (item=/root/.ssh/id_rsa.pub)
changed: [192.168.56.122] => (item=/root/.ssh/id_rsa.pub)
TASK [base : Generate SSH key pair] **********************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121]
changed: [192.168.56.123]
changed: [192.168.56.122]
TASK [base : Copy alias config] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Insert block to .bashrc] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m16.704s
user 0m9.431s
sys 0m4.175s
[root@ansible ansible_playbooks]#
可以看到,开启长连接后,第一次执行剧本,用时16s,与未开启长连接前用时一致。
检查是否用长连接:
[root@ansible ansible_playbooks]# netstat -ato
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 localhost:smtp 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 ansible-master:48610 ansible-node3:ssh ESTABLISHED keepalive (7040.48/0/0)
tcp 0 0 ansible-master:36912 ansible-node2:ssh ESTABLISHED keepalive (7040.48/0/0)
tcp 0 0 ansible-master:44752 ansible-node1:ssh ESTABLISHED keepalive (7040.48/0/0)
tcp 0 48 ansible-master:ssh 192.168.56.1:8421 ESTABLISHED on (0.23/0/0)
tcp 0 0 ansible-master:ssh 192.168.56.1:8423 ESTABLISHED keepalive (4025.82/0/0)
tcp6 0 0 [::]:ssh [::]:* LISTEN off (0.00/0/0)
tcp6 0 0 localhost:smtp [::]:* LISTEN off (0.00/0/0)
[root@ansible ansible_playbooks]# ll ~/.ansible/cp/
total 0
srw-------. 1 root root 0 Mar 17 12:18 6e835d9f0e
srw-------. 1 root root 0 Mar 17 12:18 a734bde817
srw-------. 1 root root 0 Mar 17 12:18 f59c3dce9d
[root@ansible ansible_playbooks]#
可以看到,长连接建立了,对立socket文件也生成了。
也可以通过以下命令判断~/.ansible/cp
目录下的文件是socket
文件:
[root@ansible ansible_playbooks]# file ~/.ansible/cp/6e835d9f0e
/root/.ansible/cp/6e835d9f0e: socket
[root@ansible ansible_playbooks]# file ~/.ansible/cp/a734bde817
/root/.ansible/cp/a734bde817: socket
[root@ansible ansible_playbooks]# file ~/.ansible/cp/f59c3dce9d
/root/.ansible/cp/f59c3dce9d: socket
[root@ansible ansible_playbooks]#
在工作节点上面检查一下:
# 在节点1上检查连接
[root@ansible-node1 ~]# netstat -ato|head -n 2 && netstat -ato|grep ansible
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 ansible-node1:ssh 192.168.56.1:9859 ESTABLISHED keepalive (7084.41/0/0)
tcp 0 0 ansible-node1:ssh 192.168.56.120:44752 ESTABLISHED keepalive (6789.50/0/0)
tcp 0 0 ansible-node1:ssh 192.168.56.1:9861 ESTABLISHED keepalive (7084.41/0/0)
[root@ansible-node1 ~]#
# 在节点2上检查连接
[root@ansible-node2 ~]# netstat -ato|head -n 2 && netstat -ato|grep ansible
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 0 ansible-node2:ssh 192.168.56.1:9899 ESTABLISHED keepalive (7215.16/0/0)
tcp 0 0 ansible-node2:ssh 192.168.56.120:36912 ESTABLISHED keepalive (6723.64/0/0)
tcp 0 0 ansible-node2:ssh 192.168.56.1:9897 ESTABLISHED keepalive (7215.16/0/0)
[root@ansible-node2 ~]#
# 在节点3上检查连接
[root@ansible-node3 ~]# netstat -ato|head -n 2 && netstat -ato|grep ansible
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State Timer
tcp 0 160 ansible-node3:ssh 192.168.56.1:iua ESTABLISHED on (0.22/0/0)
tcp 0 0 ansible-node3:ssh 192.168.56.120:48610 ESTABLISHED keepalive (6732.82/0/0)
tcp 0 0 ansible-node3:ssh 192.168.:multicast-ping ESTABLISHED keepalive (7207.95/0/0)
[root@ansible-node3 ~]#
可以看到,工作节点上面也正常显示了与Ansible控制节点的连接。
建立连接后,再次执行一下剧本,看看是否会降低用时:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
TASK [base : Set hostname] *******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.123]
ok: [192.168.56.122]
TASK [base : Get SELinux value] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.122]
ok: [192.168.56.121]
TASK [base : Set SELinux prints warnings instead of enforcing] *******************************************************************************************************************************************************************************************************************************
skipping: [192.168.56.121]
skipping: [192.168.56.122]
skipping: [192.168.56.123]
TASK [base : Ensure SELinux is set to disable mode] ******************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Get SELinux value] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Create a directory if it does not exist] ****************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Create backup directory] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Backup old repo config] *********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d.bak', u'src': u'/etc/yum.repos.d'})
TASK [base : Create backup directory] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Copy repo and pypi config] ******************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d/Centos-7.repo', u'src': u'Centos-7.repo'})
ok: [192.168.56.122] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.121] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.123] => (item={u'dest': u'/etc/yum.repos.d/epel-7.repo', u'src': u'epel-7.repo'})
ok: [192.168.56.122] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
ok: [192.168.56.121] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
ok: [192.168.56.123] => (item={u'dest': u'~/.pip/pip.conf', u'src': u'pip.conf'})
TASK [base : ensure a list of packages installed] ********************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.123]
ok: [192.168.56.122]
TASK [create base folder] ********************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121]
changed: [192.168.56.123]
changed: [192.168.56.122]
TASK [base : Extract safe-rm-0.12.tar.gz into /srv/safe-rm] **********************************************************************************************************************************************************************************************************************************
changed: [192.168.56.122]
changed: [192.168.56.123]
changed: [192.168.56.121]
TASK [base : Move safe-rm to /usr/bin] *******************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.121]
ok: [192.168.56.123]
TASK [base : Delete temp folder] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121]
changed: [192.168.56.122]
changed: [192.168.56.123]
TASK [base : Copy safe-rm config] ************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.121]
ok: [192.168.56.122]
TASK [base : Update pip command] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.123]
changed: [192.168.56.121]
changed: [192.168.56.122]
TASK [base : Install python package] *********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.122]
ok: [192.168.56.123]
ok: [192.168.56.121]
TASK [base : Sync time at every 10 minutes] **************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Sync time at 2:30 am] ***********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.123]
ok: [192.168.56.122]
TASK [base : Print the IP] *******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "HOST_IP: 192.168.56.121"
}
ok: [192.168.56.122] => {
"msg": "HOST_IP: 192.168.56.122"
}
ok: [192.168.56.123] => {
"msg": "HOST_IP: 192.168.56.123"
}
TASK [base : Remove sshkey file] *************************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.121] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.122] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.123] => (item=/root/.ssh/id_rsa)
changed: [192.168.56.122] => (item=/root/.ssh/id_rsa.pub)
changed: [192.168.56.121] => (item=/root/.ssh/id_rsa.pub)
changed: [192.168.56.123] => (item=/root/.ssh/id_rsa.pub)
TASK [base : Generate SSH key pair] **********************************************************************************************************************************************************************************************************************************************************
changed: [192.168.56.123]
changed: [192.168.56.122]
changed: [192.168.56.121]
TASK [base : Copy alias config] **************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Insert block to .bashrc] ********************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.122]
ok: [192.168.56.121]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m20.642s
user 0m9.591s
sys 0m4.031s
[root@ansible ansible_playbooks]#
奇怪了,用时还超了,变成了20.6秒!!
再执行一次,用时还是变多了:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m21.651s
user 0m9.436s
sys 0m4.177s
[root@ansible ansible_playbooks]#
通过以上实验可以看到:
- 开启长连接后,Ansible会保持和目标主机的持续连接,减少了连接的建立和断开时间,但是在执行剧本时,由于要维持这种长连接,可能会增加一些额外的网络开销和系统资源的消耗,导致执行剧本的时间变长。此外,可能还会受到网络延迟等因素的影响,进一步增加执行剧本的时间。因此,尽管长连接可以提高效率,但在某些情况下也可能导致执行时间变长。
2.2 开启pipelining
- pipelining也是OpenSSH的一个特性。
- 如果开启了pipelining功能,Ansible会改变默认的执行过程,默认情况下,Ansible有一个流程是把生成好的本地Python脚本PUT到远程服务器,开启pipelining功能后,这个过程将会在SSH的会话中进行,这样可以大大提高整个执行效率。
- 但开启pipelining,需要被控主机
/etc/sudoers
文件编辑当前Ansible SSH用户为requiretty
,否则在执行时会报异常。
修改/etc/ansible/ansible.cfg
后,查看配置情况:
[root@ansible ansible_playbooks]# grep pipelining /etc/ansible/ansible.cfg
# Enabling pipelining reduces the number of SSH operations required to
#pipelining = False
pipelining = True
# The -tt argument is passed to ssh when pipelining is not enabled because sudo
[root@ansible ansible_playbooks]#
此时执行剧本:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m12.928s
user 0m7.716s
sys 0m2.435s
[root@ansible ansible_playbooks]#
可以看到,用时减少了,再执行一次:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m12.877s
user 0m7.510s
sys 0m2.749s
[root@ansible ansible_playbooks]#
可以看到,开启了pipelining功能后,总用时约为13秒,相当于默认情况下约快了3秒钟。
如果开启-vvvv
详细日志参数,可以看到日志中会出现很多Pipelining is enabled
的信息:
我们将配置文件中新增加的pipelining = True
删除掉:
# 关闭pipelining功能
[root@ansible ansible_playbooks]# grep pipelining /etc/ansible/ansible.cfg
# Enabling pipelining reduces the number of SSH operations required to
#pipelining = False
# The -tt argument is passed to ssh when pipelining is not enabled because sudo
[root@ansible ansible_playbooks]#
再执行剧本:
日志中没有出现Pipelining is enabled
的信息。
注意,开启-vvvv
详细日志参数时,剧本执行时间会增加。
按我们测试的剧本来算,默认情况下用时是16秒,开启pipelining功能后用时13秒,速度优化3秒,优化百分比为3/16*100%=18.75%
,提升还是不错的。
2.3 开启accelerate模式
Ansible还有一个accelerate加速模式,这与前面SSH的Multiplexing有点类似,因为都依赖Ansible中控机跟远程机器有一个长连接。
但是accelerate是使用Python程序在远程主机上运行一个守护进程,然后Ansible会通过这个守护进程监控的端口进行通信,开启accelerate模式很简单,只需要在Ansible playbook中配置
accelerate: true
即可。需要注意的是,如果开启accelerate加速模式,则需要在Ansible中控机和远端机器都安装python-keyczar软件包。
下面是在/etc/ansible/ansible.cfg
中配置的accelerate加速模式相关的参数:
[root@ansible ansible_playbooks]# grep -n -C2 accelerate /etc/ansible/ansible.cfg
444-#command_timeout = 30
445-
446:[accelerate]
447:#accelerate_port = 5099
448:#accelerate_timeout = 30
449:#accelerate_connect_timeout = 5.0
450-
451-# The daemon timeout is measured in minutes. This time is measured
452:# from the last activity to the accelerate daemon.
453:#accelerate_daemon_timeout = 30
454-
455:# If set to yes, accelerate_multi_key will allow multiple
456-# private keys to be uploaded to it, though each user must
457-# have access to the system via SSH to add a new key. The default
458-# is "no".
459:#accelerate_multi_key = yes
460-
461-[selinux]
[root@ansible ansible_playbooks]#
我们先不安装包,直接修改剧本文件base.yml
,增加accelerate: true
配置,修改后,查看base.yml
内容:
[root@ansible ansible_playbooks]# cat base.yml
---
- hosts: basehosts
accelerate: true
roles:
- base
然后执行剧本,直接报错了:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
ERROR! 'accelerate' is not a valid attribute for a Play
The error appears to be in '/root/ansible_playbooks/base.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
---
- hosts: basehosts
^ here
real 0m0.499s
user 0m0.420s
sys 0m0.079s
[root@ansible ansible_playbooks]#
提示'accelerate' is not a valid attribute for a Play
,即accelerate不是剧本的有效属性。
这里可以找到10年前accelerate.py的源码:accelerate.py
我用Python 3.6.8版本,pip安装ansible 4.10.0也报相同的异常,因此暂时忽略此加速方案。
2.4 设置fact缓存
- Ansible在执行剧本时,默认第一个task是
TASK [Gathering Facts]
,这个任务就是Ansible收集每台主机的facts信息。方便我们在剧本中直接引用facts里面的信息。 - 如果你的剧本里面不需要facts信息,可以在playbook中设置
gather_facts: False
来提高playbook效率。 - 如果我们既要在每次执行playbook时都能收集facts,又想加速这个收集过程,那么就需要配置facts缓存了。
为了测试是否能够正常缓存facts事实变量,我们增加一个自定义的fact配置,详细可参考setup事实变量模块。
在三个节点上面创建目录/etc/ansible/facts.d
,并创建文件/etc/ansible/facts.d/myself.fact
,创建完成后查看配置内容:
[root@ansible-node1 ~]# mkdir -p /etc/ansible/facts.d
[root@ansible-node1 ~]# echo -e "[myfacts]\nmyself_fact=1" > /etc/ansible/facts.d/myself.fact
[root@ansible-node1 ~]# cat /etc/ansible/facts.d/myself.fact
[myfacts]
myself_fact=1
[root@ansible-node1 ~]#
然后在Ansible控制节点查看自定义fact信息:
[root@ansible ansible_playbooks]# ansible -i base_hosts.ini all -m ansible.builtin.setup -a "filter=ansible_local" -o
192.168.56.123 | SUCCESS => {"ansible_facts": {"ansible_local": {"myself": {"myfacts": {"myself_fact": "1"}}}, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
192.168.56.121 | SUCCESS => {"ansible_facts": {"ansible_local": {"myself": {"myfacts": {"myself_fact": "1"}}}, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
192.168.56.122 | SUCCESS => {"ansible_facts": {"ansible_local": {"myself": {"myfacts": {"myself_fact": "1"}}}, "discovered_interpreter_python": "/usr/bin/python"}, "changed": false}
[root@ansible ansible_playbooks]#
可以看到,正常获取到了我自定义的fact事实变量。
在测试前,再次执行两次剧本:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m15.347s
user 0m9.214s
sys 0m3.838s
[root@ansible ansible_playbooks]#
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml
...过程输出省略
real 0m15.472s
user 0m8.931s
sys 0m4.202s
[root@ansible ansible_playbooks]#
执行剧本用时差不多还是16秒钟。
查看现有配置:
[root@ansible ~]# grep -nE -C5 'fact_cach|gathering' /etc/ansible/ansible.cfg
31-# the remote system.
32-#
33-# smart - gather by default, but don't regather if already gathered
34-# implicit - gather by default, turn off with gather_facts: False
35-# explicit - do not gather by default, must say gather_facts: True
36:#gathering = implicit
37-
38:# This only affects the gathering done by a play's gather_facts directive,
39:# by default gathering retrieves all facts subsets
40-# all - gather all subsets
41-# network - gather min and network facts
42-# hardware - gather hardware facts (longest facts to retrieve)
43-# virtual - gather min and virtual facts
44-# facter - import facts from facter
--
238-# if set to a persistent type (not 'memory', for example 'redis') fact values
239-# from previous runs in Ansible will be stored. This may be useful when
240-# wanting to use, for example, IP information from one group of servers
241-# without having to talk to them in the same playbook run to get their
242-# current IP information.
243:#fact_caching = memory
244-
245-#This option tells Ansible where to cache facts. The value is plugin dependent.
246-#For the jsonfile plugin, it should be a path to a local directory.
247:#For the redis plugin, the value is a host:port:database triplet: fact_caching_connection = localhost:6379:0
248-
249:#fact_caching_connection=/tmp
250-
251-
252-
253-# retry files
254-# When a playbook fails a .retry file can be created that will be placed in ~/
[root@ansible ~]#
2.4.1 使用json文件进行缓存
修改/etc/ansible/ansible.cfg
配置文件中以下三个参数:
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp
修改配置,使用json文件缓存:
[root@ansible ~]# grep -nE -C5 'fact_cach|gathering' /etc/ansible/ansible.cfg
31-# the remote system.
32-#
33-# smart - gather by default, but don't regather if already gathered
34-# implicit - gather by default, turn off with gather_facts: False
35-# explicit - do not gather by default, must say gather_facts: True
36:#gathering = implicit
37:gathering = smart
38-
39:# This only affects the gathering done by a play's gather_facts directive,
40:# by default gathering retrieves all facts subsets
41-# all - gather all subsets
42-# network - gather min and network facts
43-# hardware - gather hardware facts (longest facts to retrieve)
44-# virtual - gather min and virtual facts
45-# facter - import facts from facter
--
239-# if set to a persistent type (not 'memory', for example 'redis') fact values
240-# from previous runs in Ansible will be stored. This may be useful when
241-# wanting to use, for example, IP information from one group of servers
242-# without having to talk to them in the same playbook run to get their
243-# current IP information.
244:#fact_caching = memory
245:fact_caching = jsonfile
246-
247-#This option tells Ansible where to cache facts. The value is plugin dependent.
248-#For the jsonfile plugin, it should be a path to a local directory.
249:#For the redis plugin, the value is a host:port:database triplet: fact_caching_connection = localhost:6379:0
250-
251:fact_caching_connection=/tmp
252-
253-
254-
255-# retry files
256-# When a playbook fails a .retry file can be created that will be placed in ~/
[root@ansible ~]#
注意,fact_caching_connection=/tmp
这个配置一定要打开,要不然后执行剧本时会报以下警告:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -v
Using /etc/ansible/ansible.cfg as config file
[WARNING]: No setting was provided for required configuration plugin_type: cache plugin: jsonfile setting: _uri
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.121]
ok: [192.168.56.122]
...过程输出省略
[root@ansible ansible_playbooks]#
此时不会生成缓存文件。
为了验证是否正常收集fact,开启-v
参数:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121]
ok: [192.168.56.122]
ok: [192.168.56.123]
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
...过程输出省略
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m15.348s
user 0m9.233s
sys 0m3.940s
[root@ansible ansible_playbooks]#
此时,查看/tmp
目录下文件:
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.121|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "1"
}
}
}
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.122|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "1"
}
}
}
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.123|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "1"
}
}
}
[root@ansible ansible_playbooks]#
可以看到,生成的缓存文件。再次执行一次剧本:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
TASK [base : Set hostname] **************
...过程输出省略
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m16.801s
user 0m9.292s
sys 0m4.170s
[root@ansible ansible_playbooks]#
此时,可以看到,此时已经没有TASK [Gathering Facts]
这一步任务了,但最后执行任务用时16.8秒,用时还变多了。
再执行一次剧本,用时15.889秒。可以看到,并没有节省多少时间。
如果我们此时更新三个节点上面的自定义变量:
[root@ansible-node1 ~]# echo -e "[myfacts]\nmyself_fact=2" > /etc/ansible/facts.d/myself.fact
[root@ansible-node1 ~]# cat /etc/ansible/facts.d/myself.fact
[myfacts]
myself_fact=2
[root@ansible-node1 ~]#
然后再执行剧本:
Using /etc/ansible/ansible.cfg as config file
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
TASK [base : Set hostname] *****
...过程输出省略
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m14.830s
user 0m8.939s
sys 0m3.983s
[root@ansible ansible_playbooks]#
此时,执行时间降低了!
查看自定义事实缓存文件和配置文件:
[root@ansible ansible_playbooks]# ll /tmp
total 84
-rw-r--r--. 1 root root 27350 Mar 18 19:59 192.168.56.121
-rw-r--r--. 1 root root 27685 Mar 18 19:59 192.168.56.122
-rw-r--r--. 1 root root 27727 Mar 18 19:59 192.168.56.123
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.121|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "1"
}
}
}
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.122|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "1"
}
}
}
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.123|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "1"
}
}
}
[root@ansible ansible_playbooks]#
可以看到,缓存后,当远程主机上面自定义的变量更新后,在缓存文件中并不会马上更新。
手动执行一次获取事实变量:
# 手动获取事实变量,可以看到已经获取到远程事实变量myself_fact新值2
[root@ansible ansible_playbooks]# ansible -i base_hosts.ini all -m ansible.builtin.setup -a "filter=ansible_local" -o
192.168.56.123 | SUCCESS => {"ansible_facts": {"ansible_local": {"myself": {"myfacts": {"myself_fact": "2"}}}}, "changed": false}
192.168.56.121 | SUCCESS => {"ansible_facts": {"ansible_local": {"myself": {"myfacts": {"myself_fact": "2"}}}}, "changed": false}
192.168.56.122 | SUCCESS => {"ansible_facts": {"ansible_local": {"myself": {"myfacts": {"myself_fact": "2"}}}}, "changed": false}
# 缓存文件也更新了
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.123|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "2"
}
}
}
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.122|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "2"
}
}
}
[root@ansible ansible_playbooks]# cat /tmp/192.168.56.121|jq '.ansible_local'
{
"myself": {
"myfacts": {
"myself_fact": "2"
}
}
}
[root@ansible ansible_playbooks]# ll /tmp
total 84
-rw-r--r--. 1 root root 27350 Mar 18 20:05 192.168.56.121
-rw-r--r--. 1 root root 27685 Mar 18 20:05 192.168.56.122
-rw-r--r--. 1 root root 27727 Mar 18 20:05 192.168.56.123
[root@ansible ansible_playbooks]#
2.4.2 使用redis进行缓存
首先在Ansible控制节点安装redis服务并修改配置文件,设置redis密码,并后台启动:
# 安装redis
[root@ansible ~]# yum install redis -y
# 安装后,修改配置文件,设置后台启动并设置密码
[root@ansible ~]# grep -E '^requirepass|^daemon' /etc/redis.conf
daemonize yes
requirepass foobared
[root@ansible ~]#
# 启动redis服务
[root@ansible ~]# systemctl status redis
# 测试redis命令行
[root@ansible ~]# /usr/bin/redis-cli -h 127.0.0.1 -p 6379 -a foobared
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> exit
[root@ansible ~]#
可以看到redis缓存能够正常使用,并且此时没有缓存任何键值。
修改/etc/ansible/ansible.cfg
配置文件中以下几个参数:
gathering = smart
fact_caching = redis
# 缓存时间300秒
fact_caching_timeout = 300
# 带密码的redis配置方式,不带密码时,直接配置成localhost:6379:0
fact_caching_connection = localhost:6379:0:foobared
修改后查看配置:
[root@ansible ansible_playbooks]# grep -nE -C5 'fact_cach|gathering' /etc/ansible/ansible.cfg
31-# the remote system.
32-#
33-# smart - gather by default, but don't regather if already gathered
34-# implicit - gather by default, turn off with gather_facts: False
35-# explicit - do not gather by default, must say gather_facts: True
36:#gathering = implicit
37:gathering = smart
38-
39:# This only affects the gathering done by a play's gather_facts directive,
40:# by default gathering retrieves all facts subsets
41-# all - gather all subsets
42-# network - gather min and network facts
43-# hardware - gather hardware facts (longest facts to retrieve)
44-# virtual - gather min and virtual facts
45-# facter - import facts from facter
--
239-# if set to a persistent type (not 'memory', for example 'redis') fact values
240-# from previous runs in Ansible will be stored. This may be useful when
241-# wanting to use, for example, IP information from one group of servers
242-# without having to talk to them in the same playbook run to get their
243-# current IP information.
244:#fact_caching = memory
245:fact_caching = redis
246-
247-#This option tells Ansible where to cache facts. The value is plugin dependent.
248-#For the jsonfile plugin, it should be a path to a local directory.
249:#For the redis plugin, the value is a host:port:database triplet: fact_caching_connection = localhost:6379:0
250-
251:fact_caching_connection = localhost:6379:0:foobared
252:fact_caching_timeout = 300
253-
254-
255-# retry files
256-# When a playbook fails a .retry file can be created that will be placed in ~/
257-# You can enable this feature by setting retry_files_enabled to True
[root@ansible ansible_playbooks]#
执行剧本:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -v
Using /etc/ansible/ansible.cfg as config file
[WARNING]: The 'redis' python module (version 2.4.5 or newer) is required for the redis fact cache, 'pip install redis'
...过程输出省略
可以看到,redis fact缓存需要安装python redis依赖包。
# 查看ansible版本
[root@ansible ansible_playbooks]# ansible --version
ansible 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Oct 14 2020, 14:45:30) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
[root@ansible ansible_playbooks]#
对应用的Python是2.7.5。
由于python版本较低,由没有pip命令,在pip-20.2.4.tar.gz下载安装文件pip-20.2.4.tar.gz,并解压安装:
我们安装对应的依赖包:
[root@ansible softs]# cd pip-20.2.4
[root@ansible pip-20.2.4]# python setup.py build
[root@ansible pip-20.2.4]# python setup.py install
[root@ansible pip-20.2.4]# pip install redis
[root@ansible pip-20.2.4]# pip list|grep redis
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
redis 3.5.3
[root@ansible cd]#
[root@ansible ~]# python
Python 2.7.5 (default, Oct 14 2020, 14:45:30)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import redis
>>> r = redis.Redis(host='localhost', port=6379, db=0, password='foobared')
>>> r.set('foo', 'bar')
True
>>> r.get('foo')
'bar'
>>> exit()
[root@ansible redis-2.4.5]#
检查redis缓存:
[root@ansible ansible_playbooks]# /usr/bin/redis-cli -h localhost -p 6379 -a foobared
localhost:6379> keys *
1) "foo"
localhost:6379> get foo
"bar"
localhost:6379> exit
[root@ansible ansible_playbooks]#
可以看到能正常查询到键foo
的值是bar
。
此时再执行剧本:
[root@ansible ~]# cd ansible_playbooks/
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.123]
ok: [192.168.56.121]
ok: [192.168.56.122]
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
...过程输出省略
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=26 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m24.150s
user 0m10.202s
sys 0m3.894s
[root@ansible ansible_playbooks]#
此时登陆redis命令行查看缓存信息:
[root@ansible ansible_playbooks]# /usr/bin/redis-cli -h localhost -p 6379 -a foobared
localhost:6379> keys *
1) "foo"
2) "ansible_facts192.168.56.121"
3) "ansible_facts192.168.56.123"
4) "ansible_facts192.168.56.122"
5) "ansible_cache_keys"
localhost:6379>
再次执行剧本:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [basehosts] *****************************************************************************************************************************************************************************************************************************************************************************
TASK [base : Show hostname] ******************************************************************************************************************************************************************************************************************************************************************
ok: [192.168.56.121] => {
"msg": "ansible-node1"
}
ok: [192.168.56.122] => {
"msg": "ansible-node2"
}
ok: [192.168.56.123] => {
"msg": "ansible-node3"
}
...过程输出省略
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************************************************************
192.168.56.121 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.122 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
192.168.56.123 : ok=25 changed=6 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
real 0m14.807s
user 0m9.492s
sys 0m3.406s
[root@ansible ansible_playbooks]#
可以看到,此时使用了缓存!没有执行TASK [Gathering Facts]
任务。此时执行任务快了1秒钟。
2.4.3 使用memcached进行缓存
使用memcached配置缓存,与redis类似。
安装memcached服务并启动:
[root@ansible ~]# yum install memcached -y
[root@ansible ~]# systemctl start memcached
[root@ansible ~]# ps -ef|grep memcached
memcach+ 16596 1 0 22:19 ? 00:00:00 /usr/bin/memcached -u memcached -p 11211 -m 64 -c 1024
root 16603 1525 0 22:19 pts/0 00:00:00 grep --color=auto memcached
[root@ansible ~]#
连接memcached:
[root@ansible ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set foo 0 0 3
bar
STORED
get foo
VALUE foo 0 3
bar
END
quit
Connection closed by foreign host.
[root@ansible ~]#
可以看到memcached服务可以使用。
再安装python-memcached包:
[root@ansible ~]# pip install python-memcached
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Looking in indexes: http://mirrors.aliyun.com/pypi/simple/
Collecting python-memcached
Downloading http://mirrors.aliyun.com/pypi/packages/8f/1b/3b15a37831ae34a264d7d5b71f3ae9fe74a81251453a3ec2135e76888ef1/python_memcached-1.62-py2.py3-none-any.whl (15 kB)
Installing collected packages: python-memcached
Successfully installed python-memcached-1.62
[root@ansible ~]# pip list|grep memcached
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
python-memcached 1.62
[root@ansible ~]#
修改/etc/ansible/ansible.cfg
配置文件中以下几个参数:
gathering = smart
fact_caching = memcached
fact_caching_timeout = 300
fact_caching_connection = 127.0.0.1:11211
由于python 2.7的一些语法限制,执行剧本时会报错:
[root@ansible ansible_playbooks]# time ansible-playbook -i base_hosts.ini base.yml -vvv
ansible-playbook 2.9.27
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 2.7.5 (default, Oct 14 2020, 14:45:30) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
Using /etc/ansible/ansible.cfg as config file
host_list declined parsing /root/ansible_playbooks/base_hosts.ini as it did not pass its verify_file() method
script declined parsing /root/ansible_playbooks/base_hosts.ini as it did not pass its verify_file() method
auto declined parsing /root/ansible_playbooks/base_hosts.ini as it did not pass its verify_file() method
yaml declined parsing /root/ansible_playbooks/base_hosts.ini as it did not pass its verify_file() method
Parsed /root/ansible_playbooks/base_hosts.ini inventory source with ini plugin
ERROR! Unexpected Exception, this is probably a bug: invalid syntax (memcache.py, line 374)
the full traceback was:
Traceback (most recent call last):
File "/usr/bin/ansible-playbook", line 123, in <module>
exit_code = cli.run()
File "/usr/lib/python2.7/site-packages/ansible/cli/playbook.py", line 109, in run
loader, inventory, variable_manager = self._play_prereqs()
File "/usr/lib/python2.7/site-packages/ansible/cli/__init__.py", line 473, in _play_prereqs
variable_manager = VariableManager(loader=loader, inventory=inventory, version_info=CLI.version_info(gitinfo=False))
File "/usr/lib/python2.7/site-packages/ansible/vars/manager.py", line 102, in __init__
self._fact_cache = FactCache()
File "/usr/lib/python2.7/site-packages/ansible/vars/fact_cache.py", line 24, in __init__
self._plugin = cache_loader.get(C.CACHE_PLUGIN)
File "/usr/lib/python2.7/site-packages/ansible/plugins/loader.py", line 552, in get
self._module_cache[path] = self._load_module_source(name, path)
File "/usr/lib/python2.7/site-packages/ansible/plugins/loader.py", line 530, in _load_module_source
module = imp.load_source(to_native(full_name), to_native(path), module_file)
File "/usr/lib/python2.7/site-packages/ansible/plugins/cache/memcached.py", line 59, in <module>
import memcache
File "/usr/lib/python2.7/site-packages/memcache.py", line 374
def quit_all(self) -> None:
^
SyntaxError: invalid syntax
real 0m0.344s
user 0m0.298s
sys 0m0.046s
[root@ansible ansible_playbooks]#
在Python 2.7中,quit_all
函数的定义可能出现了一些问题。Python 2.7不支持类型注释,即-> None
部分。这是导致错误的直接原因。
建议升级Python版本和Ansible版本后再进行测试。