Ansible 核心概念与架构
为什么需要 Ansible
管理一台服务器很轻松:ssh 上去,装包、改配置、起服务,完事。但机器变成几十台之后,事情就变味了:
- 重复劳动:同样的操作要在每台机器上做一遍,做到第 30 遍时难免手抖敲错。
- 状态漂移:每台机器都是手工改的,改着改着配置就不一致了,谁也说不清某台机器现在到底是什么状态。
- 没法审计:谁、什么时候、改了什么,全靠回忆,出问题查无可查。
有人会说:写个 shell 脚本,for 循环挨个 ssh 不就行了?
for host in web1 web2 web3; do
ssh "$host" "apt-get update && apt-get install -y nginx"
done
这种方式能救急,但规模稍大就会撞墙:
| 痛点 | 具体表现 |
|---|---|
| 没有幂等 | 脚本跑第二遍会怎样?apt 重复装还好,往配置文件里追加内容就会越追越多 |
| 没有状态感知 | 每台机器成功还是失败,输出混在一起,得自己逐台翻 |
| 没有并发控制 | for 循环是串行的,几十台机器要等很久;想并发又得自己管后台任务 |
| 没有抽象 | 「确保 nginx 已安装且服务在跑」要写一堆判断命令,脚本越来越长、越来越脆 |
Ansible 就是为这类问题而生的:用 YAML 描述「目标状态」,由它负责把一批机器收敛到那个状态。你只需要写「web 组所有机器装好 nginx 并启动」,至于每台机器当前装了没装、服务起没起,交给 Ansible 去判断。
Ansible 是一个「批量把机器变成你想要的样子」的工具:你写期望状态(YAML),它通过 SSH 把机器变成那个状态,变了才报告 changed,没变就是 ok。
无 Agent 架构
Ansible 和大多数配置管理工具最大的不同是:受管节点上不需要安装任何 Agent 常驻进程。

