Ansible Playbook 编写指南:从入门到 Roles 模块化

1. Playbook 骨架一览

Ansible Playbook 是 YAML 格式的任务剧本,核心组成:

关键字 作用
hosts 目标主机或主机组
remote_user 远程执行任务的用户
tasks 要执行的任务列表
handlers notify 触发的后续动作
vars 局部变量
roles 引入可复用的角色

运行示例:

复制代码
---     #yaml文件以---开头,以表明这是一个yaml文件,可省略
- name: first play1     #定义一个play的名称,可省略
  gather_facts: false    #设置不进行facts信息收集,这可以加快执行速度,可省略
  hosts: webservers    #指定要执行任务的被管理主机组,如多个主机组用冒号分隔
  remote_user: root    #指定被管理主机上执行任务的用户
  tasks:     #定义任务列表,任务列表中的各任务按次序逐个在hosts中指定的主机上执行
   - name: test connection    #自定义任务名称
     ping:     #使用 module: [options] 格式来定义一个任务
   - name: disable selinux
     command: '/sbin/setenforce 0'    #command模块和shell模块无需使用key=value格式
     ignore_errors: True     #如执行命令的返回值不为0,就会报错,tasks停止,可使用ignore_errors忽略失败的任务
   - name: disable firewalld
     service: name=firewalld state=stopped    #使用 module: options 格式来定义任务,option使用key=value格式
   - 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    #这里需要一个事先准备好的/opt/httpd.conf文件
     notify: "restart httpd"    #如以上操作后为changed的状态时,会通过notify指定的名称触发对应名称的handlers操作
   - name: start httpd service
     service: enabled=true name=httpd state=started
  handlers:     #handlers中定义的就是任务,此处handlers中的任务使用的是service模块
   - name: restart httpd    #notify和handlers中任务的名称必须一致
     service: name=httpd state=restarted
##Ansible在执行完某个任务之后并不会立即去执行对应的handler,而是在当前play中所有普通任务都执行完后再去执行handler,这样的好处是可以多次触发notify,但最后只执行一次对应的handler,从而避免多次重启。
#      

运行结果

在运行 Playbook 时,可以使用一些常用参数来调整执行行为:

复制代码
ansible-playbook test1.yaml  # 运行 playbook
ansible-playbook test1.yaml --syntax-check  # 检查语法
ansible-playbook test1.yaml --list-task  # 查看任务列表
ansible-playbook test1.yaml --list-hosts  # 查看影响的主机
ansible-playbook test1.yaml --start-at-task='install httpd'  # 从指定任务开始执行

安装mariadb

复制代码
- name: install mysql
  hosts: dbservers
  tasks:
    - name: install mysql server
      yum:
        name: mariadb,mariadb-server
        state: latest
      become: yes
    - name: start mysql
      service:
        name: mariadb
        state: started
      become: yes

解释:

运行结果:

2. 常用命令行参数

参数 说明
-k 交互输入 SSH 密码
-K 交互输入 sudo 密码
-e 传递额外变量
--start-at-task='xxx' 从指定任务开始执行
--list-tasks 仅列出任务不执行
--list-hosts 查看会命中哪些主机

3. 变量与传参

在剧本里定义:

复制代码
vars:
  pkg: httpd
  svc: httpd

使用变量:

复制代码
- name: install package
  yum: name={{ pkg }} state=present

脚本:

复制代码
- name: second play
  hosts: dbservers
  remote_user: root
  vars: 
    groupname: mysql
    username: nginx
  tasks:
    - name: creat 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}}" dest=/opt/var.txt

代码展示:

在命令行中,变量也可以通过 -e 参数传递:

复制代码
ansible-playbook test1.yaml -e "username=nginx"

运行结果:

在dbservers(192.168.10.160)中展示的结果


4. 条件判断 when

仅对满足条件的主机执行任务:

