目录
[一、Playbook 的结构](#一、Playbook 的结构)
[二、Ansible Playbook 示例](#二、Ansible Playbook 示例)
[三、命令行运行 Playbook](#三、命令行运行 Playbook)
[1. 变量定义方式](#1. 变量定义方式)
[2. 内置变量](#2. 内置变量)
[五、条件判断 when](#五、条件判断 when)
[六、迭代:使用 with_items 或 loop](#六、迭代:使用 with_items 或 loop)
[1. loop 示例(推荐)](#1. loop 示例(推荐))
[2. with_items 示例(旧版)](#2. with_items 示例(旧版))
[3. 遍历字典列表](#3. 遍历字典列表)
[七、Templates 模块](#七、Templates 模块)
[示例:动态生成 Nginx 虚拟主机配置](#示例:动态生成 Nginx 虚拟主机配置)
[八、Tags 模块](#八、Tags 模块)
[九、Roles 模块](#九、Roles 模块)
[1. Roles 目录结构](#1. Roles 目录结构)
[2. 编写 Roles 示例(以 nginx Role 为例)](#2. 编写 Roles 示例(以 nginx Role 为例))
[3. 调用 Roles](#3. 调用 Roles)
[基础部署 Nginx 服务的 Playbook](#基础部署 Nginx 服务的 Playbook)
[带变量覆盖的进阶 Playbook](#带变量覆盖的进阶 Playbook)
[4. Roles 依赖](#4. Roles 依赖)
前言
Ansible 作为一款轻量级的自动化运维工具,其核心优势之一便是通过 Playbook 实现任务的编排与自动化执行。相较于单条 ad-hoc 命令,Playbook 支持更复杂的逻辑控制、变量引用、模块组合等功能,是实现批量部署、配置管理、任务自动化的关键。本文将从 Playbook 核心结构出发,逐步讲解编写技巧、核心功能及进阶用法,带你轻松掌握剧本编写精髓。
一、Playbook 的结构
Playbook 本质是遵循 YAML 语法的文本文件,其核心结构层层嵌套,清晰明了。一个完整的 Playbook 通常包含以下几个核心组件:
-
Play :Playbook 的最小执行单元,定义了"在哪些主机上执行哪些任务"。一个 Playbook 可以包含多个 Play,实现多主机、多任务的批量编排。每个 Play 必须包含
hosts(目标主机)和tasks(任务列表)两个核心字段。 -
Hosts :指定 Play 执行的目标主机,需与 Ansible inventory(主机清单)中的主机名/组名对应,支持通配符(如
webservers、*.test.com)。 -
Tasks :任务列表,每个任务对应一个 Ansible 模块(如
yum安装软件、copy复制文件),任务按顺序执行,前一个任务失败则后续任务终止。每个任务需指定name(任务描述,可选但推荐)和模块参数。 -
Variables:变量定义,用于存储可复用的值(如软件版本、文件路径),支持在 Play 内定义、从 inventory 继承、通过命令行传递等多种方式。
-
Handlers :触发器,用于响应任务的状态变化(如配置文件修改后重启服务)。只有当任务通过
notify调用且任务状态为changed时,Handlers 才会执行,且多个任务触发同一 Handler 时,Handler 仅执行一次。 -
Roles:角色,用于将 Playbook 按功能拆分(如 web 角色、db 角色),实现代码复用与模块化管理,是 Playbook 进阶编写的核心。
YAML 语法注意事项:缩进统一使用 2 个空格(禁止使用 Tab);键值对冒号后需加空格(如 hosts: webservers);列表项以 - 开头,后跟空格。
二、Ansible Playbook 示例
以下是一个基础的 Playbook 示例,实现"在 web 服务器上安装 Nginx 并启动服务"的功能,文件名保存为 install_nginx.yml:
yaml
- name: 安装并启动 Nginx
hosts: webservers
remote_user: root
tasks:
- name: 安装 Nginx 软件
yum:
name: nginx
state: present
- name: 复制 Nginx 配置文件
copy:
src: ./nginx.conf
dest: /etc/nginx/nginx.conf
mode: 0644
notify: restart nginx
- name: 启动 Nginx 服务并设置开机自启
service:
name: nginx
state: started
enabled: yes
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
该示例包含 1 个 Play、3 个任务和 1 个 Handler,逻辑清晰:先安装 Nginx,再复制配置文件(配置变化则触发重启),最后启动服务并设置开机自启。
三、命令行运行 Playbook
编写完 Playbook 后,通过 ansible-playbook 命令执行,核心语法如下:
ansible-playbook [选项] 剧本文件名.yml
常用选项说明:
-
-i <inventory_path>:指定主机清单路径,默认路径为/etc/ansible/hosts。例:ansible-playbook -i ./my_hosts install_nginx.yml -
-u <remote_user>:指定远程执行用户,优先级高于 Playbook 中定义的remote_user。例:ansible-playbook -u centos install_nginx.yml -
--become:切换到 root 权限执行(sudo),如需指定 sudo 密码,可加--ask-become-pass(缩写-K)。例:ansible-playbook --become -K install_nginx.yml -
--check:模拟执行(干跑),不实际修改目标主机,用于验证 Playbook 语法和逻辑。例:ansible-playbook --check install_nginx.yml -
--tags <tag_name>:仅执行指定标签的任务(后续 Tags 模块详解)。例:ansible-playbook --tags install install_nginx.yml -
-e <key=value>:传递额外变量(优先级最高)。例:ansible-playbook -e "nginx_version=1.24" install_nginx.yml
执行成功后,终端会输出每个任务的执行状态(ok:无变化,changed:有修改,failed:失败),以及最终的执行统计信息。
四、变量和引用
变量是 Playbook 复用性的核心,支持多种定义方式,引用时使用 {``{ 变量名 }} 语法。
1. 变量定义方式
-
Play 内定义 :通过
vars字段定义,作用域仅限于当前 Play。示例:yaml- name: 测试变量 hosts: webservers vars: nginx_version: 1.24 nginx_conf_path: /etc/nginx/nginx.conf tasks: - name: 安装指定版本 Nginx yum: name: nginx-{{ nginx_version }} state: present - name: 验证配置文件路径 file: path: "{{ nginx_conf_path }}" state: file -
Inventory 中定义:在主机清单中为主机/组定义变量,作用域为对应主机/组。示例(inventory 文件):
主机和组变量定义
以下代码实现了在Ansible中定义主机级变量和组级变量的功能:
ini[webservers] web1.test.com nginx_version=1.24 # 主机级变量 web2.test.com nginx_version=1.23 [webservers:vars] nginx_conf_path=/etc/nginx/nginx.conf # 组级变量,所有webservers主机继承变量使用示例
在playbook中可以通过以下方式引用这些变量:
yaml- hosts: webservers tasks: - name: Display Nginx version debug: msg: "Nginx version is {{ nginx_version }}" - name: Display Nginx config path debug: msg: "Nginx config path is {{ nginx_conf_path }}"变量继承说明
组级变量
nginx_conf_path会被所有webservers组中的主机继承,而主机级变量nginx_version则只对特定主机有效。执行结果
当运行上述playbook时:
-
对于web1.test.com会显示:
Nginx version is 1.24 Nginx config path is /etc/nginx/nginx.conf -
对于web2.test.com会显示:
Nginx version is 1.23 Nginx config path is /etc/nginx/nginx.conf -
命令行传递 :通过
-e选项传递,优先级最高,会覆盖其他方式定义的同名变量。示例:ansible-playbook -e "nginx_version=1.25" install_nginx.yml -
变量文件引入 :将变量写入独立 YAML 文件(如
vars.yml),通过vars_files引入,适合变量较多的场景。示例:yamlnginx_version: 1.24 nginx_conf_path: /etc/nginx/nginx.confyaml- name: 引入变量文件 hosts: webservers vars_files: - ./vars.yml tasks: - name: 安装 Nginx yum: name: nginx-{{ nginx_version }} state: present - name: 确保 Nginx 配置文件存在 file: path: "{{ nginx_conf_path }}" state: touch - name: 启动 Nginx 服务 service: name: nginx state: started enabled: yes
2. 内置变量
Ansible 提供大量内置变量( Facts ),用于获取目标主机的系统信息(如 IP、系统版本、内存等),可通过 ansible <host> -m setup 命令查看所有 Facts。常用内置变量:
-
{``{ ansible_fqdn }}:目标主机的完全限定域名 -
{``{ ansible_default_ipv4.address }}:目标主机的默认 IPv4 地址 -
{``{ ansible_os_family }}:目标主机的系统家族(如 RedHat、Debian)
五、条件判断 when
通过 when 关键字实现条件判断,仅当条件满足时,任务才会执行。when 支持多种条件表达式(比较运算、逻辑运算、内置变量判断等)。
常用示例
-
根据系统类型执行不同任务(区分 CentOS 和 Ubuntu):
yaml- name: 条件判断示例 hosts: all tasks: - name: CentOS 系统安装 Nginx yum: name: nginx state: present when: ansible_os_family == "RedHat" - name: Ubuntu 系统安装 Nginx apt: name: nginx state: present update_cache: yes when: ansible_os_family == "Debian" -
逻辑运算条件(and/or/not):
yaml- name: 逻辑运算条件 hosts: webservers vars: env: prod # 环境变量:prod生产环境,test测试环境 tasks: - name: 生产环境且系统为CentOS时执行 yum: name: nginx state: present when: env == "prod" and ansible_os_family == "RedHat" -
判断变量是否存在:
yaml- name: 判断变量是否存在 hosts: webservers tasks: - name: 变量存在时执行 debug: msg: "Nginx版本:{{ nginx_version }}" when: nginx_version is defined - name: 变量不存在时执行 debug: msg: "nginx_version变量未定义" when: nginx_version is not defined
六、迭代:使用 with_items 或 loop
当需要重复执行同一类任务(如安装多个软件、创建多个目录)时,可通过迭代功能简化代码。Ansible 支持 with_items(旧版,仍常用)和 loop(新版,推荐)两种方式,本质都是遍历列表数据。
1. loop 示例(推荐)
遍历列表,安装多个软件:
yaml
- name: 迭代安装基础软件
hosts: webservers
tasks:
- name: 通过yum安装软件包
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- mysql-server
- php-fpm
loop_control:
label: "{{ item }}"
2. with_items 示例(旧版)
功能与 loop 类似,语法略有差异:
yaml
- name: 迭代示例(with_items)
hosts: webservers
tasks:
- name: 创建多个目录
file:
path: "{{ item }}"
state: directory
mode: 0755
with_items:
- /etc/nginx/conf.d
- /var/log/nginx
- /usr/share/nginx/html
3. 遍历字典列表
当需要传递多个参数时,可遍历字典列表:
yaml
- name: 遍历字典列表创建用户并指定组
hosts: webservers
tasks:
- name: 创建多个用户并指定组
user:
name: "{{ item.name }}"
group: "{{ item.group }}"
state: present
loop:
- { name: "nginx", group: "nginx" }
- { name: "php", group: "php" }
- { name: "mysql", group: "mysql" }
七、Templates 模块
Templates 模块用于将本地的 Jinja2 模板文件渲染到目标主机,支持在模板中嵌入变量、条件判断、循环等逻辑,适合动态生成配置文件(如 Nginx 虚拟主机配置、MySQL 配置等)。
核心步骤
-
创建 Jinja2 模板文件(后缀通常为
.j2),在模板中嵌入变量或逻辑。 -
使用
template模块将模板渲染到目标主机。
示例:动态生成 Nginx 虚拟主机配置
-
创建 Jinja2 模板 (
nginx_vhost.j2):nginxserver { listen {{ nginx_listen_port }}; server_name {{ ansible_default_ipv4.address }}; root {{ nginx_root_dir }}; index index.html index.php; {% if enable_ssl %} listen 443 ssl; ssl_certificate {{ ssl_cert_path }}; ssl_certificate_key {{ ssl_key_path }}; {% endif %} } -
Playbook 中使用 template 模块:
yaml- name: 使用 Templates 模块 hosts: webservers vars: nginx_listen_port: 80 nginx_root_dir: /usr/share/nginx/html enable_ssl: false # 不启用SSL tasks: - name: 渲染 Nginx 虚拟主机配置 template: src: ./nginx_vhost.j2 # 本地模板文件路径 dest: /etc/nginx/conf.d/default.conf # 远程目标配置文件 mode: 0644 notify: restart nginx # 配置变化触发重启 handlers: - name: restart nginx service: name: nginx state: restarted
八、Tags 模块
Tags 用于为 Play 或任务添加"标签",执行 Playbook 时可通过 --tags 或 --skip-tags 选项指定执行/跳过的任务,适合在复杂 Playbook 中仅执行部分任务(如仅安装软件、仅更新配置)。
使用示例
yaml
- name: Nginx 部署与管理
hosts: webservers
tasks:
- name: 安装 Nginx 软件包
yum:
name: nginx
state: present
tags:
- install
- package
- name: 部署 Nginx 配置文件
template:
src: ./templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
tags:
- config
- deploy
notify: reload nginx
- name: 确保 Nginx 服务运行
service:
name: nginx
state: started
enabled: yes
tags:
- service
- start
handlers:
- name: reload nginx
service:
name: nginx
state: reloaded
tags:
- handler
- reload
常用命令
-
仅执行
install标签的任务:ansible-playbook --tags install install_nginx.yml -
执行
install和config标签的任务:ansible-playbook --tags "install,config" install_nginx.yml -
跳过
restart标签的任务:ansible-playbook --skip-tags restart install_nginx.yml -
执行所有任务(默认):
ansible-playbook install_nginx.yml
九、Roles 模块
当 Playbook 越来越复杂时,通过 Roles 可实现"功能模块化拆分",将不同功能的任务、变量、模板等按固定目录结构组织,实现代码复用、团队协作和简化维护。Roles 是 Ansible 规模化部署的核心。
1. Roles 目录结构
Roles 有固定的目录规范,每个 Role 对应一个目录,目录名即为 Role 名。标准结构如下:
stylus
roles/
└── nginx/
├── defaults/
│ └── main.yml
├── vars/
│ └── main.yml
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ └── nginx.conf.j2
├── files/
│ └── index.html
└── meta/
└── main.yml
说明:每个目录下的 main.yml 是入口文件,Ansible 会自动加载该文件中的内容。
2. 编写 Roles 示例(以 nginx Role 为例)
-
tasks/main.yml(核心任务):
yaml- name: 安装 Nginx yum: name: nginx-{{ nginx_version }} state: present - name: 复制 Nginx 配置文件(模板渲染) template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf mode: 0644 notify: restart nginx - name: 复制首页静态文件 copy: src: index.html dest: "{{ nginx_root_dir }}/index.html" mode: 0644 - name: 启动 Nginx 服务 service: name: nginx state: started enabled: yes -
vars/main.yml (自定义变量):
nginx_version: 1.24 ``nginx_root_dir: /usr/share/nginx/html ``nginx_listen_port: 80 -
handlers/main.yml (触发器):
- name: restart nginx `` service: `` name: nginx `` state: restarted
3. 调用 Roles
编写 Playbook(site.yml)调用 nginx Role:
基础部署 Nginx 服务的 Playbook
yaml
- name: 部署 Nginx 服务
hosts: webservers
roles:
- nginx
带变量覆盖的进阶 Playbook
yaml
- name: 部署 Nginx 服务(自定义变量)
hosts: webservers
roles:
- role: nginx
vars:
nginx_version: 1.25
nginx_listen_port: 8080
目录结构建议
roles/
└── nginx/
├── tasks/
│ └── main.yml
├── defaults/
│ └── main.yml
├── vars/
│ └── main.yml
└── templates/
└── nginx.conf.j2
执行命令:ansible-playbook -i ./inventory site.yml
4. Roles 依赖
若一个 Role 依赖其他 Role(如 nginx Role 依赖 firewalld Role 开放端口),可在 meta/main.yml 中定义依赖:
# nginx/meta/main.yml dependencies: - role: firewalld # 依赖 firewalld Role firewalld_ports: - 80/tcp - 443/tcp
执行 nginx Role 时,Ansible 会自动先执行依赖的 firewalld Role。
总结
Ansible-Playbook 剧本编写的核心是掌握 YAML 语法和核心组件(Play、Tasks、Variables 等),再通过条件判断、迭代、模板等功能实现复杂逻辑,最终通过 Roles 实现模块化和规模化部署。本文从基础到进阶,覆盖了 Playbook 编写的全流程要点,建议结合实际场景多动手练习(如部署 Nginx、MySQL 等服务),才能快速掌握。如果需要进一步深入,可学习 Ansible 的变量优先级、加密变量(Vault)、动态 Inventory 等高级功能。