首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
Ansible批量部署实战:从安装到Playbook完整指南
📅 2026/10/14 20:06:28
✍️ 爱科研究院
👁 阅读 3,247
不知道你有没有经历过这种场景一个运维需求下来要给五十台服务器装同一个服务、改同一份配置、重启同一个进程。手动一台台敲命令运气好两个小时搞定运气不好漏了一台排查起来更头大。我第一次被这种批量部署任务折磨到凌晨的时候就开始认真找自动化工具了。Ansible就是那时候走进我工作流的它不需要在被管机器上装客户端只要控制端装了Ansible、被管端能走SSH就能把命令和配置批量推过去。这篇文章不聊虚的直接从安装环境讲起把常用模块一个个拆开说清楚最后用一个完整案例串起来适合刚接触自动化、或者已经在用但想系统梳理一遍的运维朋友。1. 环境准备与安装控制端与被管端的第一次握手1.1 控制端安装Ansible的三种方式和版本选择Ansible是典型的控制端/被管端架构控制端装Ansible被管端只需要有Python和SSH服务这也是它区别于SaltStack、Puppet这类需要安装agent的方案最大的优势——被管端零侵入维护成本一下就降下来了。控制端的安装方式不同系统选不同路子。如果你是Red Hat系CentOS 7/8、Rocky、AlmaLinux最省事的是先装EPEL仓库再直接装yum install -y epel-release yum install -y ansible如果系统源里没有Ansible或者版本太老建议用pip安装。我后来为了版本可控基本都走pip了pip3 install ansible ansible --versionDebian系Ubuntu/Debian则直接apt update apt install -y ansible这里说一个很多人踩过的坑pip安装的版本和系统源安装的版本模块行为和参数差异不小。比如systemd模块在高版本里支持了更多参数而老的service模块在某些新系统上会报错。我的习惯是统一用pip装指定版本比如pip3 install ansible9.5.1装完之后确认版本ansible --version输出里可以看到ansible核心版本、python版本、配置文件路径这些信息后面排查问题会反复用到。比如我看到config file /etc/ansible/ansible.cfg就知道它加载了系统级配置如果显示None说明完全走默认配置。1.2 被管端前置条件用户、Python、SSH免密被管端不用装Ansible但有几个前置条件必须满足能通过SSH登录有Python解释器Python 2.6或Python 3当前用户有权限执行需要提权的操作。大多数企业环境里直接拿root跑Ansible不现实安全上过不去。我一般会创建一个专用账号# 在被管端执行一次 useradd ops echo your_password | passwd --stdin ops echo ops ALL(ALL) NOPASSWD: ALL /etc/sudoers.d/ops chmod 440 /etc/sudoers.d/opsNOPASSWD的意思是sudo时不用再输密码Ansible执行提权操作时就不会卡在密码交互上。然后是SSH免密。控制端生成密钥对ssh-keygen -t rsa -b 4096把公钥分发到被管端单台用ssh-copy-idssh-copy-id -i ~/.ssh/id_rsa.pub ops192.168.1.10批量分发公钥就手写一个小循环别一台台来for ip in 192.168.1.{10..19}; do sshpass -p your_password ssh-copy-id -o StrictHostKeyCheckingno ops$ip donesshpass在CentOS里装一下就行yum install -y sshpass。这个方法只适合内网环境公网服务器不建议这么干。分发完随便挑一台验证ssh ops192.168.1.10 echo ok通了再继续不通优先检查端口和防火墙。1.3 验证连通性ansible all -m ping环境准备完跑一下Ansible的hello worldansible all -m ping -u ops这里-m指定模块ping模块不是让你去ping IP而是检测被管端是否能正常执行Python脚本并返回响应。如果配置了清单但还没建默认的all/ungrouped会去读/etc/ansible/hosts里面可能啥都没有就会连不上。所以正常操作是先配好inventory再跑这个命令。2. 核心配置inventory主机清单与ansible.cfg2.1 inventory的写法分组、变量、嵌套子组inventory就是Ansible的主机清单定义了管理哪些机器、怎么连、用什么账号。默认路径是/etc/ansible/hosts我习惯在项目目录里建一个hosts文件配合ansible.cfg的inventory参数使用这样不同项目用不同清单互不干扰。最简单的写法[web] 192.168.1.10 192.168.1.11 192.168.1.12 [db] 192.168.1.20 ansible_ssh_port2222 [all:vars] ansible_userops ansible_becomeyes ansible_become_methodsudo[web]和[db]是分组名[all:vars]是定义全局变量作用于所有主机。ansible_ssh_port2222是为db组的机器单独指定SSH端口实际场景里总有几个机器端口不一样这种每主机变量写法很实用。嵌套子组用:children[prod:children] web db [prod:vars] envproduction这样prod组包含web和db所有机器一个playbook可以按组选择性执行也可以整个运维域统一操作。通配符也是支持的[web] 192.168.1.10:20这种写法等同于192.168.1.10到192.168.1.20适合网段连续的场景。2.2 ansible.cfg关键配置项逐一解读ansible.cfg是控制端的核心配置文件默认优先级是当前目录的ansible.cfg 用户家目录的~/.ansible.cfg /etc/ansible/ansible.cfg。想确认当前生效的是哪个用ansible --version我给一套常用配置直接在项目目录下建ansible.cfg[defaults] inventory hosts remote_user ops host_key_checking False forks 20 log_path /var/log/ansible.log timeout 10 private_key_file /home/ops/.ssh/id_rsa每个参数说一下用途inventory指定hosts文件路径写相对路径就是当前项目目录。remote_userSSH登录用户统一指定免去每条命令都加-u。host_key_checking第一次SSH时会提示确认指纹交互式确认在脚本里就是灾难改成False直接跳过。forks并行执行的进程数默认5内网机器多的时候调大能显著提速但别一下拉到50控制端CPU和网络带宽都容易扛不住。timeoutSSH连接超时单位秒网络不稳定的环境调大一点。private_key_file指定私钥文件路径多账号环境很实用。还有一个我在跑生产任务时比较依赖的选项[ssh_connection] pipelining True开启SSH pipelining可以减少SSH连接次数大批量执行时性能提升非常明显。但注意如果sudoers里配置了requiretty这个会失效需要确保NOPASSWD配置里没有这限制。2.3 配置优先级命令行 环境变量 配置文件Ansible的配置优先级很直接命令行参数最高其次是环境变量ANSIBLE_开头最后才是ansible.cfg。比如你在ansible.cfg里写了remote_userops但执行命令时加了-u root以命令行为准。这个特性用好了它就是个逃生通道。比如某个紧急任务必须用root跑但项目默认配置是ops用户直接命令行加-u root覆盖即可不用改配置也不用记完再改回来。3. 常用模块逐个拆解从ping到template模块是Ansible操作被管端的手理解了模块Ansible就算入门一半。3.1 连通性测试与命令执行类ping、command、shell、rawping模块不是ICMP ping而是验证被管端Python环境可用性返回pong才算通。用它做完连通性测试后再执行具体命令。command模块是执行命令的基础模块但它不走shell解释器不支持管道、通配符、重定向这些特性。比如ansible all -m command -a cat /etc/hostname能用但如果写ansible all -m command -a ps aux | grep nginx就会报错因为管道符交给command模块直接被当作普通字符处理了。这种场景用shell模块ansible all -m shell -a ps aux | grep nginx | wc -lshell模块通过/bin/sh执行支持管道、通配符等shell特性。既然shell更强大是不是都用shell就行不行。command模块更安全不会出现复杂的shell转义问题能不用管道解决的尽量用command这是经验之谈。raw模块更底层直接通过SSH执行原始命令不经过Python解释器。什么时候用被管端连Python都没有的时候。比如新装的精简系统啥都没有先用raw把Python装上ansible all -m raw -a yum install -y python3三个模块对比用表格更清楚模块是否走shell是否需要Python适用场景command否是简单命令无特殊字符shell是是复杂命令管道、通配符raw否否无Python或Python版本过低的机器3.2 文件分发与管理类copy、file、fetchcopy模块用于把控制端的文件分发到被管端是批量部署里用得最多的模块之一。- name: 分发nginx配置文件 copy: src: ./conf/nginx.conf dest: /etc/nginx/nginx.conf owner: root group: root mode: 0644 backup: yesbackup: yes的作用是目标文件已存在时先备份再覆盖备份名带时间戳。首次上线可以去掉但线上更新配置建议开启出了问题能快速回滚。owner、group、mode不写的话权限会保持源文件的属性有时候源文件权限不对会导致服务起不来所以显式写清楚最稳妥。file模块管理文件属性、创建目录、删除文件、创建软链接。它不做内容分发只管理类型和属性。- name: 创建应用目录 file: path: /data/app/logs state: directory owner: ops group: ops mode: 0755 recurse: yesstate参数区别很大statedirectory创建目录statetouch创建空文件statelink创建软链接stateabsent删除文件或目录。recurseyes对目录和子目录一起修改属性。fetch模块是从被管端拉文件到控制端和copy正好相反。批量收集日志或配置文件时特别好用ansible web -m fetch -a src/var/log/nginx/access.log dest./logs/ flatyesflatyes表示直接拉到一个目录下不加的话它会按主机名建子目录。3.3 包管理与服务管理类yum、apt、service、systemd批量装软件是Ansible的拿手戏。Red Hat系用yum模块- name: 安装基础软件 yum: name: - vim - net-tools - nginx state: presentstatepresent表示确保安装已装则跳过statelatest表示装最新版本并更新stateabsent表示卸载。Debian系对应apt模块用法一样。服务管理有两个模块要分清。老的service模块兼容性好但新系统上推荐用systemd模块- name: 启动nginx并设置开机自启 systemd: name: nginx state: started enabled: yesstate可以取值started、stopped、restarted、reloaded。enabledyes表示开机自启。注意用的systemd模块时如果服务刚装还没daemon-reload需要先触发一下否则可能报Unit not found。稳妥写法是- name: 重新加载systemd配置 systemd: daemon_reload: yes3.4 用户、定时任务与模板类user、cron、template、debug、scriptuser模块管理用户和用户组- name: 创建部署用户 user: name: deploy uid: 2001 group: deploy groups: wheel shell: /bin/bash password: {{ password_hash }} create_home: yes append: yespassword需要传加密后的哈希值不能用明文。用python生成哈希python3 -c import crypt; print(crypt.crypt(your_password, crypt.mksalt(crypt.METHOD_SHA512)))cron模块管理定时任务- name: 每天凌晨2点清理临时文件 cron: name: clean temp files minute: 0 hour: 2 job: find /tmp -type f -mtime 7 -exec rm -f {} \\; user: root state: presenttemplate模块是Ansible的核心武器。它基于Jinja2模板渲染文件模板里可以引用变量实现一份模板不同配置的效果- name: 生成应用配置 template: src: app.conf.j2 dest: /etc/app/app.conf模板文件app.conf.j2里写server_name{{ domain_name }}; worker_processes{{ ansible_processor_cores }};这里的ansible_processor_cores是Ansible自动采集的系统信息这个特性叫Facts采集非常强大。debug模块用来打印变量和调试信息- debug: msg: 当前部署主机: {{ inventory_hostname }}script模块把本地脚本复制到被管端执行适合还没改写成playbook的存量脚本ansible all -m script -a /opt/scripts/init_env.sh相当于一个不需要参数的分发执行组合。3.5 幂等性与模块返回值判断聊Ansible模块绕不开幂等性。一个操作执行一次和执行一百次结果应该是一样的这才叫幂等。command和shell天然不幂等比如- name: 添加用户 command: useradd testuser第一次执行成功第二次就报错用户已存在。用user模块就不会- name: 添加用户 user: name: testuser state: present执行几次都是成功因为user模块会判断用户是否存在存在就跳过。选模块时优先用声明式的、自带幂等性的模块尽量避免用command/shell硬写逻辑。模块执行完会返回结果关键字段有changed是否发生了变更、rc返回码、stdout/stderr输出内容。调试时常用- name: 执行检查命令 command: /usr/local/bin/check.sh register: result - debug: var: result.stdoutregister把命令结果存到变量后面可以用when条件判断- name: 检查失败时输出错误 debug: msg: 脚本执行异常 when: result.rc ! 04. 批量部署完整实战从零部署一套Nginx集群4.1 需求场景梳理场景来自一个朋友的模拟项目某公司运维域新划了4台CentOS 7.9服务器192.168.1.31~34要统一部署Nginx作为前端入口要求包括安装nginx并配置开机自启替换默认首页内容显示每台服务器的主机名开放防火墙80端口关闭SELinux避免nginx访问文件受限最后验证所有机器的HTTP访问正常这个需求如果手动做四台机器至少半小时用Ansible一个playbook几分钟搞定而且能保证四台机器配置完全一致。4.2 Playbook编写与逐段解释项目目录结构. ├── ansible.cfg ├── hosts ├── deploy_nginx.yml └── templates └── index.html.j2hosts文件[nginx] 192.168.1.31 192.168.1.32 192.168.1.33 192.168.1.34 [nginx:vars] ansible_userops ansible_becomeyes ansible_ssh_private_key_file/home/ops/.ssh/id_rsadeploy_nginx.yml--- - name: 批量部署Nginx集群 hosts: nginx gather_facts: yes tasks: - name: 关闭SELinux selinux: state: disabled when: ansible_selinux.status enabled - name: 安装nginx yum: name: nginx state: present - name: 生成自定义首页 template: src: templates/index.html.j2 dest: /usr/share/nginx/html/index.html mode: 0644 - name: 启动nginx并设置开机自启 systemd: name: nginx state: started enabled: yes - name: 开放防火墙80端口 firewalld: service: http permanent: yes state: enabled immediate: yesindex.html.j2模板html headtitleNode {{ inventory_hostname }}/title/head body h1Welcome to {{ inventory_hostname }}/h1 pOS: {{ ansible_distribution }} {{ ansible_distribution_version }}/p /body /html这个模板用了两个变量inventory_hostname是清单里定义的IPansible_distribution是Facts采集的系统信息。跑完每台机器的首页都能看到各自信息验证部署成功就有了明确依据。4.3 执行与结果验证先做语法检查ansible-playbook -i hosts deploy_nginx.yml --syntax-check没问题就执行ansible-playbook -i hosts deploy_nginx.yml第一次执行会看到每台主机的task状态安装nginx会执行状态为changed启动服务后再次执行所有task都是ok没有changed这就是幂等性的直观体现。执行几次结果都一样这才是可靠的基础设施管理。验证环节控制端批量检查HTTP返回for ip in 192.168.1.31 192.168.1.32 192.168.1.33 192.168.1.34; do echo $ip curl -s http://$ip/ | grep -o Node [0-9.]* done四台机器返回各自的Node信息部署完成。5. 常见问题与排查技巧实录5.1 免密登录和SSH连接问题Ansible批量执行最常挂在SSH这一环。几种典型报错和处理办法报错Permission denied (publickey,gssapi-keyexch,password)原因基本是免密没配好。先手动ssh过去试试确认能免密登录。如果控制端用root操作但被管端只有ops用户检查~/.ssh/authorized_keys的权限和属主。authorized_keys这个文件要求属主是当前用户权限通常600目录权限700。还有一种情况用户配了sudo但NOPASSWD没生效导致提权时还是要密码。细心检查一下sudoers语法建议用visudo -c做语法校验。报错ssh_exchange_identification: Connection closed by remote host常见于被管端SSH连接数超限。检查被管端/etc/ssh/sshd_config可以临时调大MaxSessions但治本的办法是控制端降低forks并发数。报错Host key verification failed就是前面说的host_key_checking问题。临时可用ssh-keyscan批量导入known_hosts更推荐在ansible.cfg里设置host_key_checking False。有人担心安全问题内网环境可接受公网环境建议用ssh-keyscan固定指纹。5.2 模块报错与Python版本问题最经典的报错是ModuleNotFoundError: No module named ansible.module_utils这种基本是控制端Ansible版本与被管端Python版本不匹配导致的。Ansible 2.10分成了collection结构如果被管端Python是2.7有些新模块会不兼容。稳妥做法是确保被管端装了Python3ansible all -m raw -a yum install -y python3对于模块本身参数不认识的报错比如Unsupported parameters for (systemd) module: daemon_reload大概率是本机Ansible版本太老去控制端升级Ansible版本再跑。5.3 提权相关的坑用普通用户执行playbooktask里需要root权限时忘了加become相关配置就会出现FAILED! {msg: Missing sudo password}解决ansible.cfg里配ansible_becomeyes或者playbook/命令行加--become。如果sudo还要求密码命令行追加--ask-become-pass会交互式输入密码明文密码不落盘。还有一种情况是sudoers配置了requirettysudo: sorry, you must have a tty to run sudo在sudoers里注释掉Defaults requiretty这一行或者确认NOPASSWD配置时避开这限制。5.4 执行结果异常排查报错rc1但stdout没有明显错误先用shell模块手动跑一遍原始命令看完整输出。很多时候是环境变量问题。非交互式SSH登录不会加载.bashrc里的环境变量比如PATH里没有/usr/local/bin导致命令找不到。解决命令里写绝对路径或在playbook里用environment参数补环境变量- name: 执行应用命令 shell: /usr/local/bin/app_ctl restart environment: PATH: /usr/local/bin:/usr/bin:/bin报错template渲染缺失变量模板里引用了变量但没定义报错类似AnsibleUndefinedVariable: xxx is undefined排查用debug把当前变量打出来- debug: var: hostvars[inventory_hostname]如果只想看部分字段- debug: var: ansible_distribution5.5 批量执行速度慢的优化机器一多就觉得ansible执行慢主要是SSH握手开销。几个优化方向forks从默认5调大到20或30控制端CPU允许的前提下开启pipelining关闭不必要的Facts采集playbook里gather_facts: false用不到系统信息就别采用--limit分批执行比如 --limit nginx 只跑nginx组跑一个50台服务器的playbook没有pipelining时可能要十几分钟开完之后能压到几分钟效果非常明显。6. 效率提升技巧与模块文档速查6.1 模块用法记不住怎么办Ansible模块几百个没人能全记住。两个命令帮忙ansible-doc -l # 列出所有模块 ansible-doc yum # 查看yum模块详细用法ansible-doc输出的内容包含参数说明、示例、返回值比翻网页快得多。我写playbook时基本是ansible-doc和官方文档配合用很少背参数。6.2 语法检查与干跑模式每写完一个playbook养成习惯先检查语法ansible-playbook deploy.yml --syntax-check更保险的是干跑模式ansible-playbook deploy.yml -C-C是check模式只判断需要变更什么不实际执行变更。新环境第一次部署前我习惯先-C跑一遍看哪些task会动、哪些会跳过确认预期再真正执行。6.3 敏感信息处理ansible-vaultplaybook涉及密码、密钥时别明文写在文件里。用ansible-vault加密ansible-vault create secrets.yml ansible-vault edit secrets.yml ansible-vault encrypt secrets.ymlplaybook里引用加密变量文件时- hosts: all vars_files: - secrets.yml执行时加--ask-vault-passansible-playbook deploy.yml --ask-vault-pass敏感变量不落盘、不进版本库这个习惯建议从一开始就养成。6.4 tags的妙用playbook写大了每次全量执行既慢又有风险。tags可以按标签选择性执行- name: 安装软件 yum: name: nginx tags: nginx_install - name: 修改配置 template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf tags: nginx_conf执行时只跑指定标签ansible-playbook deploy.yml --tags nginx_conf改配置的task和装软件的task分开打标日常更新只跑配置相关不动安装环节。还有一个skill--start-at-task task名可以从指定task开始执行失败重跑时不用从头再来。6.5 用roles把任务串起来任务多了之后我建议整理成roles结构把软件安装、配置管理、服务启停拆成独立role。roles目录结构roles/ ├── nginx/ │ ├── tasks/ │ │ ├── main.yml │ │ ├── install.yml │ │ ├── config.yml │ │ └── service.yml │ ├── templates/ │ └── vars/ │ └── main.ymlplaybook变成这样- hosts: nginx roles: - nginx逻辑更清晰也方便复用。同一套role换个变量就能部署到另一套环境这个收益随着机器规模增长会越来越大。7. 写在最后的实战体会Ansible这个工具入门是真的容易装个包、配免密、写几个模块就能跑起来。但要把批量部署这件事做得稳、做得安全、做得可维护还是有一些细节值得慢慢打磨。我自己跑了这几年批量部署最大的体会是先想清楚要什么状态再动手写playbook。很多新手一上来就写命令结果脚本跑了一堆操作却没法保证每台机器最终状态一致这不是自动化只是把手工敲命令变成了脚本批量敲命令。真正的自动化是声明式的——把期望状态写清楚剩下的交给Ansible去判断和执行。所以日常建议大家能用模块解决的不用command/shell能通配的配置用template加变量敏感信息一律vault加密每次上线先-C干跑一遍。这些习惯叠加在一起批量部署才真正从能用变成可靠。这篇文章覆盖了安装、配置、模块、实战和排障基本上是我这几年操作积攒的核心内容希望对你有用。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/14 20:06:28
理解osgDB核心机制:从readNodeFile到场景图加载链路
2026/10/14 20:06:28
Dart异步编程从事件循环到Future:彻底搞懂队列、await与错误处理
2026/10/14 20:01:26
AI配音怎么导出音频?文字转语音保存与剪辑方法
2026/10/14 21:21:58
App 邮箱验证码注册与登录机制说明
2026/10/14 21:21:58
帮手如何用一句话配置消防任务
2026/10/14 21:21:58
二、C++系列之引用
2026/10/14 21:21:58
出海 B2B 销售情报落地:从信号到行动的三层工作流
2026/10/14 21:21:58
ThinkPHP6+Layui后台管理框架实践:RBAC权限设计与快速开发
2026/10/14 21:16:58
C++类和对象(下)初始化列表、类型转换、static、友元、内部类、匿名对象
2026/10/14 0:02:01
Oracle 19c Windows客户端安装配置与连接排错指南
2026/10/14 0:02:01
React Native截图优化:解决Android兼容性问题
2026/10/14 0:02:01
金属锈蚀速率计算模型与防护方案优化实践
2026/10/13 12:25:09
流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南
2026/10/14 18:35:19
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别
2026/10/14 14:52:59
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容
2026/10/12 19:53:23
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/11 21:41:11
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/11 23:43:10
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)