复制代码
- name: reboot only web01
  command: /sbin/reboot
  when: inventory_hostname == "web01"

脚本代码

复制代码
---
- hosts: all
  remote_user: root
  tasks:
    - name: shutdown host
      command: /sbin/shutdown
      when: ansible_default_ipv4.address == '192.168.10.150'

运行结果:

5. 循环: with_items vs loop

批量创建用户:

复制代码
---
- name: play1
  hosts: dbservers
  gather_facts: false
  tasks:
    - name: create directories
      file:
        path: "{{item}}"
        state: directory
      with_items:
        - /tmp/test1
        - /tmp/test2
    - name: add users
      user: name={{item.name}} state=present groups={{item.groups}}
      with_items:
        - name: test1
          groups: wheel
        - name: test2
          groups: root

运行结果:

在dbservers中查看

复制代码
[root@localhost nginx-1.20.2]# ls -ld /tmp/test1 /tmp/test2 && id test1 && id test2
drwxr-xr-x. 2 root root 6 9月  25 15:33 /tmp/test1
drwxr-xr-x. 2 root root 6 9月  25 15:33 /tmp/test2
uid=1001(test1) gid=1002(test1) 组=1002(test1),10(wheel)
uid=1002(test2) gid=1003(test2) 组=1003(test2),0(root)

6. 模板(Template)

在控制端准备模板

复制代码
#先准备一个以 .j2 为后缀的 template 模板文件,设置引用的变量
cp /etc/httpd/conf/httpd.conf /opt/httpd.conf.j2

vim /opt/httpd.conf.j2
Listen {{http_port}}				#42行,修改
ServerName {{server_name}}			#95行,修改
DocumentRoot "{{root_dir}}"          #119行,修改

主机清单里给变量:

复制代码
vim /etc/ansible/hosts  
[webservers]
192.168.10.14 http_port=80 server_name=www.accp.com root_dir=/etc/httpd/htdocs

剧本引用:

复制代码
---
- hosts: webservers
  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

运行结果:


7. Tags:只跑指定任务

复制代码
---
- hosts: webservers
  remote_user: root
  tasks:
    - name: Copy hosts file
      copy: src=/etc/hosts dest=/opt/hosts
      tags:
        - only

    - name: touch file
      file: path=/opt/testhost state=touch
      tags:
        - always

    - name: Copy zcx file
      copy: src=/opt/httpd.conf.bak dest=/opt/zcx
      tags:
        - zcx

    - name: Copy yyq file
      copy: src=/opt/httpd.conf.bak dest=/opt/yyq
      tags:
        - yyq

执行:

复制代码
ansible-playbook webhosts.yaml

webservers(192.168.10.150)里面查看

设置标签

复制代码
 ansible-playbook test5.yaml --tags="zcx"

webservers(192.168.10.150)里面查看

只会在/opt下面有一个zcx的脚本


8. Handlers:一次性重启

任务 notify → 所有任务结束后再执行 handler,避免重复重启

复制代码
tasks:
  - name: install cfg
    template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
    notify: restart httpd

handlers:
  - name: restart httpd
    service: name=httpd state=restarted

9. Roles:模块化复用

创建文件夹

复制代码
[root@localhost yaml]# mkdir /etc/ansible/roles/httpd/{files,templates,tasks,handlers,vars,defaults,meta} -p
[root@localhost yaml]# mkdir /etc/ansible/roles/mysql/{files,templates,tasks,handlers,vars,defaults,meta} -p
[root@localhost yaml]# mkdir /etc/ansible/roles/php/{files,templates,tasks,handlers,vars,defaults,meta} -p
[root@localhost yaml]# 
[root@localhost yaml]# touch /etc/ansible/roles/httpd/{defaults,vars,tasks,meta,handlers}/main.yml
[root@localhost yaml]# touch /etc/ansible/roles/mysql/{defaults,vars,tasks,meta,handlers}/main.yml
[root@localhost yaml]# touch /etc/ansible/roles/php/{defaults,vars,tasks,meta,handlers}/main.yml

