简介:Ansible 2.9.27 离线安装包,面向 CentOS 7 与 RHEL 7 系统管理员和运维工程师,适用于无外网或内网隔离环境下的自动化运维部署。该工具基于无代理架构,无需在目标服务器安装额外客户端,通过 SSH 协议即可管理大量设备,帮助团队简化配置管理、应用发布与批量命令执行等日常运维任务。
压缩包共 29 个文件,以 22 个 rpm 格式为主,涵盖 Ansible 主程序及 Python 相关依赖库;另含 gz、bz2 与 xml 等仓库元数据文件,可用于搭建本地 yum 源,整体大小约 19.29 MB。借助该包,用户能够在离线环境中直接执行 yum 安装,免去依赖逐一匹配的困扰,快速获得可运行的自动化运维工具链。
目前已有 632 人浏览学习。通过该 Ansible 控制端,可编写 YAML 格式的 Playbook 声明式地编排任务,覆盖文件分发、服务控制、软件包管理等场景,适合企业内网批量配置与服务器标准化交付,能显著降低重复手工操作带来的出错风险。
1. 项目整体设计与版本选型
1.1 为什么是2.9.27这个版本
Ansible 2.9.27是Ansible 2.9系列在2021年发布的最后一个维护版本,也可以说是2.9系列的“收官之作”。可能有人会问:现在Ansible都出了好几个大版本了,为什么还要用2.9.27?这个问题我在实际项目中遇到过很多次,得说清楚。
首先,Ansible 2.9是最后一个使用“传统Ad-Hoc命令和Playbook编写风格”的主流稳定版本。从2.10开始,Ansible做了比较大的架构调整,核心模块和Collections被拆分,很多模块的调用方式、命令写法都有变化。如果你维护的是老项目、老脚本、老Playbook,升到新版本会面临大量兼容性修复工作,这是一笔不小的成本。我在企业里见过不少团队,因为升级后Playbook跑不通,又默默回滚到2.9的。
其次,2.9.27修复了2.9系列前期积累的大量Bug,同时保留了传统Ansible的使用习惯。对于生产环境的批量管理来说,稳定性和可预测性比“新功能”更值钱。再加上很多第三方运维平台、自动化发布系统,内部依赖的还是2.9.x的调用方式,所以2.9.27成了事实上的“企业稳定版”。如果你只是管理几十台、几百台服务器,做分发文件、批量执行命令、配置下发这类日常运维操作,2.9.27完全够用,而且资料多、坑少、网上能找到的踩坑记录也最多。
1.2 核心需求拆解:从“会安装”到“能干活”
这篇项目的核心关键词是“安装部署”和“复制文件到所有节点,并授权777权限”。也就是说,很多人第一次接触Ansible,并不是为了学一堆理论概念,而是有个很具体的场景:我现在有十几台或者几十台服务器,我想把同一个配置文件、同一个脚本、同一个安装包分发到所有机器上,并且希望目标目录/文件有指定的权限,最好一条命令搞定。
Ansible天然适合这个需求。它的架构是“控制端 + 被管节点”模式,控制端装Ansible,被管节点只需要有Python环境和SSH服务,不需要提前装任何Agent,完全是靠SSH通道来执行命令。这也是它能在运维圈长期受欢迎的主要原因——没有Agent,意味着你不需要在被管机器上做大量前置部署,也意味着你的存量服务器哪怕配置不高、环境很杂,只要能SSH登录就能纳管。
围绕这个需求,我拆解出三块核心能力:
- 批量分发:把文件从控制端复制到所有目标节点的指定路径;
- 权限控制:复制的同时设置文件属主、属组、权限位(比如777);
- 幂等性:无论执行多少次,只要目标状态一致,结果就不会出乱子,不会重复追加、不会破坏已有配置。
这套思路其实就是Ansible模块化设计的精髓。咱们在下面章节里一步一步落地,从环境准备开始,到实际执行命令,再到遇到问题怎么排查。
2. 环境准备与安装部署细节
2.1 控制端与被管节点的要求
在动手装之前,先把环境要求捋清楚,避免后面踩坑。
控制端(也就是你执行ansible命令的这台机器):建议是Linux系统,CentOS 7/8、Ubuntu 18.04/20.04、Debian 10/11我这边都实测过,没问题。控制端需要能正常访问外网(用于下载安装包),并且能通过SSH访问所有被管节点。Python版本要求2.7或3.5+,2.9.27对Python 3的支持已经很成熟,所以不用刻意去装老版本Python。
被管节点:要求相对宽松,有SSH服务、有Python 2.6/2.7或Python 3.5+就行。注意一点,被管节点默认可能没有安装python命令,只有python3,这需要在配置里指定一下,后面我会专门讲。
网络层面,控制端到各节点的22端口必须通,然后保证控制端能解析各节点的主机名,或者直接用IP管理。建议提前做好控制端到所有节点的SSH免密登录,不然每次执行命令都要输密码,批量操作的意义就少了一半。
2.2 安装方式对比:包管理器、pip、源码
Ansible 2.9.27的安装方式主要就三种,我分别说下适用场景。
方式一:使用系统包管理器安装(yum/apt)
CentOS/RHEL系统需要先安装EPEL源,然后执行:
yum install epel-release -y yum install ansible -yUbuntu/Debian系统直接:
apt update apt install ansible -y这种方式的优点是依赖关系自动处理,命令最短,适合刚接触Ansible的人。但缺点是系统仓库里的版本可能不是2.9.27,有的源给的是2.9.x的早期版本,有的源甚至给到2.10+。如果你对版本有严格要求,这种方式不够精确。
方式二:使用pip安装指定版本(我推荐)
Ansible本质上是Python项目,用pip安装可以把版本锁得很死,干净利落:
pip3 install ansible==2.9.27装完验证一下:
ansible --version输出中能看到“ansible 2.9.27”就OK了。推荐在虚拟环境中安装,避免污染系统Python环境。实际项目里我会先建一个专门的Python虚拟环境:
python3 -m venv /opt/venv/ansible source /opt/venv/ansible/bin/activate pip install ansible==2.9.27之后每次要执行ansible,先激活环境,管理端环境干净、可控,后面升级也方便。
方式三:源码安装
到GitHub的ansible/ansible仓库,选择stable-2.9分支或者打tag的2.9.27版本,拉下来后执行source hacking/env-setup。这种方式适合要改Ansible源码做二次开发的场景,普通运维没必要走这条路。
提示:安装完成后,务必确认一下
/etc/ansible/ansible.cfg存在(yum安装会自动生成,pip安装有时不生成)。如果不存在,可以手动创建,或者执行ansible命令时它会使用默认配置。建议手动建一份,后面配置起来方便。
2.3 核心配置文件:ansible.cfg与hosts清单
Ansible装完之后,第一个要配置的就是Inventory(主机清单),默认位置是/etc/ansible/hosts。这个文件告诉Ansible“你要管哪些机器”。我比较习惯按业务分组来写:
[web_servers] 192.168.1.11 192.168.1.12 192.168.1.13 [db_servers] 192.168.1.21 ansible_ssh_port=2222 192.168.1.22 [all:vars] ansible_user=root ansible_python_interpreter=/usr/bin/python3上面这段配置里有个关键参数:ansible_python_interpreter=/usr/bin/python3。这解决的就是前面提到的问题——很多新装系统没有python命令,只有python3,如果不显式指定Python解释器路径,Ansible连到目标机器后会尝试用python,找不到就会报错。
还有一个常用配置是ansible_ssh_port,当某些机器的SSH端口不是默认22时,用这个参数单独指定。如果所有机器的SSH端口都一致,也可以写在组变量里。
然后看看ansible.cfg。虽然Ansible有一套默认配置,但实际使用中我通常会在项目目录放一个自定义的ansible.cfg,内容大概是这样:
[defaults] inventory = ./hosts host_key_checking = False retry_files_enabled = True gathering = smart timeout = 30 ssh_args = -o ControlMaster=auto -o ControlPersist=60s重点解释一下几个参数的设计意图:
host_key_checking = False:关闭SSH首次连接时的host key确认提示,否则批量管理新机器时会卡在交互确认上,没法全自动跑。gathering = smart:只在第一次执行时收集被管节点完整facts信息,后续执行如果facts没变化就使用缓存,能明显提升执行速度。ssh_args这行是SSH连接复用配置,开了之后,同一台机器在短时间内多次执行任务,会复用同一条SSH连接,速度快很多,大量节点编排时效果非常明显。
这些配置写好后,先验证一下控制端到被管节点的连通性:
ansible all -m ping如果返回每个节点都是"pong",说明环境没问题,可以继续往下走了。
3. 核心实操:复制文件到所有节点并授权777
3.1 先搞明白copy模块的工作方式
批量分发文件用到的核心模块是copy。我第一次用这个模块时有个误区:以为是“先上传文件再单独执行一条chmod命令改权限”。实际上copy模块支持在复制的同时设置文件属性,一步到位。
copy模块的核心参数有这几个:
src:源文件路径,对应控制端本地路径;dest:目标路径,对应被管节点的绝对路径;owner:文件属主;group:文件属组;mode:文件权限位,可以写成'0777'或'777'。
这里有个细节要注意:mode参数传的是字符串,不是数字。用YAML写Playbook时,写成mode: 0777或者mode: '0777'都可以;在Ad-Hoc命令行里则要写成mode=0777。如果只写mode = 777,在某些版本里也能识别,但为了严谨,我建议统一带上前导0,写作0777,这样表达的语义更明确。
另外,copy模块支持递归复制整个目录,只要src指向的是一个目录,并且dest是个已存在的目录路径,它就会把整个目录结构复制过去,并且mode参数在递归复制时会对目录内所有文件生效。不过这里有个小坑:如果目录里包含可执行脚本、普通配置文件,它们都会被统一设置成同样的权限,所以用递归复制时要谨慎。
3.2 Ad-Hoc命令实战:一条命令传文件并授权
我们先从最直接的Ad-Hoc命令开始。场景是这样的:我有3台Web服务器,需要把控制端/opt/packages/deploy.sh这个脚本分发到所有Web服务器的/usr/local/bin/目录,并赋予777权限。
执行命令如下:
ansible web_servers -m copy -a "src=/opt/packages/deploy.sh dest=/usr/local/bin/deploy.sh owner=root group=root mode=0777"这条命令的含义逐段拆开看:
web_servers:指定主机组,也就是hosts文件里定义的那组机器;-m copy:调用copy模块;-a "...":模块参数,按空格分隔多个键值对。
执行后,Ansible会先对被管节点做一次连接初始化(收集facts),然后逐个节点执行复制任务。输出结果中每个节点会显示changed或ok状态,同时还会有一些JSON格式的返回信息,比如checksum、dest、gid、group、mode、owner、size等字段,这些信息能帮我们确认复制结果是否符合预期。
我实测跑完一次后,返回的其中一条信息长这样:
192.168.1.11 | CHANGED => { "changed": true, "checksum": "a3d5c3b0d4a6fg2d0c4c9999999999999999999a", "dest": "/usr/local/bin/deploy.sh", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "size": 4632, "src": "/root/.ansible/tmp/ansible-tmp-xxx/source" }这个输出很有价值,mode字段确认了777权限已经生效。src字段指向的是Ansible的临时目录路径,这是Ansible的运作机制——它先把文件传到被管节点的临时目录,然后再执行复制操作,任务结束后自动清理临时文件。不需要我们干预,知道即可。
3.3 Playbook方式:把过程固化成可复用脚本
Ad-Hoc命令适合临时、一次性操作。如果你想要一个“以后每次发文件都能用”的标准化流程,那就得写Playbook了。Playbook相当于把整个任务流程刻成了模板,跑一次、跑一百次效果一致。
创建一个名为copy_deploy_file.yml的文件:
--- - name: Copy deploy script to web servers and set permissions hosts: web_servers become: yes tasks: - name: Copy deploy.sh to remote server copy: src: /opt/packages/deploy.sh dest: /usr/local/bin/deploy.sh owner: root group: root mode: '0777'先用ansible-playbook --syntax-check copy_deploy_file.yml做语法检查,没问题后执行:
ansible-playbook copy_deploy_file.yml你可能注意到Playbook里多了个become: yes,这个参数的作用是以sudo权限执行任务。如果目标机器的普通用户有sudo权限,并且我们不想直接用root登录,那这个配置就很有必要。使用root账号直连时,become写不写都不影响结果,但写上更通用。
再说说幂等性的问题。Playbook第二次执行时,如果目标文件的checksum和源文件一致、权限也是0777,Ansible会直接跳过,返回ok而不会重新复制一遍。这种特性在批量运维中很实用——你不会因为重复执行而搞乱服务器状态。
3.4 目录分发场景:批量拷贝整个目录
有时候要分发的不是一个文件,而是一整个配置目录,比如Nginx的conf.d或者某个项目的配置文件集。copy模块的src指向目录即可:
ansible web_servers -m copy -a "src=/opt/configs/ dest=/etc/myapp/configs/ owner=root group=root mode=0755"注意src路径末尾的斜杠是有讲究的。如果src写成/opt/configs/(带斜杠),Ansible会把目录内部的内容复制到dest目录下;如果写成/opt/configs(不带斜杠),Ansible会把configs这个目录整体复制到dest的父目录下,生成/etc/myapp/configs/configs这样的路径。这是新手最容易踩的坑,很多人以为目录名带了斜杠没区别,实际结构完全不同。
我一般都会在参数里把dest写得更明确,比如dest=/etc/myapp/,然后根据是否带斜杠来预判最终路径,确保不搞混。
4. 常见问题与排查技巧实录
4.1 批量操作时常见的连接与权限故障
我在实际环境中跑Ansible,遇到最多的问题基本集中在这几类,整理成表格方便对照排查:
| 常见现象 | 可能原因 | 解决思路 |
|---|---|---|
Host key verification failed | 被管节点首次连接,host key未确认 | ansible.cfg中配置host_key_checking = False |
Permission denied (publickey,password) | SSH免密未配置好,或用户名不对 | 检查ansible_user配置;用ssh-copy-id重传公钥 |
python: command not found | 目标机器没有python命令 | 设置ansible_python_interpreter=/usr/bin/python3 |
sudo: no tty present | sudo需要密码或未允许免密sudo | 配置become时确认ansible_become_pass;或目标机配置NOPASSWD sudo |
connection timed out | 网络不通或防火墙拦截22端口 | 用ansible host -m ping单独测连通性;检查防火墙 |
unsupported parameter for module: copy | Ansible版本过旧/过新,模块参数变化 | 用ansible-doc copy查看当前版本支持的参数 |
这些问题的排查思路大体一致:先用简单命令定位范围(是单台机器的问题,还是所有机器的问题),再逐步缩小。比如所有机器都报timeout,那基本是控制端网络或防火墙的全局问题;只有个别机器报Permission denied,那就集中查那台机器的SSH配置和账号权限。
4.2 文件权限777没生效的几种情况
权限相关的问题,看起来简单,实际排查时隐藏点不少。我遇到过三种情况:
第一种:mode参数被忽略。如果copy模块执行后返回ok而不是changed,说明Ansible认为目标文件状态已经符合要求,不会重新改权限。这时候去目标机器上看,会发现权限确实还是原来的。原因往往是用户在前一次执行时写了mode=0755,后一次改成mode=0777,Ansible应该能检测到差异并更新,但如果文件内容完全一致、只有权限差异,有些特殊场景下state对比可能不准确。解决办法是加一个强制更新参数:
ansible web_servers -m copy -a "src=/tmp/deploy.sh dest=/usr/local/bin/deploy.sh mode=0777 force=yes"第二种:目标路径上已存在同名文件。如果目标文件已存在且内容与源文件不一致,copy模块默认会覆盖(force默认就是yes),但如果你在配置里写了force=no,那目标文件不会被替换,权限自然也不会变。这时候要么删掉force=no,要么先手动清理目标文件。
第三种:受父目录权限影响。设置了文件的777权限,但父目录没有执行权限,用户照样无法通过路径访问这个文件。这不是Ansible的问题,是Linux本身访问控制机制决定的。批量授权时,建议把父目录权限一起梳理清楚,比如/usr/local/bin一般是755,这是正常的,但如果你的目录层级比较特殊,就要注意了。
4.3 验证结果:别只看changed,要实测
任务执行完毕,别急着收工。我会习惯性地做几个额外验证:
- 随机挑一两台节点,登录上去用
ls -l看目标文件权限; - 用
stat -c "%a %n" /usr/local/bin/deploy.sh查看权限数字是否正确; - 如果分发的是可执行脚本,顺手执行一次,确认没有权限或语法问题。
如果想要更规范的验证方式,可以写一个Playbook,用stat模块去收集目标文件的详细属性,然后和期望值做断言。不过日常操作中,挑重点节点抽查就够了。
还有一个我常用的技巧:在Playbook的copy任务后面,紧接着加一个命令任务,把目标文件的权限和校验值打印出来。比如:
- name: Verify file permission shell: stat -c "%a %n" /usr/local/bin/deploy.sh register: result tags: verify执行完copy任务后,再把result.stdout打印到终端,我就能在所有节点上统一看到结果,不需要挨个登录去看。
5. 经验心得:从“能跑”到“跑得稳”
Ansible 2.9.27这个版本,我用了很久,有几个心得值得分享。
第一个心得是:把常用任务固化成Playbook,而不是永远用Ad-Hoc命令。Ad-Hoc适合临场发挥,但不可追溯、不利于团队协作。我今天执行了一条复制命令,明天同事想复现,他不知道命令的历史记录,也不知道当时用了哪些参数。但Playbook可以放到Git仓库里,每次改动有记录、有review,这才是“工程化”的做法。我的习惯是:同一个操作如果执行超过两次,就立刻写进Playbook。
第二个心得是:统一节点命名和Inventory结构。很多团队管理几十台机器,hosts文件里还是简单堆IP,时间一长根本不知道哪台机器是干什么的。我建议按“业务-角色-环境”来分层,比如[web-prod]、[web-test]、[db-prod],再配合ansible all --list-hosts查看当前纳管范围,这样不管是手动执行还是写自动化脚本,都清晰明了。
第三个心得是:Ansible 2.9.27虽然没有新版本的炫酷功能,但它的稳定性和兼容性,使得它特别适合企业内部大量存量服务器的管理场景。遇到问题时,网上能搜到的解决方案几乎覆盖了所有常见坑,这种“社区资源厚度”本身就是巨大的效率资产。如果你的管理边界在几百台节点以内,没有用到AWX、Ansible Tower这类高级平台,2.9.27完全能满足日常需求。
最后再补充一个实用小技巧:执行Playbook时,用--step参数可以逐台确认,第一次跑重要变更时建议加上;等确认逻辑没问题了,再全量跑。经验就是这么一次次试出来的。
本文还有配套的精品资源,点击获取