🎹 个人简介:大家好,我是 金鱼哥,CSDN运维领域新星创作者,华为云·云享专家,阿里云社区·专家博主
📚个人资质: CCNA、HCNP、CSNA(网络分析师),软考初级、中级网络工程师、RHCSA、RHCE、RHCA、RHCI、ITIL😜
💬格言:努力不一定成功,但要想成功就必须努力🔥
📜5.2.1 概述
Ansible有几个特性可以支持滚动更新,这是一种将部署堆叠到一批服务器上的策略。使用此策略,部署基础设施更新时没有停机时间。
当出现不可预见的问题时,Ansible可以停止部署,任何错误都可以限制在特定批处理中的那些服务器上。有了测试和监视,您可以将剧本任务配置为:
- 回滚受影响的批量主机的配置。
- 隔离受影响的主机以分析失败的部署。
- 向涉众发送部署通知。
📜5.2.2 控制批量大小
默认情况下,Ansible会在开始执行下一个任务之前,为该剧本中的所有主机运行一个任务。如果一个任务失败,那么所有的主机将只是在任务的一半。这可能意味着您的所有主机都不能正常工作,这可能会导致停机。
理想情况下,在开始下一批主机之前,可以在整个过程中处理一些主机。如果太多主机失败,那么您可以中止整个剧本。在下面的段落中,您将配置您的剧本来做到这一点。
📑设置固定批量大小
如果要通过剧本批量处理主机,请在剧本中使用serial关键字。serial关键字指定每个批处理中应该有多少台主机。在开始下一批之前,Ansible会一直处理每一批主机。如果当前批处理的所有主机都失败。整个剧本被中止,Ansible不启动下一批。
---
- name: Update Webservers
hosts: web_servers
serial: 2
在本例中,serial关键字指示Ansible分批处理web_servers主机组中的两台主机。如果剧本没有错误地执行,则剧本将以新一批重复执行。
这一过程将继续进行,直到处理完剧本中的所有主机。因此,如果剧本中的主机总数不能除以批量大小,最后一批主机可能比serial关键字指示的值更少。在前面的示例中,如果web服务器的总数为奇数,则最后一批包含一台主机。
记住,如果使用serial关键字的整数,那么随着主机数量的增加,完成剧本所需的批数也会增加。当串行值为2时,200台主机的主机组需要100批完成,20台主机的主机组需要10批完成。
📑设置批量大小为百分比
可以为serial关键字的值指定一个百分比:
---
- name: Update Webservers
hosts: web_servers
serial: 25%
如果您指定了一个百分比,那么该百分比的主机将在每批处理中被处理。如果serial的值为25%,则无论web_servers组中包含20台主机还是200台主机,都需要4批完成所有主机的play。
Ansible将该百分比应用于主机组中主机的总数量。如果结果值不是主机的整数数量,那么该值将被截断(四舍五入)到最接近的整数。其余的主机以较小的批处理运行。批处理大小不能为零主机。如果截断的值为零,Ansible将批处理大小更改为一个主机。
📑将批量大小设置为可更改
您可以在剧本执行时更改批处理大小。例如,您可以在一台主机上批量测试一个剧本,如果该主机失败,那么整个剧本将中止。但是,如果在一个主机上成功运行,您可以将批处理规模增加到10%的主机,然后是50%的管理主机,然后是其余的管理主机。
---
- name: Update Webservers
hosts: web_servers
serial:
- 1
- 10%
- 100%
第一批只包含一个主机。
第二批包含web_servers主机组中主机总数的10%。Ansible根据前面讨论的规则计算实际值。
第三批包含所有剩余未处理的主机。这使得Ansible能够有效地处理所有剩余的主机。
如果在serial关键字最后一个条目对应的最后一批后还有未处理的主机,则重复最后一批大小,直到所有主机都处理完毕。考虑下面的操作,它对一个有100台主机的web_servers主机组执行:
---
- name: Update Webservers
hosts: web_servers
serial:
- 1
- 10%
- 25%
第一批包含1台主机,第二批包含10台主机(占100台主机的10%)。第三批处理25个主机(占100的25%),剩下64个未处理主机(1 + 10 + 25处理)。Ansible以25台主机(占100台主机的25%)的批量规模继续执行play,直到剩余不到25台未处理主机为止。以剩余的14台主机为例最终批次(1 + 10 + 25 + 25 + 25 + 14 = 100)。
📜5.2.3 中止剧本
既然您已经知道了如何逐步增加批处理大小,那么您必须了解在太多主机失败时如何中止运行。
默认情况下,Ansible会尝试让尽可能多的主机来完成剧本。如果某个主机的任务失败,则该任务将被从剧本中删除,但Ansible将继续为其他主机运行剧本中剩余的任务。只有当所有主机都失败时,剧本执行才会停止。
但是,如果使用serial关键字将主机组织成批量,那么如果当前批处理中的所有主机都失败,Ansible将停止所有剩余主机的执行,而不仅仅是当前批处理中的剩余主机。如果某批处理中所有主机都失败,导致该play停止执行,则不会启动下批处理。
Ansible在ansible_play_batch变量中保存了每个批处理的活动服务器列表。任何任务失败的主机都会从ansible_play_batch列表中删除。Ansible在每个任务之后更新这个列表。
考虑以下假设的脚本,它针对一个拥有100台主机的web_servers主机组执行:
如果99个web服务器在第一个任务中失败,但有一个主机成功,Ansible继续执行第二个任务。当Ansible执行第二个任务时,Ansible只为之前成功的一个主机执行任务。
如果您使用serial关键字,那么只有在当前批处理中没有出现故障的情况下,playbook执行才会继续。考虑一下对假设剧本的修改:
如果第一批包含一个成功的主机和一个失败的主机,那么批处理完成,Ansible继续处理第二个批处理。如果第二批处理中的两台主机都在某个任务上失败,那么Ansible将终止整个任务,不再开始任何批处理。
在这个场景中,在剧本执行之后:
- 一台主机成功地完成了剧本。
- 可能有三个主机处于错误状态。
- 其余的主机保持不变。
📑指定失败比例
默认情况下,Ansible只有在所有主机都失败时才会停止执行。但是,如果清单中超过一定比例的主机失败,即使没有整个批处理失败,您也可能希望终止操作。也有可能“快速失败”,并在任何任务失败时中止剧本。
通过添加max_fail_percentage关键字来改变Ansible的失败行为。当批处理中失败的主机数量超过这个百分比时,Ansible会停止playbook的执行。
考虑以下假设的脚本,它针对包含100台主机的web_servers主机组执行:
第一批包含两台主机。因为2的30%是0.6,单个主机故障会导致执行停止。
如果第一批主机都成功,则Ansible继续处理第二批10台主机。因为10的30%是3。超过3个主机故障必然导致Ansible停止playbook的执行。如果有三个或更少的主机在第二批中出现错误,Ansible将继续进行第三批。
要实现“快速失败”策略,将max_fail_percentage设置为零。
📑重要:
总结Ansible的失败行为:
- 如果不设置“serial”关键字和“max_fail_percentage”,则批量运行所有主机。如果所有主机都失败,则执行失败。
- 如果设置了“serial”关键字,则多批次运行主机,如果所有主机都失败,则执行失败。
- 如果设置了max_fail_percentage关键字,则如果超过该百分比的主机在批处理中失败,则执行失败。
如果play失败了,所有剩余的play都将被取消。
📜5.2.4 运行一个任务一次
某些时候,我们希望某个task只执行一次,即使它被绑定到了多个主机上。例如在一个负载均衡器后面有多台应用服务器,我们希望执行一个数据库迁移,只需要在一个应用服务器上执行操作即可。
为此,向任务添加run_once关键字,其值为布尔值true(或yes)。
- name: Reactivate Hosts
shell: /sbin/activate.sh {{ active_hosts_string }}
run_once: yes
delegate_to: monitor.example.com
vars:
active_hosts_string: "{{ ansible_play_batch | join(' ')}}"
此任务运行一次,并在monitor.example.com执行。该任务使用active_hosts_ string变量将活动主机列表作为命令行参数传递给激活脚本。该变量仅包含当前批处理中已成功完成前面所有任务的主机。
注意:设置run_once: yes关键字将导致每批执行一次任务。如果某个剧本中所有主机只需要执行一次任务,且该剧本有多个批量执行,则可以在该任务中添加以下条件:
when: inventory_hostname == ansible_play_hosts[0]
这个条件只对剧本中的第一个主机运行任务。
📜5.2.5 课本练习
[student@workstation ~]$ lab update-management start
📑拉取实验代码
[student@workstation ~]$ cd git-repos/
[student@workstation git-repos]$ git clone http://git.lab.example.com:8081/git/update-management.git
[student@workstation git-repos]$ cd update-management
📑执行剧本。
# 部署一个前端负载均衡器和一组后端web服务器。
[student@workstation update-management]$ ansible-playbook site.yml
[student@workstation update-management]$ curl servera
This is serverb. (version v1.0)
[student@workstation update-management]$ curl servera
This is serverc. (version v1.0)
[student@workstation update-management]$ curl servera
This is serverd. (version v1.0)
[student@workstation update-management]$ curl servera
This is servere. (version v1.0)
[student@workstation update-management]$ curl servera
This is serverf. (version v1.0)
📑查看测试脚本并执行
[student@workstation update-management]$ cat issue_requests.sh
#!/bin/bash
SERVER=servera.lab.example.com
WAIT_TIME_SECS=0.5
LOG_FILE=curl_output.log
rm -f $LOG_FILE
while true; do
#Print curl response to stdout and also write to log file.
curl -s $SERVER | tee -a $LOG_FILE
sleep $WAIT_TIME_SECS
done
[student@workstation update-management]$ chmod +x issue_requests.sh
[student@workstation update-management]$ ./issue_requests.sh
This is serverb. (version v1.0)
This is serverc. (version v1.0)
This is serverd. (version v1.0)
This is servere. (version v1.0)
This is serverf. (version v1.0)
This is serverb. (version v1.0)
This is serverc. (version v1.0)
This is serverd. (version v1.0)
This is servere. (version v1.0)
This is serverf. (version v1.0)
^C
📑查看可滚动更新的剧本
[student@workstation update-management]$ cat update_webapp.yml
---
- hosts: web_servers
serial:
- 1
- 25%
- 100%
# 关键字serial表示该play中的任务分三批处理。
# 第一批为1台主机。在此批处理完成后,仍有4台主机需要处理。
# 第二批包含1台主机,因为25%的主机组大小是1.25,所以被截断为1。
# 第三批处理中有3台主机,因为100%的主机组大小为5,只有3台主机未处理。
pre_tasks:
- name: Remove web server from service during the update
haproxy:
state: disabled
backend: app
host: "{{ inventory_hostname }}"
delegate_to: "{{ item }}"
with_items: "{{ groups['lb_servers'] }}"
# 在playbook更新每个服务器上的web应用程序之前,haproxy模块会禁用所有负载均衡器中的服务器。通过这项任务,外部客户端不会暴露在应用程序部署后发现的错误中。
roles:
- role: webapp
# webapp角色部署驻留在Git存储库中的web应用程序。webapp_repo变量指定了web应用程序Git存储库的URL。webapp_version变量指定应用程序存储库中的分支或版本tag。这些变量在group_vars/web_servers/webapp.yml文件定义。
# cat group_vars/web_servers/webapp.yml
# webapp_repo: http://git.lab.example.com:8081/git/simple-webapp.git
# webapp_version: v1.0
post_tasks:
# Firewall rules dictate that requests to backend web
# servers must originate from a load balancer.
- name: Smoke Test - Ensure HTTP 200 OK
uri:
url: "http://{{ inventory_hostname }}:{{ apache_port }}"
status_code: 200
delegate_to: "{{ groups['lb_servers'][0] }}"
become: no
# 在剧本部署web应用程序之后,烟雾测试确保每个后端web服务器都响应一个200 HTTP状态代码。每个web服务器上的防火墙规则只允许来自负载均衡器的web请求,所以所有冒烟测试都被委派给负载均衡器。
# If the test fails, servers are not re-enabled
# in the load balancers, and the update process halts.
- name: Enable healthy server in load balancers
haproxy:
state: enabled
backend: app
host: "{{ inventory_hostname }}"
delegate_to: "{{ item }}"
with_items: "{{ groups['lb_servers'] }}"
# 如果服务器的冒烟测试失败,则该服务器的进一步处理将停止,并且不会在负载均衡器中重新启用web服务器。当冒烟测试通过时,第二个任务启用负载均衡器中的服务器。
📑尝试使用新版本号执行
[student@workstation update-management]$ ansible-playbook update_webapp.yml -e webapp_version=v1.1.0
剧本会失败。
监视issue_requests.sh脚本的输出。
从外部客户机的角度来看,负载均衡器继续提供web应用程序v1.0版本的响应。但是,来自其中一个服务器的响应停止出现在输出中。
📑拉取代码进行排错分析
[student@workstation update-management]$ cd ~/git-repos
[student@workstation git-repos]$ git clone http://git.lab.example.com:8081/git/simple-webapp.git
[student@workstation git-repos]$ cd simple-webapp
[student@workstation simple-webapp]$ git checkout v1.1.0
[student@workstation simple-webapp]$ ls
index.php
[student@workstation simple-webapp]$ cat index.php
<?php
This is {{ ansible_hostname }}. (version {{ webapp_version}})
?>
# 正确的,应该如下所示,因此,v1.1.0版本是有问题的。
[student@workstation simple-webapp]$ cat index.php
<?php
echo "This is {{ ansible_hostname }}. (version {{ webapp_version}})\n"
?>
📑进行新版本更新
# 假设已修复的版本为 v1.1.1(课本环境已为我们准备)
[student@workstation update-management]$ ansible-playbook update_webapp.yml -e webapp_version=v1.1.1
# 监视issue_requests.sh脚本的输出。
📑清除实验
[student@workstation ~]$ lab update-management finish
📚章节实验
[student@workstation ~]$ lab update-review start
📑拉取实验代码
[student@workstation ~]$ cd /home/student/git-repos/
[student@workstation git-repos]$ git clone http://git.lab.example.com:8081/git/update-review.git
[student@workstation update-review]$ cd update-review
📑执行剧本
[student@workstation update-review]$ ansible-playbook site.yml
📑按要求编写剧本
[student@workstation update-review]$ vim update_webapp.yml
---
- name: Upgrade Web Application
hosts: web_servers
#TODO: Configure max allowable failures
#TODO: Configure batches
max_fail_percentage: 0
serial:
- 5%
- 35%
- 100%
#TODO: Add a pre-task to disable each web server
pre_tasks:
- name: Remove web server from service during the update
haproxy:
state: disabled
backend: app
host: "{{ inventory_hostname }}"
delegate_to: "{{ groups['lb_servers'][0] }}"
roles:
- role: webapp
post_tasks:
- name: Smoke Test - Ensure HTTP 200 OK
uri:
url: "http://{{ inventory_hostname }}:{{ apache_port }}"
status_code: 200
become: no
delegate_to: "{{ groups['lb_servers'][0] }}"
# TODO: Add a post-task to re-enable each web server
- name: Enable healthy server in load balancers
haproxy:
state: enabled
backend: app
host: "{{ inventory_hostname }}"
delegate_to: "{{ groups['lb_servers'][0] }}"
📑执行剧本
[student@workstation update-review]$ ansible-playbook update_webapp.yml
📑上传代码
[student@workstation update-review]$ git add .
[student@workstation update-review]$ git commit -m "Rolling updates"
[student@workstation update-review]$ git push
📑评分并清除实验
[student@workstation ~]$ lab update-review grade
[student@workstation ~]$ lab update-review finish
💡总结
RHCA认证需要经历5门的学习与考试,还是需要花不少时间去学习与备考的,好好加油,可以噶🤪。
以上就是【金鱼哥】对 第五章 协调滚动更新--管理滚动更新 的简述和讲解。希望能对看到此文章的小伙伴有所帮助。
💾 红帽认证专栏系列:
RHCSA专栏: 戏说 RHCSA 认证
RHCE专栏: 戏说 RHCE 认证
此文章收录在RHCA专栏: RHCA 回忆录
如果这篇【文章】有帮助到你,希望可以给【金鱼哥】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点。
如果有对【运维技术】感兴趣,也欢迎关注❤️❤️❤️ 【金鱼哥】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!