尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Ansible 2.9.27实战:批量复制文件到所有节点并授权777权限

Ansible 2.9.27实战:批量复制文件到所有节点并授权777权限 简介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.52.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/aptCentOS/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 ansible2.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 ansible2.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_port2222 192.168.1.22 [all:vars] ansible_userroot 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 ControlMasterauto -o ControlPersist60s重点解释一下几个参数的设计意图host_key_checking False关闭SSH首次连接时的host key确认提示否则批量管理新机器时会卡在交互确认上没法全自动跑。gathering smart只在第一次执行时收集被管节点完整facts信息后续执行如果facts没变化就使用缓存能明显提升执行速度。ssh_args这行是SSH连接复用配置开了之后同一台机器在短时间内多次执行任务会复用同一条SSH连接速度快很多大量节点编排时效果非常明显。这些配置写好后先验证一下控制端到被管节点的连通性ansible all -m ping如果返回每个节点都是pong说明环境没问题可以继续往下走了。3. 核心实操复制文件到所有节点并授权7773.1 先搞明白copy模块的工作方式批量分发文件用到的核心模块是copy。我第一次用这个模块时有个误区以为是“先上传文件再单独执行一条chmod命令改权限”。实际上copy模块支持在复制的同时设置文件属性一步到位。copy模块的核心参数有这几个src源文件路径对应控制端本地路径dest目标路径对应被管节点的绝对路径owner文件属主group文件属组mode文件权限位可以写成0777或777。这里有个细节要注意mode参数传的是字符串不是数字。用YAML写Playbook时写成mode: 0777或者mode: 0777都可以在Ad-Hoc命令行里则要写成mode0777。如果只写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 ownerroot grouproot mode0777这条命令的含义逐段拆开看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和源文件一致、权限也是0777Ansible会直接跳过返回ok而不会重新复制一遍。这种特性在批量运维中很实用——你不会因为重复执行而搞乱服务器状态。3.4 目录分发场景批量拷贝整个目录有时候要分发的不是一个文件而是一整个配置目录比如Nginx的conf.d或者某个项目的配置文件集。copy模块的src指向目录即可ansible web_servers -m copy -a src/opt/configs/ dest/etc/myapp/configs/ ownerroot grouproot mode0755注意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 FalsePermission denied (publickey,password)SSH免密未配置好或用户名不对检查ansible_user配置用ssh-copy-id重传公钥python: command not found目标机器没有python命令设置ansible_python_interpreter/usr/bin/python3sudo: no tty presentsudo需要密码或未允许免密sudo配置become时确认ansible_become_pass或目标机配置NOPASSWD sudoconnection timed out网络不通或防火墙拦截22端口用ansible host -m ping单独测连通性检查防火墙unsupported parameter for module: copyAnsible版本过旧/过新模块参数变化用ansible-doc copy查看当前版本支持的参数这些问题的排查思路大体一致先用简单命令定位范围是单台机器的问题还是所有机器的问题再逐步缩小。比如所有机器都报timeout那基本是控制端网络或防火墙的全局问题只有个别机器报Permission denied那就集中查那台机器的SSH配置和账号权限。4.2 文件权限777没生效的几种情况权限相关的问题看起来简单实际排查时隐藏点不少。我遇到过三种情况第一种mode参数被忽略。如果copy模块执行后返回ok而不是changed说明Ansible认为目标文件状态已经符合要求不会重新改权限。这时候去目标机器上看会发现权限确实还是原来的。原因往往是用户在前一次执行时写了mode0755后一次改成mode0777Ansible应该能检测到差异并更新但如果文件内容完全一致、只有权限差异有些特殊场景下state对比可能不准确。解决办法是加一个强制更新参数ansible web_servers -m copy -a src/tmp/deploy.sh dest/usr/local/bin/deploy.sh mode0777 forceyes第二种目标路径上已存在同名文件。如果目标文件已存在且内容与源文件不一致copy模块默认会覆盖force默认就是yes但如果你在配置里写了forceno那目标文件不会被替换权限自然也不会变。这时候要么删掉forceno要么先手动清理目标文件。第三种受父目录权限影响。设置了文件的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参数可以逐台确认第一次跑重要变更时建议加上等确认逻辑没问题了再全量跑。经验就是这么一次次试出来的。本文还有配套的精品资源点击获取
返回列表