一、Ansible Playbook 核心基础
Playbook 是 Ansible 的自动化脚本文件,基于 YAML 格式,用于批量执行任务。其核心价值是将 "零散命令" 组织成 "可复用、可维护的自动化流程"。
1. Playbook 核心结构
一个完整的 Playbook 由多个Play
组成,每个Play
包含以下关键部分:
组成部分 | 作用说明 |
---|---|
Tasks | 核心执行单元,每个任务调用一个 Ansible 模块(如ping 、yum ),按顺序执行 |
Variables | 存储动态数据,让 Playbook 更灵活(如定义软件名、端口号) |
Templates | 基于 Jinja2 模板生成动态配置文件(如 Apache 的httpd.conf ) |
Handlers | 响应任务变更的 "触发器"(如配置文件修改后重启服务),仅在任务状态为changed 时执行 |
Roles | 将任务、变量、模板等按功能拆分,实现模块化复用(如 "Web 服务角色""数据库角色") |
2. 基础 Playbook 示例(含核心语法)
--- # YAML文件标识(可省略)
- name: 部署Web服务 # Play名称(便于识别,可省略)
hosts: webservers # 目标主机组(来自/etc/ansible/hosts)
remote_user: root # 远程执行用户
gather_facts: false # 关闭facts信息收集(加快执行速度,可省略)
tasks: # 任务列表
# 任务1:测试主机连通性
- name: 测试Ping连通性
ping: # 调用ping模块(无参数)
# 任务2:关闭防火墙(忽略执行错误)
- name: 停止firewalld服务
service: name=firewalld state=stopped # 模块参数用key=value格式
ignore_errors: True # 忽略任务执行失败(如服务已停止)
# 任务3:安装Apache(修改配置后触发Handler)
- name: 安装httpd
yum: name=httpd state=latest
- name: 推送httpd配置文件
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: "重启httpd" # 配置变更时触发同名Handler
# 任务4:启动Apache并设为开机自启
- name: 启动httpd服务
service: name=httpd state=started enabled=true
handlers: # 触发器列表(仅被notify调用)
- name: 重启httpd # 名称必须与notify完全一致
service: name=httpd state=restarted
二、Playbook 关键功能与实操
1. 变量使用(灵活传递数据)
变量可通过 "Play 内定义" 或 "命令行传递",引用时用{``{ 变量名 }}
。
-
方式 1:在 Play 内定义变量
- name: 用变量创建用户和组 hosts: dbservers vars: # 定义变量 groupname: mysql username: nginx tasks: - name: 创建mysql组 group: name={{ groupname }} gid=306 - name: 创建nginx用户 user: name={{ username }} group={{ groupname }}
-
方式 2:命令行传递变量(优先级更高)
ansible-playbook test.yaml -e "username=testuser" # -e参数指定变量
2. 条件判断(when 指令)
通过when
指定 "任务执行的条件",条件为true
时才执行任务,变量无需加{``{ }}
。
- name: 仅特定IP主机执行关机
hosts: all
tasks:
- name: 重启主机
command: /sbin/shutdown -r now
when: ansible_default_ipv4.address == "192.168.10.14" # 条件:IP匹配
3. 迭代(循环执行任务)
通过loop
(推荐)或with_items
实现 "重复执行同一任务",支持列表、字典格式。
- name: 循环创建目录和用户
hosts: dbservers
tasks:
# 1. 循环创建目录(列表格式)
- name: 创建/tmp/test1、/tmp/test2
file: path={{ item }} state=directory
loop: # 等同于with_items
- /tmp/test1
- /tmp/test2
# 2. 循环创建用户(字典格式)
- name: 创建test1、test2用户并指定组
user: name={{ item.name }} groups={{ item.groups }}
loop:
- { name: "test1", groups: "wheel" }
- { name: "test2", groups: "root" }
4. Templates 模块(动态生成配置)
基于 Jinja2 模板(后缀.j2
)生成配置文件,支持嵌入变量。
-
步骤 1:创建 Jinja2 模板(/opt/httpd.conf.j2)
Listen {{ http_port }} # 嵌入变量 ServerName {{ server_name }} DocumentRoot "{{ root_dir }}"
-
步骤 2:在 Playbook 中使用 Templates 模块
- name: 动态生成httpd配置 hosts: webservers tasks: - name: 推送模板并生成配置 template: src=/opt/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf notify: 重启httpd # 配置变更时触发重启
-
步骤 3:在主机清单中定义变量(/etc/ansible/hosts)
[webservers] 192.168.10.14 http_port=80 server_name=www.test.com root_dir=/var/www/html
5. Tags 模块(指定执行特定任务)
给任务打 "标签",执行 Playbook 时通过--tags
只运行指定标签的任务,特殊标签always
表示 "始终执行"。
- name: 带标签的任务示例
hosts: webservers
tasks:
- name: 复制hosts文件
copy: src=/etc/hosts dest=/opt/hosts
tags: only # 标签:only
- name: 创建测试文件
file: path=/opt/test.txt state=touch
tags: always # 标签:始终执行
-
执行命令 :
ansible-playbook test.yaml --tags="only" # 仅执行标签为only的任务(always任务也会执行)
三、Roles 模块(模块化管理)
Roles 是 Playbook 的 "模块化方案",将任务、变量、模板等按 "功能" 拆分(如 Web 角色、数据库角色),便于复用和维护。
1. Roles 目录结构(固定格式)
每个角色需按以下目录存放,未用到的目录可省略:
/etc/ansible/roles/ # 默认Roles目录
├── httpd/ # Web服务角色
│ ├── files/ # 存储copy/script模块用到的静态文件
│ ├── templates/ # 存储Jinja2模板文件
│ ├── tasks/ # 任务列表(必须有main.yml)
│ ├── handlers/ # 触发器(必须有main.yml)
│ ├── vars/ # 角色变量(必须有main.yml)
│ ├── defaults/ # 默认变量(优先级最低,必须有main.yml)
│ └── meta/ # 角色依赖、作者等信息(必须有main.yml)
└── mysql/ # 数据库服务角色(结构同上)
2. Roles 实操步骤(以部署 LAMP 为例)
步骤 1:创建 Roles 目录结构
# 创建httpd、mysql、php角色目录
mkdir -p /etc/ansible/roles/{httpd,mysql,php}/{files,templates,tasks,handlers,vars,defaults,meta}
# 创建各角色的main.yml文件(固定文件名)
touch /etc/ansible/roles/{httpd,mysql,php}/{tasks,vars,handlers,defaults,meta}/main.yml
步骤 2:编写各角色的任务与变量
-
httpd 角色(安装并启动 Apache)
# /etc/ansible/roles/httpd/tasks/main.yml - name: 安装httpd yum: name={{ pkg }} state=latest - name: 启动httpd并设为开机自启 service: name={{ svc }} state=started enabled=true # /etc/ansible/roles/httpd/vars/main.yml(角色变量) pkg: httpd svc: httpd
-
mysql 角色(安装并启动 MariaDB)
# /etc/ansible/roles/mysql/tasks/main.yml - name: 安装MariaDB yum: name={{ pkg }} state=latest - name: 启动MariaDB service: name={{ svc }} state=started enabled=true # /etc/ansible/roles/mysql/vars/main.yml pkg: - mariadb - mariadb-server svc: mariadb
步骤 3:编写总 Playbook(调用 Roles)
创建site.yml
,按主机组分配角色:
# /etc/ansible/site.yml
---
- name: 给Web服务器部署LAMP
hosts: webservers
remote_user: root
roles: # 调用角色(按顺序执行)
- httpd
- mysql
- php
步骤 4:执行 Roles
cd /etc/ansible
ansible-playbook site.yml # 执行总Playbook
四、Playbook 常用命令
命令用途 | 命令示例 |
---|---|
运行 Playbook | ansible-playbook test.yaml |
检查语法错误 | ansible-playbook test.yaml --syntax-check |
查看任务列表 | ansible-playbook test.yaml --list-task |
查看目标主机 | ansible-playbook test.yaml --list-hosts |
从指定任务开始执行 | ansible-playbook test.yaml --start-at-task='安装httpd' |
输入 SSH 密码执行 | ansible-playbook test.yaml -k |
输入 sudo 密码执行 | ansible-playbook test.yaml -K |
扩展
在 Ansible 中,组嵌套(Group Nesting) 是指在主机清单(Inventory)中,将一个组作为另一个组的成员,形成层级关系的组织方式。通过组嵌套,可以更灵活地管理不同层级、不同功能的主机集合,简化 Playbook 中目标主机的指定。
组嵌套的核心作用
- 层级化管理主机:将主机按 "父组 - 子组" 的逻辑分类(如按业务线→部门→功能划分)。
- 简化目标指定:执行任务时,指定父组即可对其包含的所有子组主机生效,无需逐个列出。
示例(主机清单 hosts
文件)
# 定义子组(具体功能组)
[webservers]
192.168.10.11
192.168.10.12
[dbservers]
192.168.10.21
192.168.10.22
# 定义父组(嵌套子组),使用 :children 标识
[prod:children] # prod组包含以下子组
webservers # 嵌套webservers子组
dbservers # 嵌套dbservers子组
[all_servers:children] # 更大的父组,可包含多个子组/父组
prod
testservers # 假设还有testservers子组
使用场景
-
执行命令时,指定父组
prod
即可操作其包含的所有子组主机:ansible prod -m ping # 对webservers和dbservers的所有主机执行ping测试
-
Playbook 中指定父组作为目标:
- name: 部署生产环境所有服务 hosts: prod # 涵盖webservers和dbservers tasks: ...
通过组嵌套,能有效减少重复配置,尤其适合主机数量多、分类复杂的场景(如多环境、多业务线的企业级部署)。
在 Ansible 中,Handlers(处理器) 是一种特殊的任务,它不会主动执行,而是被其他任务通过 notify
指令触发触发 ,通常用于响应配置变更后的操作(如服务重启、进程重载等)。它的核心价值是:仅在相关任务产生 "变更" 时才执行,避免无意义的重复操作(例如配置文件未修改时,无需重启服务)。
Handlers 的核心特性
- 被动触发 :Handlers 定义的任务不会默认执行,必须被其他任务的
notify
指令调用。 - 条件执行 :只有当触发它的任务执行状态为
changed
(配置有实际变更)时,Handlers 才会执行。 - 合并执行 :多个任务触发同一个 Handler 时,Handler 只会在当前 Play 的所有普通任务执行完毕后运行一次(避免重复操作)。
Handlers 的基本用法
定义 Handlers
Handlers 通常在 Playbook 的 handlers
区块中定义,语法与普通任务完全一致(调用 Ansible 模块),但必须指定唯一的 name
(用于被 notify
匹配)。
触发 Handlers
在普通任务中通过 notify: "Handler名称"
指令触发,名称必须与 Handlers 中定义的 name
完全一致(区分大小写)。
notify:notify
是 Ansible 中连接 "任务变更" 与 "后续响应操作" 的桥梁
示例:配置文件变更后重启服务
---
- name: 部署Nginx并自动重启
hosts: webservers
tasks:
# 任务1:安装Nginx(无变更时不会触发Handler)
- name: 安装Nginx
yum: name=nginx state=latest
# 任务2:推送Nginx配置文件(配置变更时触发Handler)
- name: 复制Nginx配置文件
copy:
src: /opt/nginx.conf
dest: /etc/nginx/nginx.conf
notify: "重启Nginx服务" # 配置变更时触发同名Handler
# 任务3:启动Nginx(首次执行时启动,后续不重复操作)
- name: 确保Nginx服务启动
service: name=nginx state=started
# 定义Handlers(触发后执行的任务)
handlers:
- name: 重启Nginx服务 # 名称必须与notify完全匹配
service: name=nginx state=restarted