ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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 综合实战:Haproxy+Keepalived负载均衡集群
  • 踩坑汇总与实操总结
      • 核心踩坑点汇总
      • 实操心得

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高可用部署,最后实现了Haproxy+Keepalived负载均衡集群的全自动化部署。中间踩了不少权限、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命令将公钥推送到被控节点server2:

ssh-copy-id devops@192.168.48.162

首次连接会弹出主机指纹确认提示,输入yes后再输入devops用户的密码,即可完成公钥推送。推送完成后可以直接SSH登录验证,无需输入密码就说明配置成功。

2.3 Ansible工作目录与基础配置

我没有使用系统默认的/etc/ansible目录,而是在devops用户家目录下创建独立的ansible工作目录,方便文件管理和权限控制。

mkdir-p~/ansiblecd~/ansible

首先编写inventory主机清单文件,定义web主机组和通用连接变量:

[web] server2 ansible_host=192.168.48.162 [web :vars] ansible_user=devops ansible_become=yes ansible_become_method=sudo

将用户名、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\n"dest:/var/www/html/index.html

执行Playbook:

ansible-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 db

node1节点需要提前配置好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:'^Listen'insertafter:'#Listen'line: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\n"dest:/var/www/html/index.html-name:Ensure the default Apache port is 80ansible.builtin.lineinfile:path:/etc/httpd/conf/httpd.confregexp:'^Listen'insertafter:'#Listen'line: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 }}\n"dest:/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:'^Listen'insertafter:'#Listen'line:Listen{{http_port}}notify:restart service httpd

3.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 }}\n"dest:/var/www/html/index.htmltags:t3

可以先查看Playbook中所有的标签:

ansible-playbook install-apache.yml --list-tags

指定单个标签执行,比如只执行安装任务:

ansible-playbook install-apache.yml--tags=t1

也可以指定多个标签,用逗号分隔:

ansible-playbook install-apache.yml--tags=t1,t3

四、进阶实战:Jinja2模板与高可用集群部署

4.1 Keepalived高可用:模板化批量配置

Keepalived主备节点的配置大部分内容一致,只有节点状态、优先级等少数参数不同,非常适合用Jinja2模板+主机变量的方式实现,一份模板适配所有节点。

首先在inventory中新增hacluster组,给每个主机定义独立的状态和优先级变量,组变量定义公共参数:

[hacluster] 192.168.48.161 state=MASTER pri=100 192.168.48.171 state=BACKUP pri=80 [hacluster:vars] interface=eth0 router_id=61 vip=192.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 综合实战:Haproxy+Keepalived负载均衡集群

最后做了一个综合实战案例:两台节点部署Haproxy+Keepalived实现负载层高可用,后端对接Apache服务,整套架构全部通过Ansible自动化部署。

先更新inventory最终分组:

[backend_web] 192.168.48.162 [hacluster] 192.168.48.161 state=MASTER pri=100 192.168.48.171 state=BACKUP pri=80 [hacluster:vars] interface=eth0 router_id=61 vip=192.168.48.200/24 vip_ip=192.168.48.200 [all:children] hacluster backend_web

Haproxy配置模板同样使用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解析,再部署Haproxy+Keepalived高可用负载层,最后部署后端Web服务。执行完成后所有节点状态正常,通过VIP即可访问后端Apache服务,Haproxy状态页也能正常打开。



踩坑汇总与实操总结

核心踩坑点汇总

  1. 密码复杂度校验报错:设置用户密码时长度过短、包含用户名都会触发PAM的密码复杂度警告,测试环境可忽略提示重复输入,生产环境建议遵循密码规范。
  2. sudo配置格式错误:visudo中单词拼写错误、缩进异常都会导致sudo命令失效,修改后建议保留一个root终端验证,避免普通用户无法提权。
  3. YAML缩进语法错误:YAML对空格缩进要求极其严格,禁止使用Tab键,层级必须对齐。初期handlers和tasks层级错位,导致反复报语法错误。
  4. handlers触发条件限制:只有任务状态为changed时才会触发notify,若配置已符合预期,任务为ok状态则handler不会执行,修改配置时需留意该特性。
  5. 密码哈希弃用警告password_hash默认依赖的Python crypt模块在高版本Python中已弃用,生产环境建议安装passlib库以保证兼容性。
  6. 模板变量未定义:Jinja2模板中引用的变量必须在inventory或Playbook中提前定义,否则渲染时会直接报变量未定义错误。

实操心得

完整走下来最大的感受是,Ansible的核心价值在于幂等性模板化:同一份脚本重复执行不会产生副作用,配置通过变量+模板解耦后,扩容节点只需要修改主机清单,部署脚本完全不用改动,批量运维的效率提升非常明显。

从单模块Ad-hoc命令,到Playbook任务编排,再到Jinja2模板、分组管理,一步步进阶下来,自动化运维的思路也越来越清晰。后续还可以继续探索Roles角色化管理,把不同服务的部署拆分成独立角色,代码复用性和可维护性会更高。

返回列表