跳到主要内容

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 常驻进程。

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、变量、模板、文件按约定目录打包复用
FactsAnsible 自动采集的节点信息(OS、IP、内存等),playbook 里可直接引用
Handler处理器,被 task「通知」后才执行,常用于「配置变了才重启服务」
Collection模块的发行包,ansible-core 只自带 ansible.builtin.*,其余按集合安装

其中 module / task / play / playbook 的包含关系是:

playbook ── 1..n ── play ── 1..n ── task ── 1 ── module
FQCN

写模块时建议用全限定名(FQCN),如 ansible.builtin.copy 而不是短名 copy,避免不同 collection 里的同名模块撞车。本系列文档一律使用 FQCN。

一次任务的执行流程​

以一句 ad-hoc 命令为例,看看 Ansible 在背后做了什么:

ansible web -m ansible.builtin.apt -a "name=nginx state=present" -b

执行过程:

  1. 选定目标:根据 inventory 解析 pattern web,得到这组的主机列表;-b 表示到对端用 sudo 提权。
  2. 生成临时脚本:控制节点把 ansible.builtin.apt 模块代码、参数、必要的工具函数打包成一个 Python 脚本。
  3. SSH 下发:通过 SSH 把脚本传到目标节点的临时目录(类似 ~/.ansible/tmp/...)。
  4. 远端执行:用目标节点的 Python 解释器运行脚本,脚本干活后输出一段 JSON(成功与否、是否改变、附加信息)。
  5. 收集结果:控制节点回收各节点返回的 JSON,汇总成你看到的 ok / changed / failed 输出。
  6. 清理现场:删除临时脚本,断开连接,节点上什么都不留。
排障思路

理解这条链路后,报错就好定位了:连不上是 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。