2026/8/16 8:46:45

Day 20-Ansible 自动化运维实战复盘:从环境搭建到高可用集群部署

Day 20-Ansible 自动化运维实战复盘:从环境搭建到高可用集群部署 目录Ansible自动化运维实操从环境搭建到高可用集群部署全流程复盘一、实验环境说明二、环境准备Ansible管控端与被控端配置2.1 被控端统一用户与sudo权限配置2.2 控制端SSH免密配置2.3 Ansible工作目录与基础配置三、Playbook入门Apache服务自动化部署3.1 基础版三步完成Apache部署3.2 主机分组多节点批量管理3.3 配置文件修改lineinfile模块改端口3.4 配置变更触发重启handlers机制3.5 变量引用facts变量与自定义变量3.6 自动校验uri模块做可用性检测3.7 任务标签tags实现精细化执行四、进阶实战Jinja2模板与高可用集群部署4.1 Keepalived高可用模板化批量配置4.2 批量用户管理loop循环迭代4.3 批量分发hosts文件模板自动生成映射4.4 综合实战HaproxyKeepalived负载均衡集群踩坑汇总与实操总结核心踩坑点汇总实操心得Ansible自动化运维实操从环境搭建到高可用集群部署全流程复盘一、实验环境说明本次实操共使用2台Rocky Linux和1台Centos 7主机分别承担控制节点、Web后端、高可用备节点角色具体IP与作用如下主机名IP地址角色与作用server1192.168.48.161Ansible控制节点、Keepalived主节点、Haproxy主节点负责下发配置与管控所有主机server2192.168.48.162Web后端节点部署Apache服务作为负载均衡后端池成员node1192.168.48.171Keepalived备节点、Haproxy备节点同时用于测试批量用户管理等功能这次实操从Ansible基础环境搭建开始一步步完成了Playbook入门、Jinja2模板配置、Keepalived高可用部署最后实现了HaproxyKeepalived负载均衡集群的全自动化部署。中间踩了不少权限、YAML缩进、变量引用的坑把完整流程和排坑思路整理出来方便后续复盘。二、环境准备Ansible管控端与被控端配置2.1 被控端统一用户与sudo权限配置Ansible基于SSH协议工作为了统一管控权限所有被控节点都需要创建专用的运维用户并配置sudo免密提权。首先在server2节点创建devops用户并设置密码useradddevopspasswddevops一开始图省事设了个短密码直接被系统弹出BAD PASSWORD警告还踩了一次两次密码输入不一致的坑最后设置了符合复杂度要求的密码才通过验证。用户创建完成后通过visudo命令配置sudo免密权限在root配置行下方添加devops用户的权限规则让该用户可以无需密码执行所有sudo命令## Allow root to run any commands anywhere root ALL(ALL) ALL devops ALL(ALL) NOPASSWD: ALL同样的操作在server1控制端也执行一遍创建devops用户并配置sudo免密为后续SSH免密和Ansible运行做准备。2.2 控制端SSH免密配置Ansible默认通过SSH连接被控端配置密钥免密登录后无需每次输入密码是自动化运维的基础。切换到devops用户生成4096位的RSA密钥对su- devops ssh-keygen-trsa-b4096生成过程一路回车即可不设置密钥口令避免后续使用时重复输入密码。密钥生成完成后通过ssh-copy-id命令将公钥推送到被控节点server2ssh-copy-id devops192.168.48.162首次连接会弹出主机指纹确认提示输入yes后再输入devops用户的密码即可完成公钥推送。推送完成后可以直接SSH登录验证无需输入密码就说明配置成功。2.3 Ansible工作目录与基础配置我没有使用系统默认的/etc/ansible目录而是在devops用户家目录下创建独立的ansible工作目录方便文件管理和权限控制。mkdir-p~/ansiblecd~/ansible首先编写inventory主机清单文件定义web主机组和通用连接变量[web] server2 ansible_host192.168.48.162 [web :vars] ansible_userdevops ansible_becomeyes ansible_become_methodsudo将用户名、sudo提权配置都放在组变量中后续执行命令时无需重复附加参数。接着编写ansible.cfg主配置文件指定主机清单路径同时关闭主机密钥检查避免首次连接弹出确认提示[defaults] inventory/home/devops/ansible/inventory host_key_checking False配置完成后使用ping模块做连通性测试ansible web-mping返回ping: pong就说明两端通信正常Ansible基础环境搭建完成。三、Playbook入门Apache服务自动化部署3.1 基础版三步完成Apache部署第一个Playbook实现最基础的Apache部署包含安装软件、启动服务、写入默认首页三个任务。创建install-apache.yml文件-hosts:webbecome:yestasks:-name:Install the Apacheansible.builtin.yum:name:httpdstate:present-name:Start service httpd,if not startedansible.builtin.service:name:httpdstate:startedenabled:yes-name:create index.htmlansible.builtin.copy:content:www.westos.org\ndest:/var/www/html/index.html执行Playbookansible-playbook install-apache.yml首次执行三个任务均为changed状态说明软件安装、服务启动、首页写入全部执行成功。Ansible的幂等性在这里体现得很明显重复执行时已完成的任务会显示ok不会重复操作。3.2 主机分组多节点批量管理后续新增node1节点后我将主机按角色分组管理web组存放Web节点db组存放测试节点再通过:children关键字定义lamp父组批量操作所有节点时直接调用lamp组即可。更新inventory文件[web] 192.168.48.162 [db] 192.168.48.171 [lamp:children] web dbnode1节点需要提前配置好devops用户和sudo免密操作流程和server2完全一致。配置完成后测试lamp组的连通性ansible lamp-mping两个节点均返回pong分组配置正常。3.3 配置文件修改lineinfile模块改端口需要修改Apache配置文件的监听端口时使用lineinfile模块最合适功能类似Linux的sed命令通过正则匹配行并替换内容。比如将默认80端口修改为8080在Playbook中新增任务-name:Ensure the default Apache port is 8080ansible.builtin.lineinfile:path:/etc/httpd/conf/httpd.confregexp:^Listeninsertafter:#Listenline:Listen 8080执行Playbook后只有端口修改任务为changed状态其余已配置完成的任务均为ok状态不会重复执行。3.4 配置变更触发重启handlers机制修改端口后需要重启服务才会生效但如果端口没有发生变更就没必要重启服务这种场景正好适用Ansible的handlers机制只有任务状态为changed时才会通过notify触发对应的处理器。将端口改回80新增notify触发和handlers配置-hosts:webbecome:yestasks:-name:Install the Apacheansible.builtin.yum:name:httpdstate:present-name:Start service httpd,if not startedansible.builtin.service:name:httpdstate:startedenabled:yes-name:create index.htmlansible.builtin.copy:content:www.westos.org\ndest:/var/www/html/index.html-name:Ensure the default Apache port is 80ansible.builtin.lineinfile:path:/etc/httpd/conf/httpd.confregexp:^Listeninsertafter:#Listenline:Listen 80notify:restart service httpdhandlers:-name:restart service httpdansible.builtin.service:name:httpdstate:restarted执行后可以看到端口修改任务变更后触发了RUNNING HANDLER执行服务重启。如果端口已经是80任务为ok状态handler就不会执行避免不必要的服务中断。3.5 变量引用facts变量与自定义变量Ansible的facts组件可以自动采集被控端的主机名、IP、系统版本等信息这些内置变量可以直接在Playbook中调用。比如将首页内容设置为当前主机名方便区分不同后端节点-name:create index.htmlansible.builtin.copy:content:{{ ansible_hostname }}\ndest:/var/www/html/index.html除了内置facts变量也可以在Playbook中自定义变量比如将端口号定义为变量后续修改时只需更改变量值即可-hosts:lampvars:http_port:80tasks:...-name:Ensure the default Apache port is{{http_port}}ansible.builtin.lineinfile:path:/etc/httpd/conf/httpd.confregexp:^Listeninsertafter:#Listenline:Listen{{http_port}}notify:restart service httpd3.6 自动校验uri模块做可用性检测服务部署完成后可以通过uri模块自动发起HTTP请求验证服务是否正常返回200状态码无需手动逐个curl测试。在Playbook中新增一个针对localhost的play专门执行检测任务-hosts:localhostgather_facts:falsebecome:falsetasks:-name:Check that you can connect (GET) to a page and it returns a status 200ansible.builtin.uri:url:http://192.168.48.162return_content:trueregister:result-name:Print return information from the previous taskansible.builtin.debug:var:result执行完成后可以看到返回状态码为200响应内容为server2说明Apache服务运行正常。3.7 任务标签tags实现精细化执行当Playbook任务较多时有时只需要执行其中某几个任务不需要全量运行。给任务打上tags标签就可以通过标签指定执行范围。给每个任务添加对应的标签-name:Install the Apacheansible.builtin.yum:name:httpdstate:presenttags:t1-name:Start service httpd,if not startedansible.builtin.service:name:httpdstate:startedenabled:yestags:t2-name:create index.htmlansible.builtin.copy:content:{{ ansible_hostname }}\ndest:/var/www/html/index.htmltags:t3可以先查看Playbook中所有的标签ansible-playbook install-apache.yml --list-tags指定单个标签执行比如只执行安装任务ansible-playbook install-apache.yml--tagst1也可以指定多个标签用逗号分隔ansible-playbook install-apache.yml--tagst1,t3四、进阶实战Jinja2模板与高可用集群部署4.1 Keepalived高可用模板化批量配置Keepalived主备节点的配置大部分内容一致只有节点状态、优先级等少数参数不同非常适合用Jinja2模板主机变量的方式实现一份模板适配所有节点。首先在inventory中新增hacluster组给每个主机定义独立的状态和优先级变量组变量定义公共参数[hacluster] 192.168.48.161 stateMASTER pri100 192.168.48.171 stateBACKUP pri80 [hacluster:vars] interfaceeth0 router_id61 vip192.168.48.200/24编写keepalived.conf.j2模板文件用变量替换所有差异化配置项global_defs { router_id LVS_DEVEL vrrp_skip_check_adv_addr vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_instance VI_1 { state {{ state }} interface {{ interface }} virtual_router_id {{ router_id }} priority {{ pri }} advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { {{ vip }} dev {{ interface }} } }编写keepalived.ymlPlaybook完成软件安装、配置下发、服务启动全流程配置变更时自动触发服务重启最后在本地验证VIP连通性-hosts:haclusterbecome:yestasks:-name:Install keepalivedansible.builtin.yum:name:keepalivedstate:present-name:Deploy keepalived config templateansible.builtin.template:src:keepalived.conf.j2dest:/etc/keepalived/keepalived.confnotify:restart keepalived service-name:Start enable keepalivedansible.builtin.service:name:keepalivedstate:startedenabled:yeshandlers:-name:restart keepalived serviceansible.builtin.service:name:keepalivedstate:restarted-hosts:localhostgather_facts:falsebecome:falsetasks:-name:Test ping virtual VIPansible.builtin.command:ping-c 3 192.168.48.200register:ping_res-debug:var:ping_res.stdout执行完成后在server1上通过ip a查看网卡信息可以看到虚拟IP 192.168.48.200已经成功绑定在eth0网卡上本地ping VIP也能正常通。4.2 批量用户管理loop循环迭代需要批量创建多个用户时不需要重复编写user任务使用loop循环迭代用户列表即可配合password_hash过滤器可以对密码进行SHA512加密。编写user.yml-hosts:dbbecome:yestasks:-ansible.builtin.user:name:{{ item.user }}password:{{ item.pass | password_hash(sha512) }}state:presentcreate_home:yesloop:-{user:user1,pass:pass1}-{user:user2,pass:pass2}执行时会出现一条弃用警告Python的crypt模块将在后续版本中移除推荐安装passlib库。测试环境可以忽略该警告不影响用户创建结果。登录被控端查看用户家目录两个用户均已正常创建。4.3 批量分发hosts文件模板自动生成映射集群节点数量较多时手动维护每台机器的/etc/hosts文件非常繁琐。通过Jinja2模板结合Ansible的groups魔法变量可以自动生成所有节点的主机名映射批量下发到所有机器。基础版hosts.j2模板固定写入所有节点映射127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.48.161 server1 192.168.48.162 server2 192.168.48.171 node1编写deploy_hosts.yml将模板批量分发到所有节点-hosts:allbecome:yestasks:-ansible.builtin.template:src:hosts.j2dest:/etc/hostsowner:rootgroup:rootmode:0644后续优化了模板写法通过for循环遍历指定主机组自动生成后端节点映射新增节点时只需修改inventory无需改动模板127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.48.161 server1 192.168.48.162 server2 192.168.48.171 node1 {% for ip in groups[backend_web] %} {{ ip }} web{{ loop.index }} {% endfor %}4.4 综合实战HaproxyKeepalived负载均衡集群最后做了一个综合实战案例两台节点部署HaproxyKeepalived实现负载层高可用后端对接Apache服务整套架构全部通过Ansible自动化部署。先更新inventory最终分组[backend_web] 192.168.48.162 [hacluster] 192.168.48.161 stateMASTER pri100 192.168.48.171 stateBACKUP pri80 [hacluster:vars] interfaceeth0 router_id61 vip192.168.48.200/24 vip_ip192.168.48.200 [all:children] hacluster backend_webHaproxy配置模板同样使用for循环遍历backend_web组自动生成后端服务器列表扩容时只需在inventory中加IP无需修改配置模板global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners stats timeout 30s user haproxy group haproxy daemon defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 frontend http_front bind *:80 default_backend http_back backend http_back balance roundrobin {% for srv in groups[backend_web] %} server web{{ loop.index }} {{ srv }}:80 check inter 2000 fall 3 rise 2 {% endfor %} listen stats bind *:8088 stats enable stats uri /stats stats auth admin:123456完整的Playbook分为三个逻辑段先批量更新所有节点的hosts解析再部署HaproxyKeepalived高可用负载层最后部署后端Web服务。执行完成后所有节点状态正常通过VIP即可访问后端Apache服务Haproxy状态页也能正常打开。踩坑汇总与实操总结核心踩坑点汇总密码复杂度校验报错设置用户密码时长度过短、包含用户名都会触发PAM的密码复杂度警告测试环境可忽略提示重复输入生产环境建议遵循密码规范。sudo配置格式错误visudo中单词拼写错误、缩进异常都会导致sudo命令失效修改后建议保留一个root终端验证避免普通用户无法提权。YAML缩进语法错误YAML对空格缩进要求极其严格禁止使用Tab键层级必须对齐。初期handlers和tasks层级错位导致反复报语法错误。handlers触发条件限制只有任务状态为changed时才会触发notify若配置已符合预期任务为ok状态则handler不会执行修改配置时需留意该特性。密码哈希弃用警告password_hash默认依赖的Python crypt模块在高版本Python中已弃用生产环境建议安装passlib库以保证兼容性。模板变量未定义Jinja2模板中引用的变量必须在inventory或Playbook中提前定义否则渲染时会直接报变量未定义错误。实操心得完整走下来最大的感受是Ansible的核心价值在于幂等性和模板化同一份脚本重复执行不会产生副作用配置通过变量模板解耦后扩容节点只需要修改主机清单部署脚本完全不用改动批量运维的效率提升非常明显。从单模块Ad-hoc命令到Playbook任务编排再到Jinja2模板、分组管理一步步进阶下来自动化运维的思路也越来越清晰。后续还可以继续探索Roles角色化管理把不同服务的部署拆分成独立角色代码复用性和可维护性会更高。