官方目录结构:

复制代码
[root@localhost ansible]# tree roles/
roles/
├── httpd
│   ├── defaults
│   │   └── main.yml
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   │   └── main.yml
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   └── vars
│       └── main.yml
├── mysql
│   ├── defaults
│   │   └── main.yml
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   │   └── main.yml
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   └── vars
│       └── main.yml
└── php
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── tasks
    │   └── main.yml
    ├── templates
    └── vars
        └── main.yml

24 directories, 15 files

httpd:

复制代码
vim /etc/ansible/roles/httpd/tasks/main.yml
- name: install apache
  yum: name={{pkg}} state=latest
- name: start apache
  service: enabled=true name={{svc}} state=started
 
//定义变量:可以定义在全局变量中,也可以定义在roles角色变量中,一般定义在角色变量中
vim /etc/ansible/roles/httpd/vars/main.yml
pkg: httpd
svc: httpd

mysql:

复制代码
vim /etc/ansible/roles/mysql/tasks/main.yml
- name: install mysql
  yum: name={{pkg}} state=latest
- name: start mysql
  service: enabled=true name={{svc}} state=started
  
vim /etc/ansible/roles/mysql/vars/main.yml
pkg:
  - mariadb
  - mariadb-server
svc: mariadb

php:

复制代码
vim /etc/ansible/roles/php/tasks/main.yml
- name: install php
  yum: name={{pkg}} state=latest
- name: start php-fpm
  service: enabled=true name={{svc}} state=started

vim /etc/ansible/roles/php/vars/main.yml
pkg:
  - php
  - php-fpm
svc: php-fpm

编写roles:

复制代码
[root@localhost ansible]# cat /etc/ansible/site.yaml 
---
- hosts: webservers
  remote_user: root
  roles:
    - httpd
    - mysql
    - php

运行:

复制代码
cd /etc/ansible
ansible-playbook site.yml

10. 快速调试技巧

目的 命令
仅语法检查 ansible-playbook xxx.yml --syntax-check
空跑(不真正改变) ansible-playbook xxx.yml --check
逐步调试 ansible-playbook xxx.yml --step
从指定任务开始 ansible-playbook xxx.yml --start-at-task='install httpd'
查看 diff ansible-playbook xxx.yml --diff

结语

掌握 Playbook → Variables → Templates → Tags → Roles 这条主线后,你就能写出可维护、可复用、可扩展 的 Ansible 自动化代码。

建议把文中示例保存到本地,跑通一次,再根据自己的业务场景逐步拆解、组合,很快即可形成一套完整的自动化运维体系。

录制文件:https://meeting.tencent.com/crm/2yX3JXV095

密码:WFCS

相关推荐
红尘客栈24 小时前
Ansible 入门到实战:自动化运维的瑞士军刀
运维·自动化·ansible
小闫BI设源码1 天前
Ansible自动化运维平台部署
运维·自动化·ansible·批量管理·devops工具·持续集成ci/cd·ssh协议
我好饿11 天前
自动化运维工具 Ansible 集中化管理服务器
运维·自动化·ansible
東雪蓮☆1 天前
Ansible 自动化运维:集中化管理服务器实战指南
linux·运维·自动化·ansible
荣光波比1 天前
自动化运维工具 Ansible:集中化管理服务器完全指南
运维·自动化·云计算·ansible
伞啊伞1 天前
自动化运维工具 Ansible 集中化管理服务器
运维·自动化·ansible
傻啦猫@_@12 天前
如何使用ansible上的A用户操作其它服务上的B用户目录下的文件
ansible
Sweety丶╮79412 天前
【Ansible】将文件部署到受管主机知识点
云原生·ansible
Anthony_23113 天前
Ansible的 Playbook 模式详解
linux·运维·服务器·ansible