整体是 Push(推送)模式:
- 控制节点(Control Node):你手边装了 Ansible 的那台机器(macOS 或 Linux),所有命令从这里发出。
- 受管节点(Managed Node):被管理的服务器,只需要满足两个条件——能 SSH 连上、装了 Python。
- 通信通道:管理 Linux/Unix 节点默认走 SSH,Windows 节点走 WinRM。不需要额外开端口、装服务。
执行时 Ansible 会把模块(本质上是一段 Python 脚本)临时拷贝到受管节点的临时目录里运行,跑完立刻清理,节点侧零残留——不装 agent、不开监听端口、不留后台进程。
这个设计带来的实际好处:
- 接入成本低:一台新机器只要能 ssh 上去,立刻就能被管理,不用先装一堆东西。
- 攻击面小:节点上没有常驻 agent,少一个要维护、要担心漏洞的组件。
- 版本一致:逻辑都在控制节点,升级 Ansible 只升控制端,不会出现「各节点 agent 版本不齐」的问题。
Push 模式也有代价:执行任务时控制节点要同时维持大量 SSH 连接,机器多了靠 forks 参数提高并发(默认 5,常用 20~50)。Ansible 也提供 Pull 模式(ansible-pull),适合节点动态上线的场景,日常用得少。
核心概念地图
先把后面会反复出现的名词一次过一遍,有个印象就行,用到再回来查:
| 概念 | 一句话说明 |
|---|---|
| Control Node | 控制节点,装了 Ansible、发起任务的机器 |
| Managed Node | 受管节点,被管理的目标主机,也叫 host |
| Inventory | 主机清单,列出管哪些机器、怎么分组,INI 或 YAML 格式 |
| Module | 模块,干活的最小单元(装包、拷文件、管服务),每个任务调用一个模块 |
| Task | 任务,「对一组机器调用一次模块」,playbook 里的一个步骤 |
| Play | 把「哪些主机」和「一串 task」绑定在一起的单元 |
| Playbook | 剧本文件,YAML 格式,由一个或多个 play 组成,是日常维护的主要对象 |
| Role | 角色,把一套相关的 task、变量、模板、文件按约定目录打包复用 |
| Facts | Ansible 自动采集的节点信息(OS、IP、内存等),playbook 里可直接引用 |
| Handler | 处理器,被 task「通知」后才执行,常用于「配置变了才重启服务」 |
| Collection | 模块的发行包,ansible-core 只自带 ansible.builtin.*,其余按集合安装 |
其中 module / task / play / playbook 的包含关系是:
playbook ── 1..n ── play ── 1..n ── task ── 1 ── module
写模块时建议用全限定名(FQCN),如 ansible.builtin.copy 而不是短名 copy,避免不同 collection 里的同名模块撞车。本系列文档一律使用 FQCN。
一次任务的执行流程
以一句 ad-hoc 命令为例,看看 Ansible 在背后做了什么:
ansible web -m ansible.builtin.apt -a "name=nginx state=present" -b
执行过程:
- 选定目标:根据 inventory 解析 pattern
web,得到这组的主机列表;-b表示到对端用 sudo 提权。 - 生成临时脚本:控制节点把
ansible.builtin.apt模块代码、参数、必要的工具函数打包成一个 Python 脚本。 - SSH 下发:通过 SSH 把脚本传到目标节点的临时目录(类似
~/.ansible/tmp/...)。 - 远端执行:用目标节点的 Python 解释器运行脚本,脚本干活后输出一段 JSON(成功与否、是否改变、附加信息)。
- 收集结果:控制节点回收各节点返回的 JSON,汇总成你看到的
ok / changed / failed输出。 - 清理现场:删除临时脚本,断开连接,节点上什么都不留。
理解这条链路后,报错就好定位了:连不上是 SSH 层的问题(网络、密钥、指纹);MODULE FAILURE 多半是目标节点缺 Python 或模块自身执行报错;结果不符合预期则是模块参数或目标状态的问题。命令加 -vvv 可以看到每一步的 SSH 细节。
幂等性
幂等(Idempotent):同一个操作执行一次和执行一百次,最终状态一样。
这是配置管理的根基。它意味着 playbook 可以放心地反复执行——Ansible 每次都会先检查目标状态,「已经是那个样子」就跳过(ok),「还不是」才动手(changed)。日常巡检、定时跑一遍 playbook 做合规收敛,靠的就是幂等。
大多数内置模块天然幂等:
| 模块 | 幂等的表现 |
|---|---|
ansible.builtin.apt / ansible.builtin.dnf | 包已装且版本符合就跳过 |
ansible.builtin.copy | 文件内容一致(校验哈希)就不再拷贝 |
ansible.builtin.service | 服务已在目标状态就不动 |
ansible.builtin.user / ansible.builtin.group | 用户/组的属性一致就跳过 |
ansible.builtin.file | 属主、权限、链接目标一致就跳过 |
要小心的两个:ansible.builtin.command 和 ansible.builtin.shell。它们只是原样执行命令,不知道这条命令会改变什么,所以每次都报告 changed。万不得已要用时,可以加 creates: / removes: 参数告诉它「某文件已存在就跳过」,勉强补上幂等性。
能用专用模块就别用 shell。装包用 apt/dnf,改配置用 template/copy/lineinfile,管服务用 service——这些模块会做状态判断,写出来的 playbook 才能放心反复跑。
与同类工具的边界
| 工具 | 定位 | 与 Ansible 的关系 |
|---|---|---|
| Shell 脚本 | 单机/小规模自动化 | Ansible 相当于「可幂等、可并发、有状态汇总」的加强版批量 ssh;简单的一次性任务脚本仍然够用 |
| Terraform / Pulumi | 资源编排:创建云主机、VPC、数据库这些「资源」 | 互补。Terraform 把机器开出来,Ansible 进去装软件、改配置。一个管「有没有这台机器」,一个管「机器里长什么样」 |
| SaltStack | 配置管理,agent 常驻 + 拉模式,基于消息总线,并发性能强 | 同赛道竞品。Salt 要在节点装 minion、维护 master;Ansible 无 agent 接入更简单,但大规模并发下 SSH 开销更高 |
| Puppet / Chef | 老牌配置管理,agent + master 架构,声明式 DSL | 理念相同,架构更重;新项目现在一般优先考虑 Ansible |
机器已经在那里、要把它们管起来 → Ansible;机器还不存在、要先把云资源开出来 → Terraform / Pulumi;两者经常搭配使用。
小结
- Ansible 解决的是批量配置管理:用 YAML 描述目标状态,批量收敛机器。
- 无 Agent、Push 模式:控制节点通过 SSH 把临时 Python 模块推到受管节点执行,跑完即清理,节点侧零残留。
- 核心概念记住一条链:inventory 选机器 → playbook 里的 play/task → 调用 module 干活;facts 提供节点信息,handler 做变更联动,role 做复用打包。
- 幂等性是 playbook 能反复执行的前提,优先用专用模块,少用 command/shell。
- 和 Terraform 这类资源编排工具是互补关系,不是替代关系。
概念有了,下一篇《安装与快速上手》就从装 Ansible 开始,跑通第一条 ping 命令和第一个 playbook。