老实交代,以前我对自动化运维工具有点“迷之自信”。
那会儿刚入行,觉得自己那一手行云流水的Shell脚本简直无敌:for循环批量操作,sed正则替换配置,awk处理日志,这多极客啊?直到那个凌晨两点的“事故现场”,彻底改变了我的看法。
当时我们要紧急给生产环境的50台Web服务器打一个补丁,更新Nginx配置。我自信满满地敲下了那个用来追加配置的Shell脚本回车键。结果因为网络波动,脚本在一部分机器上中断了,我下意识地按了“重试”。
悲剧发生了——脚本里用的是echo >>追加写入,重试导致配置文件里出现了双份配置,Nginx重启直接报错,全线业务挂了15分钟。
那一刻我才明白,写脚本和做工程是两码事。也是从那时候起,我开始硬着头皮啃Ansible。今天我想以一个“过来人”的身份,不讲枯燥的概念,只聊聊如果你想摆脱“人肉运维”的苦海,Ansible Playbook(剧本)到底该怎么写,以及怎么避免我当年踩过的那些坑。
告别“一次性”脚本,拥抱“幂等性”
很多做开发或者运维刚转型的朋友,最大的思维误区就是把Ansible当成“批量执行Shell命令的工具”。如果你只是在Playbook里用shell模块跑命令,那你真的亏大了。
Ansible最核心的价值在于幂等性(Idempotency)。啥意思?就是同一个操作,无论你执行一次还是执行一百次,结果都是一样的,且不会产生副作用。
回到我那个惨痛的Nginx案例。如果用Shell写,你需要写大量的if判断来检查配置是否存在。但用Ansible的原生模块,画风是这样的:
- name: 确保Nginx配置文件包含安全策略
blockinfile:
path: /etc/nginx/nginx.conf
marker: "# {mark} ANSIBLE MANAGED BLOCK"
block: |
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
这个写法的妙处在哪?
- 自动判断:它会自动检查
/etc/nginx/nginx.conf里有没有这段内容。 - 安全重试:如果有,它就什么都不做;如果没有,它就加上;如果内容不一样,它就修正。
- 结果导向:你不用管它是怎么写入的,你只需要告诉Ansible:“我要这个文件长这样”。
我有个同事大刘,之前死活不愿意学Ansible,觉得写YAML麻烦。后来有次因断电导致脚本跑了一半,他花了一整天去排查哪台跑了哪台没跑。后来我让他试着用上面的逻辑跑了一遍Playbook,5分钟搞定。从那以后,他再也没提过用Shell批量改配置的事。
让代码像“说明书”一样易读
大家回想一下,当你接手前任留下的几百行Shell脚本时,是什么心情?
是不是充满了各种var1、temp_file这种莫名其妙的变量?代码逻辑像迷宫一样?我曾经接手过一个项目,光是读懂那个初始化环境的脚本就花了我整整两天。
Ansible Playbook 强迫你把运维操作变成文档。
这就好比做菜。Shell脚本像是那种只有大厨看得懂的“少许、适量、火候自便”;而Playbook则是标准的工业化SOP(标准作业程序)。
来看看这个对比:
普通脚本风格:
# 安装软件
yum install -y httpd
# 启动
systemctl start httpd
你不知道这步是为了干啥,也不知道失败了会怎样。
Playbook风格:
- name: 部署Web服务全流程
hosts: webservers
tasks:
- name: 第一步:安装Apache服务
yum:
name: httpd
state: present
- name: 第二步:启动服务并设置开机自启
service:
name: httpd
state: started
enabled: yes
我现在的习惯是,每周五下午进行复盘时,只要把Playbook打开,对着YAML文件给新人讲一遍,他们基本就能明白整个系统的部署架构。代码即文档,这句话真不是虚的,它能帮你省下大量写Wiki和解释的时间。
变量与模板:不要把配置“写死”
刚开始写Playbook时,我最爱干的事就是Hardcode(硬编码)。比如把数据库IP直接写在配置文件任务里。
结果到了年底,公司做架构调整,数据库迁移了。我不得不打开十几个Playbook文件,一个个查找替换。那种绝望感,谁试谁知道。
真正的自动化,是把“逻辑”和“数据”剥离开。
这时候,Ansible的Jinja2模板引擎就派上用场了。
举个真实场景:我们要给开发环境(Dev)、测试环境(QA)和生产环境(Prod)部署同一套应用,但它们的端口和数据库地址不一样。
做法是这样的:
-
创建一个模板文件
app_config.j2:[database] host = port = -
在Playbook里调用:
- name: 分发配置文件 template: src: app_config.j2 dest: /opt/app/config.ini -
在变量文件里定义不同环境的值。
这套方法落地后,效果立竿见影。上个月我们做灾备演练,需要把全套环境切换到备用机房。我只需要修改group_vars里的几个IP变量,运行一遍Playbook,10分钟内,30多个微服务的配置全部自动更新并重启完毕。
要是放在以前用脚本处理,我估计得拉上整个运维组通宵加班。
别光看不练,给你3个落地建议
说了这么多,我知道很多朋友还在犹豫:“看起来好难,我还是用老办法吧。”
其实技术债都是这么欠下的。与其等到像我当年那样半夜炸雷,不如现在就开始填坑。Ansible其实是DevOps工具链里门槛最低的一个,不需要Agent,只要能SSH就能跑。
如果你想开始尝试,我建议你这周只做这三件事:
- 环境准备:在你的笔记本或者一台跳板机上装好Ansible(
pip install ansible或者yum install ansible),不需要复杂的配置。 - 写第一个Hello World:不要试图上来就搞复杂的部署。写一个Playbook,只做一件事:在所有目标服务器的
/tmp目录下创建一个叫success.txt的文件。 跑通这个,你就理解了核心流程。 - 重构一个小脚本:找一个你平时最常用的、不超过20行的Shell脚本(比如清理日志、同步时间),把它翻译成Ansible Playbook,并设定为每天自动运行。
当你第一次看着屏幕上那一排绿色的“OK”和黄色的“Changed”滚动闪过,相信我,那种掌控感会让你上瘾的。
最后留个问题:你们现在的日常运维中,哪一个重复性操作让你最头疼?或者如果你已经用了Ansible,踩过什么印象深刻的“坑”?欢迎在评论区聊聊,我们一起避雷。