Ansible 你快点:Ansible 执行过程分析、异步、效率优化
链接:https://www.cnblogs.com/f-ck-need-u/p/17718504.html
Ansible你快点:Ansible执行过程分析、异步、效率优化
11.1 测量任务执行速度:profile_tasks插件
(1). profile_tasks
:该回调插件用于计时每个任务的执行时长(2). profile_roles
插件用于计时每个Role的执行时长(3). timer
插件用于计时每个play执行时长
callback_whitelist
中加入各插件。如下:1
2
3[defaults]
callback_whitelist = profile_tasks
# callback_whitelist = profile_tasks, profile_roles, timer
profile_tasks
插件。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19---
- name: test for timer
hosts: timer
gather_facts: no
tasks:
- name: only one debug
debug:
var: inventory_hostname
- name: shell
shell:
cp /etc/fstab /tmp/
loop: "{{ range(0, 100)|list }}"
- name: scp
copy:
src: /etc/hosts
dest: /tmp/
loop: "{{ range(0, 100)|list }}"
profile_tasks
后在屏幕中输出的计时信息:1
2
3
4
5
6
7
8$ ansible-playbook -i timer.host timer.yml
...................
......省略输出......
...................
=========================================
scp ------------------------------------ 57.96s
shell ---------------------------------- 42.78s
only one debug ------------------------- 0.07s
11.2 Ansible执行流程分析
-vvv
选项,会输出很多调试信息,包括建立的连接、发送的文件等等。-vvv
去执行一个任务并观察输出信息,同时可与我所做的注释做比较。需注意:不同版本的Ansible为每个任务建立的连接数量不同,Ansible 2.9为每个任务建立7次ssh连接。有的资料或书籍中介绍时说只建立二次、三次、四次ssh连接都是有可能的,版本不同确实是有区别的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37# 1.第一个连接:获取用户家目录,此处为/root
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ....... '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
<node1> (0, '/root\n', ......)
# 2.第二个连接:在家目录下创建临时目录,临时目录由配置文件中remote_tmp指令控制
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ...... '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1575542743.85-116022411851390 `" && ...... `" ) && sleep 0'"'"''
# 3.第三个连接:探测目标节点的平台和python解释器的版本信息
<node1> Attempting python interpreter discovery
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ......
# 4.第四个连接:将要执行的模块相关的代码和参数放到本地临时文件中,并使用sftp将任务文件传输到被控节点的临时文件中
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ......
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/ping.py
......
<node1> SSH: EXEC sftp ......
<node1> (0, 'sftp> put /root/.ansible/tmp/ansible-local-78628na2FKL/tmpaE1RbJ /root/.ansible/tmp/ansible-tmp-1575542743.85-116022411851390/AnsiballZ_ping.py\n', ......
# 5.第五个连接:对目标节点上的任务文件授以执行权限
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ...... '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1575542743.85-116022411851390/ /root/.ansible/tmp/ansible-tmp-1575542743.85-116022411851390/AnsiballZ_ping.py && sleep 0'"'"''
......
# 6.第六个连接:执行目标节点上的任务
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ...... '/bin/sh -c '"'"'/usr/bin/python /root/.ansible/tmp/ansible-tmp-1575542743.85-116022411851390/AnsiballZ_ping.py && sleep 0'"'"''
<node1> (0, '\r\n{"invocation": {"module_args": {"data": "pong"}}, "ping": "pong"}\r\n',
......
# 7.第七个连接:删除目标节点上的临时目录
<node1> ESTABLISH SSH CONNECTION FOR USER: None
<node1> SSH: EXEC ssh -vvv ...... '/bin/sh -c '"'"'rm -f -r /root/.ansible/tmp/ansible-tmp-1575542743.85-116022411851390/ > /dev/null 2>&1 && sleep 0'"'"''
......
(1).第一个连接:获取远程主机时行目标用户的家目录,此处为/root (2).第二个连接:在远程家目录下创建临时目录,临时目录可由ansible.cfg中 remote_tmp
指令控制(3).第三个连接:探测目标节点的平台和python解释器的版本信息 (4).第四个连接:将待执行模块的相关代码和参数放到本地临时文件中,并使用sftp将任务文件传输到被控节点的临时文件中 (5).第五个连接:对目标节点上的任务文件授以执行权限 (6).第六个连接:执行目标节点上的任务 (7).第七个连接:删除目标节点上的临时目录,并将执行结果返回给Ansible端
(1).进入第一个play,挑选forks=5设置的5个节点 (2).每个节点执行第一个任务,每个节点都会建立7次ssh连接 (3).每个节点执行第二个任务,每个节点都再次建立7次ssh连接 (4).按照相同逻辑执行该play中其它任务... (5).所有节点执行完该play中的所有任务后,进入下一个play (6).按照上面的流程执行完所有play中的所有任务
11.3 回顾Ansible的执行策略
serail
是play级别的指令,用于指定几个节点作为一批去执行该play,该play执行完后才让下一批节点执行该play中的任务。如果不指定serial,则默认的行为等价于将所有节点当作一批。strategy
指令用于指定节点执行任务时的策略,其侧重点在于节点而在于任务,默认情况下其策略为linear
,表示某个节点先执行完一个任务后等待其余所有节点都执行完该任务,才统一进入下一个任务。另一种策略是free
策略,表示某节点执行完一个任务后不等待其它节点,而是毫不停留的继续执行该play中的剩余任务,直到该play执行完成,才释放节点槽位让其它未执行任务的节点开始执行任务。11.4 加大forks的值
11.5 修改执行策略
strategy=free
便能让这些执行任务的节点彻底放飞自我。只是剩余的一部分节点可能会比较悲剧,它们处于调度不公平的一方。但是从整体来说,先让大部分节点快速完成任务是值得的。11.6 使Ansible异步执行任务
11.6.1 async和poll指令
1
2
3
4
5
6
7
8
9
10- name: it is an async task
copy:
src:
dest:
async: 200
poll: 2
- name: a sync task
copy:
src:
dest:
async
指令表示该任务将以异步的模式执行。async指令的值200表示,如果该后台任务200秒还未完成,则认为该任务失败。poll
指令表示该任务丢入后台后,Ansible每隔多久去检查一次异步任务是否已成功、是否报错等,只有检查到已完成后才认为该异步任务执行完成,才会进入下一个任务。-B N
选项指定async功能,N为超时时长,-P N
选项指定poll功能,N为检查后台任务状况的时间间隔。$ ansible inventory_file -B200 -P 0 -m yum -a 'name=dos2unix' -o -f 20
11.6.2 等待异步任务
T1(async) --> T2(sync) --> T3(sync) --> T4(wait T1) --> T5
async_status
模块,该模块接受一个后台任务的job id作为参数,然后获取该后台任务的状态并返回。(1).ansible_job_id:异步任务的job id (2).finished:表示所等待的异步任务是否已执行完成,值为1表示完成,0表示未完成 (3).started:表示所等待的异步任务是否已开始执行,值为1表示已开始,0表示未开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14- name: Asynchronous yum task
yum:
name: nginx
state: present
async: 1000
poll: 0
register: yum_sleeper
- name: Wait for asynchronous job to end
async_status:
jid: '{{ yum_sleeper.ansible_job_id }}'
register: job_result
until: job_result.finished
retries: 30
yum_sleeper
,该变量中包含一个ansible_job_id
的属性。将该属性交给async_status
模块的jid选项,该模块便可以获取该异步任务的状态,并将状态注册到变量job_result
中,结合until
指令不断等待job_result.finished
事件发生,即表示异步任务执行完成。async_status
模块使用loop循环来完成该功能。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29---
- name: test for timer
hosts: timer
gather_facts: no
tasks:
- name: async task 1
shell: sleep 5
async: 200
poll: 0
register: async_task1
- name: async task 2
shell: sleep 10
async: 200
poll: 0
register: async_task2
- name: waiting for all async task
async_status:
jid: "{{item}}"
register: job_result
until: job_result.finished
loop:
- "{{ async_task1.ansible_job_id }}"
- "{{ async_task2.ansible_job_id }}"
- name: after waiting
debug:
msg: "after waiting"
11.6.3 何时使用异步任务
11.7 开启ssh长连接
ssh -V
可以查看版本号。然后设置ansible使用ssh连接被控端的连接参数,此处修改/etc/ansible/ansible.cfg,在此文件中启动下面的连接选项,其中ControlPersist=5d
是控制ssh连接会话保持时长为5天。ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
/etc/ssh/ssh_config
(不是sshd_config,因为ssh命令是客户端命令)中对应的长连接选项也是可以的。ansible centos -m ping
1
2
3
4
5
6
7
8
9
10
11
12
13
14$ netstat -tnalp
Local Address Foreign Address State PID/Program name
0.0.0.0:22 0.0.0.0:* LISTEN 1143/sshd
127.0.0.1:25 0.0.0.0:* LISTEN 2265/master
192.168.200.26:58474 192.168.200.59:22 ESTABLISHED 31947/ssh: /root/.a
192.168.200.26:22 192.168.200.1:8189 ESTABLISHED 29869/sshd: root@pt
192.168.200.26:37718 192.168.200.64:22 ESTABLISHED 31961/ssh: /root/.a
192.168.200.26:38894 192.168.200.60:22 ESTABLISHED 31952/ssh: /root/.a
192.168.200.26:48659 192.168.200.61:22 ESTABLISHED 31949/ssh: /root/.a
192.168.200.26:33546 192.168.200.65:22 ESTABLISHED 31992/ssh: /root/.a
192.168.200.26:54824 192.168.200.63:22 ESTABLISHED 31958/ssh: /root/.a
:::22 :::* LISTEN 1143/sshd
::1:25 :::* LISTEN 2265/master
.ansible/cp
目录下生成一些socket文件,每个ssh连接会话一个文件。1
2
3
4
5
6
7
8$ ls -l ~/.ansible/cp/
total 0
srw------- 1 root root 0 Jun 3 18:26 5c4a6dce87
srw------- 1 root root 0 Jun 3 18:26 bca3850113
srw------- 1 root root 0 Jun 3 18:26 c89359d711
srw------- 1 root root 0 Jun 3 18:26 cd829456ec
srw------- 1 root root 0 Jun 3 18:26 edb7051c84
srw------- 1 root root 0 Jun 3 18:26 fe17ac7eed
control_path_dir
指令决定。11.7.1 开启ssh长连接后的注意事项
root@B
节点后,A会缓存到B节点的ssh连接,如果此时B节点目标用户root修改了密码,A节点借助缓存下来的ssh长连接仍然能够连接到root@B
节点。11.8 开启Pipelining
1
2$ echo 'hostname -I' | ssh [email protected] 'bash'
192.168.200.48
hostname -I
并将其写入到远程主机上的标准输入供bash命令读取,于是bash命令执行读取到的数据。所以,相当于是在远程主机上执行了echo "hostname -I" | bash
。$ echo 'print("hello world")' | ssh [email protected] 'python'
$ echo 'print("hello world")' | python
pipelining=true
,默认是false,即默认Pipelining是禁用状态。1
2$ grep '^pipelining' /etc/ansible/ansible.cfg
pipelining = True
11.8.1 开启Pipelining后的注意事项
1
2
3
4
5
6
7
8
9---
- name: test for timer
hosts: timer
gather_facts: no
become: yes
become_user: root
become_method: sudo
tasks:
- shell: sleep 1
requiretty
将报错:1
2Pseudo-terminal will not be allocated because stdin is not
a terminal.\r\nsudo: sorry, you must have a tty to run sudo
1
2$ grep requiretty /etc/sudoers
Defaults requiretty # 注释此行表示禁用
1
2
3
4
5$ grep 'ssh_args' /etc/ansible/ansible.cfg
ssh_args = -C -o ControlMaster=auto -o ControlPersist=1d -tt
# 或者在命令行中指定
$ ansible-playbook --ssh-extra-args="-tt"" xxxxxx
11.8.2 开启Pipelining后的执行流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36TASK [test task] *******************************************
task path: /root/ansible/timer.yml:6
# 第一个SSH连接,用于探测目标节点上支持的Python版本
<192.168.200.48> Attempting python interpreter discovery
<192.168.200.48> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.200.48> SSH: EXEC ssh -C -o ......
<192.168.200.48> (0, b'
PLATFORM\nLinux\nFOUND\n
/usr/bin/python\n
/usr/bin/python3.6\n
/usr/bin/python2.7\n
/usr/bin/python3\n
/usr/bin/python\n
ENDFOUND\n', b'')
# 第二个SSH连接用于探测目标节点操作系统的信息
<192.168.200.48> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.200.48> SSH: EXEC ssh -C -o ......
<192.168.200.48> (0, b'{"osrelease_content":
"NAME=\\"CentOS Linux\\"\\n
VERSION=\\"7 (Core)\\"\\n
ID=\\"centos\\"\\n
ID_LIKE=\\"rhel fedora\\"\\n
VERSION_ID=\\"7\\"\\n
......b'')
# 准备执行任务,加载任务使用的模板文件,且发现开启了Pipelining
Using module file ......ansible/modules/commands/command.py
Pipelining is enabled.
# 第三个SSH连接用于执行任务
<192.168.200.48> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.200.48> SSH: EXEC ssh -C ......
'/bin/sh -c '"'"'/usr/bin/python && sleep 0'"'"''
<192.168.200.48> (目标节点执行任务返回的结果)
11.8.3 开启和不开启Pipelining的效率比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 开启Pipelining之前
$ ansible-playbook -i timer.host timer.yml
...................
......省略输出......
...................
=========================================
scp ------------------------------------ 57.96s
shell ---------------------------------- 42.78s
only one debug ------------------------- 0.07s
# 开启Pipelining后
$ ansible-playbook -i timer.host timer.yml
...................
......省略输出......
...................
=========================================
scp ------------------------------------ 39.99s
shell ---------------------------------- 20.29s
only one debug ------------------------- 0.07s
11.9 修改facts收集行为
gather_facts: no
关闭收集功能。gather_subset=!all,!any,network
,这样可以减少收集的数据量,从而提升效率。11.10 Shell层次上的优化:将任务分开执行
1
2
3$ ansible-playbook nginx.yml >/tmp/nginx.log &
$ ansible-playbook mysql.yml >/tmp/mysql.log # 被依赖,所以不后台
$ ansible-playbook php.yml >/tmp/php.log
11.11 第三方策略插件:Mitogen for Ansible
(1).linear (2).free (3).host-pinned (4).debug
1
2
3$ wget 'https://networkgenomics.com/try/mitogen-0.2.9.tar.gz'
$ mkdir -p ~/.ansible/plugins
$ tar xf mitogen-0.2.9.tar.gz -C ~/.ansible/plugins/
1
2
3[defaults]
strategy_plugins = ~/.ansible/plugins/mitogen-0.2.9/ansible_mitogen/plugins/strategy
strategy = mitogen_linear
1
2
3
4
5
6$ ls -1 ~/.ansible/plugins/mitogen-0.2.9/ansible_mitogen/plugins/strategy/
__init__.py
mitogen_free.py
mitogen_host_pinned.py
mitogen_linear.py
mitogen.py
(1). mitogen_linear
对应于Ansible自身的linear策略(2). mitogen_free
对应于Ansible自身的free策略(3). mitogen_host_pinned
对应于Ansible自身的host_pinned策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 开启Pipelining但未使用mitogen插件
$ ansible-playbook -i timer.host timer.yml
...................
......省略输出......
...................
=========================================
scp ------------------------------------ 39.99s
shell ---------------------------------- 20.29s
only one debug ------------------------- 0.07s
# 开启Pipelining且使用mitogen插件
$ ansible-playbook -i timer.host timer.yml
...................
......省略输出......
...................
=========================================
shell -------------------------------- 8.02s
scp ---------------------------------- 3.37s
only one debug ----------------------- 0.33s
(1).原生Ansible允许使用forks设置最大并发节点数量,但mitogen默认固定最多32个连接,需要修改环境变量 MITOGEN_POOL_SIZE
的值来设置最大并发量。(2).mitogen的sudo处理行为和Ansible不一样,所以可能需要单独在目标节点的sudoer配置中加入对应用户的配置。比如 your_ssh_username = (ALL) NOPASSWD:/usr/bin/python -c*
。
END
官方站点:www.linuxprobe.com
Linux命令大全:www.linuxcool.com
刘遄老师QQ:5604215
Linux技术交流群:2636170
(新群,火热加群中……)
想要学习Linux系统的读者可以点击"阅读原文"按钮来了解书籍《Linux就该这么学》,同时也非常适合专业的运维人员阅读,成为辅助您工作的高价值工具书!
微信扫码关注该文公众号作者
戳这里提交新闻线索和高质量文章给我们。
来源: qq
点击查看作者最近其他文章