简介Ansible 2.9.27 是面向 CentOS7/RHEL7 系统的自动化运维工具安装包专为需要批量配置管理、应用部署与日常维护的系统管理员设计。资源以 gz 压缩包形式提供共 29 个文件主体为 rpm 软件包并包含 gz、bz2、xml 格式的仓库元数据整体约 19.29MB。包内不仅包含 ansible 主程序及其依赖组件还附带了 repodata 仓库索引信息可在内网或离线环境下快速搭建本地 yum 源实现一键离线安装。该版本对 RHEL7 系列兼容性良好支持 copy、service、template 等常用模块可配合 Playbook 声明式语法完成配置管理、软件部署与服务编排显著提升基础设施运维效率。资源目录结构清晰便于快速定位所需组件已有 632 人学习适合正在搭建自动化运维体系或需要在受限网络环境中部署 Ansible 的工程师。 如果要我给稳定压倒一切这句话找最佳注脚ansible 2.9.27 一定在名单里。很多同行看到我还在用这个版本第一反应都是不解这不是好几年前的老版本了吗可正是这个版本撑起了我这边多套环境的批量部署从补丁下发、脚本同步到配置管理从来没在核心功能上掉过链子。这篇文章不打算讲大而全的 Ansible 教程而是围绕 2.9.27 这个具体版本把为什么选它、怎么装它、复制文件到所有节点并授权 777 权限怎么做、新手最容易踩的坑有哪些一次讲透。适合正在选型的老手也适合刚入行的运维同学参考至少能帮你少走几段弯路。1. 为什么到今天还在用 2.9.27版本定位和真实理由1.1 2.9 系列在整个 Ansible 生态的位置2.9 是 Ansible 被 Red Hat 整合后、在核心代码库拆分之前的一个重要分水岭。2.10 开始官方把项目拆成了 ansible-core 和 collections 两大部分架构上更清晰但对习惯了装一个 ansible 就全都有的人来说升级反而引入了额外的依赖管理和版本同步成本。2.9.27 正好卡在模块够全、形态够简单的位置上。它内置了大量开箱即用的模块copy、command、shell、ping、yum、apt、service、cron、file、template 这类日常批量操作几乎能覆盖 95% 的服务器管理需求。对我个人来说运维工具的第一原则是稳定可控不是追新。一个经过大量生产环境验证的版本比一个刚发布、社区资料还不多的大版本更让人放心。1.2 新版本不追的理由模块拆分带来的复杂度新版本好在哪到处都是文章但运维真正关心的是升级后我要多干多少活。从 2.10 开始如果 playbook 用到某个 collection 模块得先确认自己装了对应 collection否则直接报找不到模块。再加上语法变化、回调插件兼容、host_key_checking 行为调整……这些都是隐形成本。我的判断标准很朴素生产环境没有强烈功能需求不折腾就是最优解。2.9.27 作为 2.9 分支的收官补丁版本把该修的 bug 和安全问题都收拢到一个稳定状态是一个能让人安心长期使用的版本。当然也要说清楚边界如果你是在全新的 Kubernetes 环境或者依赖某个云厂商的新模块那选新版本更合适。老版本不是万能药但你要是搞批量脚本下发和配置同步2.9.27 完全够用。2. 安装 2.9.27 的三条路线pip、yum 和离线包2.1 pip 精确安装版本可控路径易错我最推荐的控制端安装方式就是 pip能精确锁版本不会出现说好 2.9 结果装成 2.10的尴尬python3 -m pip install ansible2.9.27装完以后验证一下ansible --version踩坑点主要集中在两个地方。第一CentOS 7 自带的 python 是 2.7虽然 2.9.27 支持 python2.7但后面有些模块依赖处理起来麻烦实测用 python3 更省心。第二用 python3 -m pip 安装后可执行文件通常会落在 /usr/local/bin 或 ~/.local/bin如果 PATH 里没包含这个目录会报ansible 命令找不到。这时候用pip3 show -f ansible看一下实际安装位置把对应目录加进 PATH 就能解决。注意如果系统里同时存在多个 Python 版本务必保持用哪个 python 装就用哪个 python 调出的 ansible不要混用。2.2 yum 安装适合快速上线版本不保证如果只是想快速在 CentOS 上搭一个控制端用系统的包管理工具最省事yum install epel-release -y yum install ansible -yEPEL 仓库基本能提供 2.9 系列但具体小版本跟着仓库更新走不一定正好是 2.9.27。我见过不少同学按老教程装完ansible --version显示的不是预期版本折腾半天。Ubuntu/Debian 上对应的是apt install ansible思路同理。我的建议是能接受只要是 2.9 系列就行的用 yum/apt必须锁定 2.9.27 的老老实实用 pip。三种安装方式可以简单对比如下安装方式核心优点主要缺点适用场景pip版本精确可控依赖 Python 环境路径易错有独立控制端机器yum/apt命令简单依赖自动处理小版本不可控快速上线、测试环境离线包不依赖外网需要提前准备包隔离内网生产环境2.3 离线安装内网环境的唯一方案很多生产环境是隔离内网连外部软件源都访问不了。这种场景用 pip 下载离线包再转移是最可控的方式。在一台能联网的机器上pip3 download ansible2.9.27 -d /tmp/ansible-packages把整个 /tmp/ansible-packages 目录拷到内网机器然后在目标机器上执行pip3 install --no-index --find-links/tmp/ansible-packages ansible2.9.27--no-index 告诉 pip 不要尝试访问 PyPI--find-links 指向本地包目录。这里有一个经验如果离线机器和控制端机器的 Python 版本不一致最好用相同版本的 Python 去下载否则 cryptography 这类带二进制编译的依赖很容易出兼容问题。想省事就找一台同版本 Python 的机器下载或者下载时用 --platform 参数指定目标平台。3. 复制文件到所有节点并授权 777核心操作拆解3.1 copy 模块下发文件的基本写法复制文件到所有节点并授权 777 权限是做批量运维时被问最多的需求。用 Ansible 实现ad-hoc 命令非常简洁ansible all -m copy -a src/opt/scripts/deploy.sh dest/opt/deploy.sh ownerroot grouproot mode0777这条命令的目标很明确把 deploy.sh 复制到所有主机的 /opt 目录属主和属组设为 root权限设为 777。第一次执行时因为目标文件不存在每个节点都会返回 changed第二次再执行因为内容和权限都没变化会自动变成 ok。这个行为是 Ansible 的核心设计也就是后面要说的幂等性。3.2 777 权限的坑YAML 中 mode 必须加引号很多人第一次写 playbookmode 直接写0777结果执行完一看权限完全不对。原因在 YAML 解析带前导零的数字会被 YAML 当作八进制解析0777被转成了十进制整数 511Ansible 收到整数 511 后再按字符串处理成八进制权限位最终得到的权限就变成了r-x--x--x跟预期的 rwxrwxrwx 差得十万八千里。正确写法是把 mode 作为字符串传进去- name: copy script to all nodes copy: src: deploy.sh dest: /opt/deploy.sh owner: root group: root mode: 0777也可以写成符号模式mode: urwx,grwx,orwx我习惯统一用带引号的0777直观、不易错别人 review 的时候也一眼能看出这是八进制权限。3.3 目录不存在时先创建目录还有一个高频报错目标目录不存在时copy 模块会直接失败提示类似Destination directory /opt/scripts does not exist。copy 模块不会自动创建深层目录。处理方式是在 playbook 里加一个 file 任务先把目录建好- name: ensure target directory exists file: path: /opt/scripts state: directory mode: 0755 - name: copy script file copy: src: deploy.sh dest: /opt/scripts/deploy.sh owner: root group: root mode: 0777如果你习惯用 ad-hoc也可以先执行一条ansible all -m file -a path/opt/scripts statedirectory mode0755目录不自动创建这个行为初看是坑但其实是刻意的。自动化工具最怕隐式行为目录不存在就显式创建流程反而更清晰也方便回滚和排障。3.4 template 模块差异化配置的下发方式如果不同节点上的文件内容不一样比如 Nginx 配置里带节点 IPcopy 就不够用了这时候要用 template。template 先把 Jinja2 模板渲染好再分发server_name {{ inventory_hostname }};playbook 写起来和 copy 很像- name: deploy nginx config template: src: nginx.conf.j2 dest: /etc/nginx/conf.d/app.conf owner: root group: root mode: 0644这里有个常见误区template 不是把模板原样复制过去而是每台机器根据自己的变量渲染出不同内容。如果只是纯文件复制用 template 反而多此一举。选型标准一句话内容是否依赖主机变量依赖就用 template不依赖就用 copy。4. 从零跑通日常管理主机清单、连通性和批量命令4.1 主机清单分组让操作范围可控无论从哪个教程开始学第一件事永远是配置主机清单。默认路径是 /etc/ansible/hosts也可以自己指定。我的习惯是放在项目目录里维护格式如下[web] 192.168.1.10 192.168.1.11 [db] 192.168.2.10 ansible_userroot ansible_port22 [all:vars] ansible_python_interpreter/usr/bin/python3分组的意义在于精确控制操作范围想重启 web 组就只针对 [web] 操作而不是无脑 all。末尾的[all:vars]是我强烈建议加上的很多系统同时装了 python2 和 python3不指定解释器时 Ansible 默认找 /usr/bin/python找不到就会报python 解释器缺失指定以后能少踩很多坑。4.2 第一次连接连通性检查与 SSH 密钥配置配好清单以后先用 ping 模块验证连通性ansible all -i hosts -m ping第一次执行大概率会碰到两个问题。一个是要求输入 SSH 密码主机多了逐个输密码太煎熬建议提前配置密钥ssh-keygen -t rsa -b 4096 ssh-copy-id root192.168.1.10另一个是Host key verification failed因为本机 known_hosts 里还没有目标主机指纹。测试环境可以在 ansible.cfg 里设置[defaults] host_key_checking False生产环境则建议把指纹提前导入 known_hosts或者用 ssh-keyscan 批量收集ssh-keyscan 192.168.1.10 ~/.ssh/known_hosts4.3 ad-hoc 还是 playbook根据任务性质决定临时执行一条命令用 ad-hoc需要把操作固化、可复用就写 playbook。比如看看所有机器的内存一条 ad-hoc 就够了ansible all -m shell -a free -m但如果这条命令每天都要跑或者涉及判断、循环、异常处理那就应该写进 playbook。我的经验界限是超过两个步骤或者第二步依赖第一步的结果就别再用 ad-hoc 硬凑了。把 playbook 放进版本管理也是运维规范化的起点。4.4 command 与 shell 模块选型批量执行命令时新手最爱问 command 和 shell 有什么区别。command 模块不经过 shell 解释器所以管道符、重定向、变量扩展都不支持# 下面这条会报错因为 command 不支持管道 ansible all -m command -a df -h | head -5要支持管道和重定向必须用 shellansible all -m shell -a df -h | head -5既然 shell 功能更强为什么还要用 command因为 shell 会直接调用目标机器的 shell 解释执行如果命令里拼接了外部变量存在命令注入风险而 command 把整段命令当作参数直接传给可执行文件更安全也更符合幂等理念。我的安全底线很明确能用 command 就不要用 shell非用 shell 时不要拼接用户可控内容。5. 踩坑与排查认证、目录缺失和权限规范5.1 SSH Host Key 校验失败与连接超时生产环境第一次批量执行最高频的失败信息是Host key verification failedknown_hosts 里没有指纹导致的解决办法上文已经写过。还有一个常见问题是 unreachable表现为 SSH 连接超时。先看网络和安全组是否放行 22 端口再用单台 ssh 手动连接验证。如果单台能连上Ansible 却连不上优先检查 ansible_user 是否写对以及控制端用户和远端用户之间的密钥是否匹配。我排障的顺序是单台 ssh 手动连接然后看 ansible.cfg 里的 remote_user最后加 -vvv 看具体 SSH 参数输出。5.2 权限不能只会 777分级授权建议用户要 777工具上也能实现 777但我还是忍不住多说几句。777 意味着任何用户都能读、写、执行一旦脚本里有敏感操作或者机器被非预期用户登录风险会成倍放大。实际项目中我会把需求拆开看如果脚本要被某个服务账号执行就通过属组和写权限来配合如果只是批量下发的临时修复脚本755 甚至 700 就够了配合 Ansible 的 become 在目标机器上以 root 执行。别把能跑就行带到生产环境这是我在多次事故复盘里最想强调的一点。5.3 调试三件套--check、--diff、-vvv写过 playbook 的人都知道改一次跑一次完整执行效率太低。Ansible 提供了三个调试利器。--check 是预演模式不实际执行只告诉你哪些任务会变化适合改动前的校验。--diff 显示文件内容的具体差异配合 copy/template 任务非常直观。最常用的还是 -vvv把 SSH 连接细节、模块参数、远端输出全部打印出来报错时基本能定位到具体哪一步。比如ansible-playbook -i hosts deploy.yml --check --diff -vvv这三个选项组合起来排查问题的速度能快一大截。我个人长期用 2.9.27 之后最大的体会是工具稳定不等于你不需要理解它在底层做的事情。SSH 连接、权限语义、文件幂等这些概念不管版本怎么换都绕不开。等哪天业务真正需要新模块、新语法再带着这些踩坑经验迁移到 ansible-core会比从零开始顺利得多。本文还有配套的精品资源点击获取