暗色模式

Ansible 自动化运维:从主机清单到 Playbook 批量配置

技术教程
2026-08-27
22
1
本文要点
  • ansible 是无需在目标机装代理的自动化工具,走 SSH 下发任务,用 YAML 描述"期望状态"
  • 主机清单 hosts.ini 把机器分成组,ansible -m ping 一条命令验证连通性
  • ad-hoc 命令用 -m 指定模块 + -a 传参数,适合快速查询和临时操作
  • Playbook 把多台主机的配置流程写成 YAML 剧本,天然幂等:重复执行结果一致
  • 常用模块涵盖包管理(apt)、服务(service)、文件(copy/template/file),组合起来就能完成完整的服务部署

为什么要用自动化运维

维护几台服务器时,SSH 上去敲命令还能应付。但机器一旦多起来,安装软件、改配置、启停服务这些重复动作就会越来越费时间,还会因为手滑导致两台机器配置不一致。自动化运维要解决的核心问题,就是把"用手敲"变成"用代码描述"——让同样的操作在任意数量的机器上稳定、可重复地执行。

本文用 Ansible 为例,从安装、主机清单、ad-hoc 临时命令到 Playbook 剧本,在一台真实的 Ubuntu 服务器上把一套 Nginx 服务从零部署起来,顺便验证它的幂等特性。

Ansible 是什么

Ansible 是一个无代理(agentless)的自动化工具:它不用在被管理机器上安装任何客户端,控制端通过 SSH 连接目标机,把要执行的模块下发过去运行,运行完就断开。这一点和远程执行脚本、Docker、盐堆等方案很不一样——你只要保证控制端能 SSH 到目标机即可。

它有三个关键设计:

  • 声明式:你描述目标状态("这台机器上要装 nginx"),而不是一步步写"先执行 apt-get,再检查返回值"。
  • 基于 YAML:任务清单直接就是给人看的文本,容易审核和版本管理。
  • 幂等:同一份配置反复执行,结果一致;已经满足的状态会被跳过,不会重复搞坏系统。

安装 Ansible

在 Ubuntu 控制端上用 apt 一句命令装好:

sudo apt-get install -y ansible

安装后确认核心组件可用:

ansible --version

它由几个命令组成,后面都会用到:

命令作用
ansible执行 ad-hoc 单条任务
ansible-playbook执行 Playbook 剧本
ansible-inventory查看主机清单
ansible-doc查阅模块文档(如 ansible-doc apt

主机清单:告诉 Ansible 管理哪些机器

Ansible 需要知道目标主机是谁、怎么连接,这份配置叫主机清单(Inventory),默认路径是 /etc/ansible/hosts,也可以启动时用 -i 指定。最简单的 INI 格式长这样:

# 主机清单 hosts.ini
[web_servers]
web01 ansible_host=192.168.1.10
web02 ansible_host=192.168.1.11

[db_servers]
db01 ansible_host=192.168.1.20

[local_host]
127.0.0.1 ansible_connection=local

方括号里是主机组名,组下面的行是组内主机。ansible_host 指定连接地址,ansible_connection=local 表示直接在本机执行(不用 SSH),方便我们在同一台机器上演示。实际生产环境通常默认使用 SSH 连接,不写 ansible_connection 即可。

写好清单后,用一条命令验证连通性:

cat /root/ansible-demo/hosts.ini && ansible -i /root/ansible-demo/hosts.ini local_host -m ping

主机清单与连通性测试

-i 指向清单文件,local_host 是要操作的组名,-m ping 指定模块。输出里 127.0.0.1 | SUCCESS 并且返回 "ping": "pong",说明清单配置正确、连接通畅。每个想到的目标主机会单独输出一行,多台机器时一眼就能看出哪些通、哪些挂。

ad-hoc 命令:一次性的快速操作

不需要写剧本、只想快速跑一条命令时,用 ansible 的 ad-hoc 模式。格式是 ansible <组名> -m <模块> -a "<参数>"。看两个例子:

ansible -i /root/ansible-demo/hosts.ini local_host -m command -a "hostname" -o && ansible -i /root/ansible-demo/hosts.ini local_host -m setup -a "filter=ansible_distribution,ansible_distribution_version,ansible_memtotal_mb" -o

ad-hoc 命令执行

第一段用 -m command 在目标机上执行 hostname,返回 127.0.0.1 | CHANGED | rc=0 | (stdout) 加主机名 democommand 模块直接调用远端 shell 执行命令,是最基础的"远程执行"。

第二段用 -m setup 收集目标机的系统信息(叫 facts),filter 参数限制只返回我们关心的字段。这里能看到一台 Ubuntu 24.04、内存 1886 MB 的主机。facts 在执行 Playbook 时会被自动收集并当作变量使用,后面模板小节会用到。

其他常用的 ad-hoc 例子:

# 安装软件包(apt 模块)
ansible -i hosts.ini local_host -m apt -a "name=cowsay state=present"

# 复制文件
ansible -i hosts.ini local_host -m copy -a "src=/root/ansible-demo/welcome.txt dest=/tmp/ansible-welcome.txt"

# 创建目录
ansible -i hosts.ini local_host -m file -a "path=/tmp/ansible-test-dir state=directory mode=0750"

state 参数是 Ansible 模块里最常见的设计:它声明"目标状态"。比如 aptstate=present 表示包要存在(没有就装),filestate=directory 表示目录要存在、state=absent 表示要删除。

Playbook:把流程写成剧本

ad-hoc 适合单条任务,要部署完整服务就得靠 Playbook。它是一个 YAML 文件,按顺序描述一组任务。下面是部署 Nginx 的完整示例:

---
- name: 部署 Nginx Web 服务器
  hosts: local_host
  gather_facts: yes
  become: true
  tasks:
    - name: 安装 nginx
      ansible.builtin.apt:
        name: nginx
        state: present

    - name: 写入自定义首页
      ansible.builtin.copy:
        content: "<h1>Hello from Ansible</h1>\n<h2>Hostname: {{ ansible_hostname }}</h2>\n"
        dest: /var/www/html/index.html

    - name: 用模板生成登录欢迎信息
      ansible.builtin.template:
        src: motd.j2
        dest: /etc/motd
        owner: root
        group: root
        mode: "0644"

    - name: 启动 nginx 并设置开机自启
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

    - name: 打印服务状态摘要
      ansible.builtin.command:
        cmd: systemctl is-active nginx
      register: nginx_status
      changed_when: false

    - name: 显示 nginx 进程状态
      ansible.builtin.debug:
        msg: "nginx current state: {{ nginx_status.stdout }}, hostname: {{ ansible_hostname }}"

结构拆解:

  • hosts——这组任务作用在哪个主机组上,这里是清单里的 local_host
  • become: true——以 root 权限执行(command 里那句 systemctl 需要)。
  • gather_facts: yes——执行前自动收集目标机信息,供模板和变量使用。
  • tasks——按顺序执行的任务列表,每个任务有名字和模块定义。
  • register——把某条命令的返回值存进变量,供后续任务引用。

运行这个剧本:

cd /root/ansible-demo && ANSIBLE_NOCOWS=1 ansible-playbook -i hosts.ini nginx-setup.yml

Playbook 部署 Nginx

输出里每个 TASK 一行,changed 表示本任务真正对系统产生了修改。首次运行时 安装 nginx写入自定义首页用模板生成登录欢迎信息 三个任务变成了 changed,说明它真的装了包、写了文件;而 启动 nginxok,因为服务已经处于运行状态。结尾的 PLAY RECAP 汇总了整轮结果:ok=7 changed=3 failed=0,代表部署成功、有 3 处实际改动、0 处失败。

部署完直接验证效果:

curl -s http://127.0.0.1/

返回的就是 Playbook 里写入的 <h1>Hello from Ansible</h1>,而 /etc/motd 也和模板里的内容一致,Nginx 服务真实可用。

再跑一次会发现什么

同一份 Playbook 立刻再执行一遍:

ANSIBLE_NOCOWS=1 ansible-playbook -i hosts.ini nginx-setup.yml

这次 PLAY RECAP 会变成 ok=7 changed=0——所有任务都已是期望状态,Ansible 判断"无需修改"全部跳过。这就是幂等:配置代码可以放心反复执行、可以被纳入 CI 定期核对,不会因为重复运行而出错。

模板与变量:配置随机器变化

直接写死配置适合固定内容,真实环境里往往需要"同一份模板、随机器不同渲染"的配置。template 模块基于 Jinja2 模板引擎,能读取收集到的 facts 并渲染。前面 Playbook 里的 motd.j2 模板:

===========================================
 欢迎访问 {{ ansible_hostname }}
 操作系统: {{ ansible_distribution }} {{ ansible_distribution_version }}
 内存大小: {{ ansible_memtotal_mb }} MB
 管理工具: Ansible
===========================================

执行后 /etc/motd 被渲染为:

 欢迎访问 demo
 操作系统: Ubuntu 24.04
 内存大小: 1886 MB

{{ ansible_hostname }}{{ ansible_distribution }} 这类双大括号语法就是变量占位。第一次运行时这些 facts 正是靠 gather_facts 收集的。用同样的思路,template 可以渲染 nginx 站点配置、systemd 单元文件、环境变量文件等,一套模板覆盖不同 IP、不同端口的机器。

常用模块速查

把零散需求映射到合适的模块,是写 Playbook 的基本功。这份速查覆盖了日常绝大部分场景:

模块用途典型参数
apt / yum / dnf安装、卸载软件包namestate=present/absent/latest
service / systemd启停服务、设置开机自启namestate=started/stoppedenabled
copy复制文件或将内容写入文件src/contentdestmodeowner
template用 Jinja2 模板渲染文件src(.j2)、destmode
file创建/删除目录、文件、链接pathstate=directory/file/absentmode
command / shell执行任意命令cmd(command)或直接命令串(shell)
user / group管理用户和组namestate=present/absent
lineinfile在配置文件中精确增改一行pathlineregexp
debug打印变量/调试信息msgvar
setup收集目标机 factsfilter

查询某个模块的完整参数,随时用 ansible-doc <模块名>

Playbook 设计建议

  1. 任务粒度要小:一个任务只做一件事,报错时定位准确,也能单独跳过。
  2. 坚持幂等:能用模块就用模块(aptservice),少用裸 commandcommand 记得配 changed_when,告诉 Ansible 什么情况下算"变了"。
  3. 把可变值提为变量:端口、路径、版本放 vars: 或单独变量文件,模板内容才有意义。
  4. 敏感信息用 vault:密码、密钥不要明文写进剧本,Ansible 的 ansible-vault 可加密整个文件。
  5. --check 预演ansible-playbook --check 进入 dry-run 模式,只看"会改动什么"而不真改,上线前必跑。

小结

从手动敲命令到声明式自动化,核心转变是用代码描述期望状态而非操作步骤。本文的完整链路是:

  • 用主机清单声明机器归属,ansible -m ping 验证连通;
  • 用 ad-hoc 命令做一次性查询和临时操作;
  • 把 Nginx 部署写成 Playbook,用 apt/copy/template/service 组合完成任务;
  • 靠幂等保证剧本可以反复执行、结果稳定。

当你需要把"装个 nginx、改个配置、起个服务"这类操作复制到十台、上百台机器时,这套方法就能把重复劳动变成一次提交。

相关阅读:Ansible 官方文档Ansible 常用模块索引Jinja2 模板引擎

发表评论

吃了么?
吃了么?
2026-08-27 10:45 #1
测试评论