文章目录
- 前言
- 理论部分
-
- [1_Playbook 的结构](#1_Playbook 的结构)
- [2_Ansible Playbook 示例](#2_Ansible Playbook 示例)
-
- [2.1_基础 Playbook 结构](#2.1_基础 Playbook 结构)
- [3_命令行运行 Playbook](#3_命令行运行 Playbook)
- 4_变量和引用
- [5_条件判断 when](#5_条件判断 when)
- [6_迭代:with_items 与 loop](#6_迭代:with_items 与 loop)
- [7_Templates 模块](#7_Templates 模块)
- [8_Tags 模块](#8_Tags 模块)
- [9_Roles 模块](#9_Roles 模块)
-
- [9.1_Roles 概念](#9.1_Roles 概念)
- [9.2_roles 目录结构及含义](#9.2_roles 目录结构及含义)
- [9.3_使用 Roles 的步骤](#9.3_使用 Roles 的步骤)
- 实验部分
-
- [1_搭建基于 Roles 的 LAMP 环境](#1_搭建基于 Roles 的 LAMP 环境)
-
- 1.1_环境规划
- [1.2_创建 Roles 目录结构](#1.2_创建 Roles 目录结构)
- 1.3_编写各角色内容
- [1.4_编写主 Playbook(site.yml)](#1.4_编写主 Playbook(site.yml))
- [1.5_执行 Playbook](#1.5_执行 Playbook)
- 结语
前言
本文系统讲解了 Ansible Playbook 的核心编写方法,涵盖结构组成、变量使用、条件判断、循环迭代、模板(Templates)、标签(Tags)以及角色(Roles)等关键知识点,并辅以完整实验案例。通过本文学习,可掌握自动化运维中 Playbook 的规范写法与模块化设计。
- Playbook 的基本结构
- Playbook 示例与运行方式
- 变量定义与引用
- 条件判断(when)
- 迭代(with_items / loop)
- Templates 模板机制
- Tags 标签控制任务执行
- Roles 角色体系与目录结构
- Roles 实战部署 Web + DB + PHP 环境
理论部分
1_Playbook 的结构
Ansible Playbook 是一个 YAML 格式的配置文件,用于批量执行任务,其核心由多个 Play 组成,每个 Play 面向一组主机执行一系列操作。
1.1_核心组成部分
① Tasks(任务)
任务列表,按顺序在目标主机上执行,每个任务调用一个 Ansible 模块(如 yum、copy、service 等)。
② Variables(变量)
用于提升 Playbook 的灵活性和复用性,可在 vars 区域定义,或通过命令行 -e 传入。
③ Templates(模板)
基于 Jinja2 引擎的 .j2 文件,动态生成配置文件(如 httpd.conf.j2),支持变量替换。
④ Handlers(处理器)
仅在被 notify 触发且任务状态为 changed 时执行,常用于服务重启。所有普通任务执行完毕后才统一执行 handlers,避免重复触发。
⑤ Roles(角色)
将 tasks、handlers、vars、templates 等按功能模块化组织,形成可复用的标准化单元,便于大型项目管理。
2_Ansible Playbook 示例
2.1_基础 Playbook 结构
yaml
---
- name: first play1
gather_facts: false
hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
- name: disable selinux
command: '/sbin/setenforce 0'
- name: disable firewalld
service: name=firewalld state=stopped
- name: install httpd
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify: "restart httpd"
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
---:YAML 文件起始标记(可省略)
gather_facts: false:跳过 facts 收集,加速执行
ping::测试连通性模块,无需参数
command:执行命令,不经过 shell,不支持管道/重定向
notify:仅当任务状态为changed时触发 handler
handlers:必须与notify名称严格一致
3_命令行运行 Playbook
常用命令参数:
shell
ansible-playbook test1.yaml # 执行 playbook
ansible-playbook test1.yaml --syntax-check # 语法检查
ansible-playbook test1.yaml --list-tasks # 列出所有任务
ansible-playbook test1.yaml --list-hosts # 列出影响的主机
ansible-playbook test1.yaml --start-at-task='install httpd' # 从指定任务开始
ansible-playbook test1.yaml -k # 提示输入 SSH 密码
ansible-playbook test1.yaml -K # 提示输入 sudo 密码
-k(小写):SSH 密码
-K(大写):sudo 密码(需配合become: yes使用,默认未启用)
4_变量和引用
变量可在 Play 内部定义,也可通过命令行传入:
yaml
- name: second play
hosts: dbservers
remote_user: root
vars:
groupname: mysql
username: nginx
tasks:
- name: create group
group: name={{ groupname }} system=yes gid=306
- name: create user
user: name={{ username }} uid=306 group={{ groupname }}
- name: copy file
copy: content="{{ ansible_default_ipv4.address }}" dest=/opt/vars.txt
命令行传参:
shell
ansible-playbook test1.yaml -e "username=nginx"
{``{ }}:Jinja2 变量引用语法
ansible_default_ipv4.address:facts 中的 IP 地址变量(需gather_facts: true)
5_条件判断 when
when 指令用于控制任务是否执行,条件为真则执行。
yaml
- name: shutdown host
command: /sbin/shutdown -r now
when: ansible_default_ipv4.address == "192.168.10.14"
- name: check hostname
debug: msg="This is db server"
when: inventory_hostname == "db01"
when中的变量 无需加{``{}},直接使用变量名常用于跳过特定主机或根据硬件条件(内存、CPU)执行任务
6_迭代:with_items 与 loop
Ansible 支持对列表进行循环操作,推荐使用 loop(新语法),with_items 为旧语法但兼容。
yaml
- name: create directories
file:
path: "{{ item }}"
state: directory
loop:
- /tmp/test1
- /tmp/test2
- name: add users
user: name={{ item.name }} state=present groups={{ item.groups }}
loop:
- { name: 'test1', groups: 'wheel' }
- { name: 'test2', groups: 'root' }
item:循环中的当前元素支持字典列表,通过
item.key访问字段
7_Templates 模块
利用 Jinja2 模板动态生成配置文件。
步骤:
- 准备
.j2模板文件 - 在 inventory 或 vars 中定义变量
- 使用
template模块部署
示例模板 /opt/httpd.conf.j2:
conf
Listen {{ http_port }}
ServerName {{ server_name }}
DocumentRoot "{{ root_dir }}"
Playbook 片段:
yaml
- hosts: all
remote_user: root
vars:
package: httpd
service: httpd
tasks:
- name: install httpd package
yum: name={{ package }} state=latest
- name: install configure file
template: src=/opt/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: restart httpd
- name: create root dir
file: path=/etc/httpd/htdocs state=directory
- name: start httpd server
service: name={{ service }} enabled=true state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
Inventory 定义主机变量:
ini
[webservers]
192.168.10.14 http_port=80 server_name=www.benet.com root_dir=/etc/httpd/htdocs
8_Tags 模块
通过 tags 为任务打标签,运行时可选择性执行。
yaml
- name: Copy hosts file
copy: src=/etc/hosts dest=/opt/hosts
tags:
- only
- name: touch file
file: path=/opt/testhost state=touch
tags:
- always
执行命令:
shell
ansible-playbook webhosts.yaml --tags="only"
always:无论指定哪个标签,带always的任务都会执行
9_Roles 模块
9.1_Roles 概念
Roles 是 Ansible 的最佳实践,用于将复杂 Playbook 拆分为可复用、结构化的组件,适用于多服务(Web、DB、PHP)混合部署场景。
优势:
- 模块化组织任务、变量、模板
- 自动加载
tasks/main.yml、handlers/main.yml等 - 支持默认变量(
defaults)与覆盖变量(vars)
9.2_roles 目录结构及含义
标准角色目录结构:
roles/
└── <role_name>/
├── files/ # 存放 copy/script 模块使用的静态文件
├── templates/ # 存放 .j2 模板文件
├── tasks/ # 主任务文件 main.yml
├── handlers/ # 处理器 main.yml
├── vars/ # 角色专属变量 main.yml(优先级高)
├── defaults/ # 默认变量 main.yml(优先级低)
└── meta/ # 元数据,定义依赖关系
9.3_使用 Roles 的步骤
- 创建 roles 目录:
/etc/ansible/roles/ - 为每个服务创建角色目录(如 httpd、mysql)
- 在各角色下创建子目录并添加
main.yml - 编写
site.yml调用角色 - 运行
ansible-playbook site.yml
实验部分
1_搭建基于 Roles 的 LAMP 环境
1.1_环境规划
| 主机组 | IP 地址 | 角色 |
|---|---|---|
| webservers | 192.168.10.14 | httpd, mysql, php |
本实验将 httpd、mysql、php 三个服务均部署在
webservers组
1.2_创建 Roles 目录结构
① 创建项目目录与角色骨架
shell
mkdir -p /etc/ansible/roles/{httpd,mysql,php}/{files,templates,tasks,handlers,vars,defaults,meta}
-p:递归创建多级目录
② 创建各角色的 main.yml 文件
shell
touch /etc/ansible/roles/httpd/{tasks,handlers,vars}/main.yml
touch /etc/ansible/roles/mysql/{tasks,handlers,vars}/main.yml
touch /etc/ansible/roles/php/{tasks,handlers,vars}/main.yml
defaults和meta本次未使用,可省略
1.3_编写各角色内容
① 编写 httpd 角色
shell
vim /etc/ansible/roles/httpd/tasks/main.yml
yaml
- name: install apache
yum: name={{ pkg }} state=latest
- name: start apache
service: enabled=true name={{ svc }} state=started
shell
vim /etc/ansible/roles/httpd/vars/main.yml
yaml
pkg: httpd
svc: httpd
② 编写 mysql 角色
shell
vim /etc/ansible/roles/mysql/tasks/main.yml
yaml
- name: install mysql
yum: name={{ pkg }} state=latest
- name: start mysql
service: enabled=true name={{ svc }} state=started
shell
vim /etc/ansible/roles/mysql/vars/main.yml
yaml
pkg:
- mariadb
- mariadb-server
svc: mariadb
③ 编写 php 角色
shell
vim /etc/ansible/roles/php/tasks/main.yml
yaml
- name: install php
yum: name={{ pkg }} state=latest
- name: start php-fpm
service: enabled=true name={{ svc }} state=started
shell
vim /etc/ansible/roles/php/vars/main.yml
yaml
pkg:
- php
- php-fpm
svc: php-fpm
1.4_编写主 Playbook(site.yml)
shell
vim /etc/ansible/site.yml
yaml
---
- hosts: webservers
remote_user: root
roles:
- httpd
- mysql
- php
1.5_执行 Playbook
shell
cd /etc/ansible
ansible-playbook site.yml
执行后将在目标主机安装并启动 httpd、mariadb、php-fpm 服务
结语
Playbook 结构化要点 :Tasks 执行操作,Handlers 响应变更,Variables 提升复用,Templates 动态配置。
Roles 核心价值 :通过标准化目录(tasks/vars/handlers)实现模块解耦,支持跨项目复用。
执行优化技巧 :使用 --tags 精准控制任务,when 实现条件分支,loop 简化重复操作。
!question\] 请问 Ansible 中 handlers 为什么不在任务执行后立即触发? 为避免多次变更导致服务反复重启,Ansible 将所有 handlers 延迟到当前 Play 所有 tasks 执行完毕后统一执行,确保只触发一次。 \[!question\] 请问 roles 目录中 vars 和 defaults 的区别是什么? `vars/main.yml` 中的变量优先级高,会覆盖 `defaults/main.yml`;`defaults` 用于提供可被用户覆盖的安全默认值。 \[!question\] 请问 template 模块和 copy 模块的核心区别? `template` 支持 Jinja2 变量渲染(`.j2` 文件),动态生成配置;`copy` 仅做静态文件传输,不解析变量。 \[!question\] 请问 when 条件中为何不需要 {{}}? `when` 指令内部已处于 Jinja2 上下文,直接写变量名即可被解析,加 `{``{}}` 反而导致语法错误。