目录

Ansible-Playbook-编写与模块详解

Ansible Playbook 编写与模块详解

前言

Ansible 的 Playbook 是自动化运维的核心工具,它用 YAML 文件描述在远程主机上执行的一系列任务。本文详细介绍 Playbook 的结构及其各模块的概念、用途和写法,适合初学者和有经验的运维人员查阅。


1. Playbook 基本结构

Playbook 由一个或多个 Play 组成,每个 Play 负责对一组主机执行任务。主要模块:

模块概念用途
Tasks定义要执行的具体任务,每个任务调用一个模块(如 yumcopy控制任务执行顺序
Variables变量,使 Playbook 灵活可复用在不同主机间传递不同值
TemplatesJinja2 模板,动态生成文件自动化配置文件生成
Handlers响应任务变更(由 notify 触发)常用于服务重启、刷新配置
Tags给任务打标签执行 Playbook 时只执行特定任务
Roles模块化组织 Playbook管理复杂剧本、提高复用性

2. Tasks 模块

概念

Tasks 是 Playbook 中的“执行单元”。每个任务调用一个 Ansible 模块在远程主机上执行操作。

用法

tasks:
  - name: 测试连通性
    ping:
​
  - name: 安装软件包
    yum: name=httpd state=latest
​
  - name: 停止防火墙
    service: name=firewalld state=stopped

Tips

  • 任务按顺序执行
  • 每个任务尽量有 name 方便查看日志
  • 可用 ignore_errors: true 忽略失败继续执行

3. Variables 模块

概念

变量用于提高 Playbook 的通用性和可维护性。变量可以在 Playbook 中用 vars 定义,也可以通过命令行 -e 传递,还可以在 Inventory 中定义主机变量。

用法

- hosts: dbservers
  vars:
    groupname: mysql
    username: nginx
  tasks:
    - name: 创建组
      group: name={{ groupname }} system=yes gid=306
    - name: 创建用户
      user: name={{ username }} uid=306 group={{ groupname }}

命令行传递变量:

ansible-playbook test.yaml -e "username=nginx"

4. Templates 模块(Jinja2 模板)

概念

模板用于动态生成配置文件。通过 Jinja2 语法,把变量写进模板文件,执行 Playbook 时替换成真实值。

用法

  1. 创建模板文件(以 .j2 为后缀):
# /opt/httpd.conf.j2
Listen {{ http_port }}
ServerName {{ server_name }}
DocumentRoot "{{ root_dir }}"
  1. 在主机清单定义变量:
[webservers]
192.168.10.14 http_port=80 server_name=www.accp.com root_dir=/etc/httpd/htdocs
  1. 在 Playbook 中调用模板:
- hosts: webservers
  tasks:
    - name: 安装配置文件
      template: src=/opt/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf

5. Handlers 模块

概念

Handlers 是特殊任务,用于响应普通任务的变更,通常结合 notify 使用,例如配置文件更新后自动重启服务。

用法

tasks:
  - name: 拷贝配置文件
    copy: src=/opt/httpd.conf dest=/etc/httpd/conf/httpd.conf
    notify: restart httpd
​
handlers:
  - name: restart httpd
    service: name=httpd state=restarted

Tips

  • Handlers 在 Play 执行完所有普通任务后统一执行
  • 多次 notify 同一 handler 只执行一次

6. Tags 模块

概念

Tags 用于给任务打标签,执行 Playbook 时可以指定只执行特定标签的任务。

用法

tasks:
  - name: 拷贝 hosts 文件
    copy: src=/etc/hosts dest=/opt/hosts
    tags: [only]
​
  - name: 永远执行的任务
    file: path=/opt/testhost state=touch
    tags: [always]

执行:

ansible-playbook play.yaml --tags="only"

Tipsalways 标签的任务无论执行哪个 tags 都会执行。


7. 条件判断 when

概念

when 用于按条件执行任务,只在条件为 true 时执行。

用法

tasks:
  - name: 仅在特定 IP 上重启
    command: /sbin/shutdown -r now
    when: ansible_default_ipv4.address == "192.168.10.14"
​
  - name: 按主机名判断
    debug: msg="This is myhost"
    when: inventory_hostname == "myhost"

8. 循环 with_items / loop

概念

循环可批量执行相似任务,比如批量创建目录或用户。

用法

- name: 创建多个目录
  file:
    path: "{{ item }}"
    state: directory
  with_items:
    - /tmp/test1
    - /tmp/test2
​
- name: 创建多个用户
  user: name={{ item.name }} state=present groups={{ item.groups }}
  with_items:
    - { name: test1, groups: wheel }
    - { name: test2, groups: root }

Tipsloop 是 Ansible 2.5+ 推荐用法,功能与 with_items 相同。

9.Roles 模块详解

Roles 的概念

在 Ansible 中,随着 Playbook 的功能越来越多、越来越复杂,单个 YAML 文件可能包含几十上百个任务,难以管理和复用。 **Roles(角色)**就是为了解决这个问题而设计的:

  • 把变量、任务、模板、文件、处理程序等按照固定目录结构分类存放
  • 自动按约定位置加载文件
  • 支持在不同 Playbook 中重复使用相同的角色
  • 适合按“功能”组织(例如 httpd、mysql、php),提高可维护性

简而言之,Roles 就是把 Playbook 模块化。


Roles 的目录结构

每个 Role 都在 roles/ 目录下有一个独立的子目录:

roles/
└── httpd/
    ├── files/       # copy、script 模块调用的文件
    ├── templates/   # 模板文件,template 模块自动在此目录查找
    ├── tasks/       # 必须有 main.yml,定义任务列表
    ├── handlers/    # 必须有 main.yml,定义处理程序(notify 响应)
    ├── vars/        # 必须有 main.yml,定义角色使用的变量
    ├── defaults/    # 必须有 main.yml,定义角色的默认变量(优先级最低)
    └── meta/        # 必须有 main.yml,定义角色依赖关系、特殊设定

注意

  • tasks/main.yml 是角色的入口文件(必须存在)
  • handlers/vars/defaults/meta 下的 main.yml 文件名也必须固定
  • 用不到的目录可以不建

创建 Roles 的步骤

创建 roles 目录
mkdir -p /etc/ansible/roles
创建角色目录和子目录

httpd 角色为例:

mkdir -p /etc/ansible/roles/httpd/{files,templates,tasks,handlers,vars,defaults,meta}
在各目录创建 main.yml 文件
touch /etc/ansible/roles/httpd/{defaults,vars,tasks,meta,handlers}/main.yml

在 Roles 中定义任务和变量

任务文件(tasks/main.yml):
# /etc/ansible/roles/httpd/tasks/main.yml
- name: 安装 Apache
  yum: name={{pkg}} state=latest
- name: 启动 Apache
  service: enabled=true name={{svc}} state=started
变量文件(vars/main.yml):
# /etc/ansible/roles/httpd/vars/main.yml
pkg: httpd
svc: httpd

小技巧

  • 一般把角色专用变量写在 vars/main.yml
  • 把默认变量写在 defaults/main.yml(用户可以覆盖)
  • 全局变量可以写在 /etc/ansible/group_vars/all

在 Playbook 中调用 Roles

创建 site.yml(或任意 Playbook):

# /etc/ansible/site.yml
---
- hosts: webservers
  remote_user: root
  roles:
    - httpd      # 调用 httpd 角色

如果有多个角色,按顺序写:

roles:
  - httpd
  - mysql
  - php

执行:

cd /etc/ansible
ansible-playbook site.yml

Roles 与变量的灵活使用

  • 角色变量:写在 roles/<role>/vars/main.yml,作用范围仅限当前角色
  • 默认变量:写在 roles/<role>/defaults/main.yml,优先级最低,便于用户在外部覆盖
  • 主机/组变量:写在 /etc/ansible/hostsgroup_vars/
  • 命令行变量:用 -e 覆盖一切

例子:

ansible-playbook site.yml -e "pkg=nginx svc=nginx"

Roles 依赖关系(meta/main.yml)

如果某个角色依赖于其他角色,可以在 meta/main.yml 中定义:

# /etc/ansible/roles/php/meta/main.yml
dependencies:
  - role: httpd
  - role: mysql

这样在调用 php 角色时,会自动先执行 httpdmysql 角色。


综合案例

# 创建角色
mkdir -p /etc/ansible/roles/{httpd,mysql,php}/{files,templates,tasks,handlers,vars,defaults,meta}
touch /etc/ansible/roles/{httpd,mysql,php}/{defaults,vars,tasks,meta,handlers}/main.yml

httpd/tasks/main.yml

- name: install apache
  yum: name={{pkg}} state=latest
- name: start apache
  service: enabled=true name={{svc}} state=started

httpd/vars/main.yml

pkg: httpd
svc: httpd

mysql/vars/main.yml

pkg:
  - mariadb
  - mariadb-server
svc: mariadb

php/vars/main.yml

pkg:
  - php
  - php-fpm
svc: php-fpm

site.yml

---
- hosts: webservers
  remote_user: root
  roles:
    - httpd
    - mysql
    - php

执行:

cd /etc/ansible
ansible-playbook site.yml

效果:在 webservers 主机组上依次安装 httpd、mysql、php 并启动服务。

10. 总结

  • Tasks 是执行单元
  • Variables 提供灵活性
  • Templates 动态生成配置文件
  • Handlers 响应变更,统一处理
  • Tags 定向执行特定任务
  • when/loop 控制条件和循环
  • Roles 模块化管理大型 Playbook