Ansible最佳实践之Playbook管理滚动更新

傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波

写在前面


  • 理解不足小伙伴帮忙指正

傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波

Ansible的滚动更新

关于什么是滚动更新

通常,当Ansible运行play时,它会确保所有受管主机在启动任何主机进行下一个任务之前已完成每个任务。在所有受管主机完成所有任务后,运行通知的 handles 程序。

在所有主机上运行所有任务可能会导致意外行为。例如,在更新 Web 负载均衡器,如果同时更新所有Web服务器、可能会导致所有Web服务器停眼务。

Ansible支持滚动更新-一将一大批主机分批次更新,这样的好处:

  • 同一时刻只有部分服务器在更新,其他服务器仍然可以对外提供服务。
  • 如果这一批次服务器更新失败,其他服务器仍然可以对外提供服务。

所以一般建议在更新的剧本中配置:

  • 监视更新过程,测试更新结果。
  • 如果更新失败,隔离受影响的主机,以分析失败的部署,或者回滚受影响批次中主机配置。
  • 将部署结果发送给相关人员。

控制批处理大小

默认情况下,Ansible会在开始执行下一个任务之前,需要对Play中所有主机完成前一个任务。如果某一任务失败,则所有主机将只有一部分通过该任务。意味着任何主机都无法正常工作,可能会导致中断。理想情况下,在启动下一批主机之前,需要全部成功通过Play,如果有太多主机失败,则可以中止整个Play。

设置固定的批处理大小

在Play 中使用 serial 关键字来指定每个批处理中应当有多少个主机。

在开始下一批主机之前,Ansible 将全程通过Play处理每一批主机,如果当前批处理中的所有主机都失败,则整个Play 将中止,且 Ansible 不会启动下一批次处理。

1
2
3
4
5
6
7
8
[student@workstation task-execution]$ cat serial.yaml
---
- name: 滚动更新
hosts: all
serial: 2
tasks:
- name: update web
shell: sleep 2
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
38
39
[student@workstation task-execution]$ ansible-playbook  serial.yaml

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [servera]
ok: [serverb]

TASK [update web] ********************************************************************************************
changed: [servera]
changed: [serverb]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [serverd]
ok: [serverc]

TASK [update web] ********************************************************************************************
changed: [serverc]
changed: [serverd]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [servere]
ok: [serverf]

TASK [update web] ********************************************************************************************
changed: [servere]
changed: [serverf]

PLAY RECAP ***************************************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverb : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverc : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverd : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
servere : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverf : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

在上面示例中,serial 关键字指定Ansible在两个主机的批处理中处理 web_servers 主机组中的主机。如果play正常执行且没有错误,则使用新的批处理再次重复该 play。

如果play中的主机总数不能被批处理大小整除,则最后一个批处理包含的主机可能比serial 关键字的指定值更少。serial关键字中使用整数。

将批处理大小设置为百分比

还可以为 serial 关键字设置为百分比:

1
2
3
4
5
6
7
8
[student@workstation task-execution]$ cat serial.yaml
---
- name: 滚动更新
hosts: all
serial: 25%
tasks:
- name: update web
shell: sleep 2
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
[student@workstation task-execution]$ ansible-playbook  serial.yaml

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [servera]

TASK [update web] ********************************************************************************************
changed: [servera]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [serverb]

TASK [update web] ********************************************************************************************
changed: [serverb]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [serverc]

TASK [update web] ********************************************************************************************
changed: [serverc]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [serverd]

TASK [update web] ********************************************************************************************
changed: [serverd]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [servere]

TASK [update web] ********************************************************************************************
changed: [servere]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [serverf]

TASK [update web] ********************************************************************************************
changed: [serverf]

PLAY RECAP ***************************************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverb : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverc : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverd : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
servere : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverf : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

[student@workstation task-execution]$

每个批次分别设置

1
2
3
4
5
6
7
8
9
10
11
12
[student@workstation task-execution]$ cat serial.yaml
---
- name: 滚动更新
hosts: all
serial:
- 25%
- 3
- 100%
tasks:
- name: update web
shell: sleep 2
[student@workstation task-execution]$
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
38
39
40
[student@workstation task-execution]$ vim  serial.yaml
[student@workstation task-execution]$ ansible-playbook serial.yaml

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [servera]

TASK [update web] ********************************************************************************************
changed: [servera]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [serverc]
ok: [serverb]
ok: [serverd]

TASK [update web] ********************************************************************************************
changed: [serverb]
changed: [serverc]
changed: [serverd]

PLAY [滚动更新] **************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************
ok: [servere]
ok: [serverf]

TASK [update web] ********************************************************************************************
changed: [servere]
changed: [serverf]

PLAY RECAP ***************************************************************************************************
servera : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverb : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverc : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverd : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
servere : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
serverf : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

中止Play

默认情况下,Ansible尝试获取尽可能多的主机来完成play。如果某一任务对于某一主机失败,则它将从play中丢弃,但Ansible 将继续为其他主机运行play中剩余的任务。仅当所有主机都失败时,play才会停止。

但是,如果使用 serial 关键字将主机组织到批处理中,那么如果当前批处理中的所有主机都失败,则Ansible将停止所有剩余主机的 play,而不仅仅是当前批处理中剩余的主机。如果由于批处理中的所有主机失败而停止了该play的执行,则下一个批处理将不会启动。

Ansible的ansible_play_batch变量中的每个批处理保留活动服务器列表。任何有任务失败的主机都将从ansible play batch 列表中删除。Ansible会在每项任务后更新此列表。

指定容错 max_fail_percentage

这里可以通过 指定容错 的方式来提前终止剧本。通过将 max_fail_percentage 关键字添加到剧本 ,改变 Ansible 的失败行为

1
2
3
4
5
6
7
8
9
10
11
- name: 滚动更新
hosts: all
max_fail_percentage: 30%
serial:
- 25%
- 3
- 100%
tasks:
- name: update web
shell: sleep 2

上面的配置,即所有机器里 30% 的机器执行 tasks 任务失败,那个会提前终止 剧本。

博文参考

《Red Hat Ansible Engine 2.8 DO447》

发布于

2022-08-12

更新于

2023-06-21

许可协议

评论
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×