跳转至

Ansible剧本 --- playbook的yaml文件编写

一. playbook基础

1. 基础知识

我们在执行大量ansible时候,如果在终端中一个一个敲就太麻烦了。这时候可以通过某种特殊方式将各种命令组合到一起,形成一个"剧本"文件。通过执行该文件就能匹配执行所有ansible命令。

2. 关键点

  • playbook是由一个一个任务组合而成的
  • playbook中的指令是基于ansible命令演变来的
  • playbook的专用执行命令时ansible-playbook

3. 样式示例

- hosts: 10.0.0.13
  remote_user: root
  tasks:
  - name: Hello World
    command: echo "Hello World"
    tags:
    - hello world
  - name: extra vars
    debug: msg-{{ extra_vars }}

4. 功能解析

对于ansible的局部playbook文件来说,主要有四部分组成

组成部分 功能描述 常见属性 备注
Target section 执行playbook的目标主机 hosts、remote_user、order 必备内容
Variable section 执行playbook所需的变量 vars 可选内容
Task section playbook中的功能任务 task(name、模块名称) 必备内容
Handler section 各任务之间的关联关系 handler(name、模块名称) 可选内容

注意:

  • 可选内容的意思是说,可以使用ansible的默认的,我们不一定需要自己自定义
  • task部分的作用就是各自ansible模块的使用
  • playbook文件内容格式是yaml文件

二. 核心功能

1. playbook的常见组件

一个playbook中由多个组件组成,其中所用到的常见组件类型如下

Hosts: 执行的远程主机列表

Tasks: 任务集,由多个tasks的元素组成的列表实现,每个tasks是一个字典。

Variables: 内置变量或者自定义变量在playbook中调用。

Templates: 模板,可以换模板文件中的变量并实现一些简单的逻辑文件。

Handlers: 和notify结合使用,由特定条件触发操作,满足条件方可执行。否则不执行。

tags: 标签,指定某条任务执行。用于选择playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分。即便如此有些代码为测试其确实没有发生变化的实践依然会非常长。因此如果确信其没有变化,就可以通过tags跳过此些代码的片段。

一个完整代码块功能最少元素需要包括name和task,一个name只能包括一个task。

2. hosts属性

1) 简介

playbook的作用就是自动化批量执行各种ansible命令来实现特定功能。而这些ansible指令最终都是要到某个或某些主机上执行。所以playbook文件中必须要制定某些特定的ansible指令操作地方 --- 也就是目标主机

playbook中专门指定目标主机的属性叫hosts,而这个里面定义的目标主机必须在ansible主机列表或清单文件中。

2) 属性样式

由于hosts的配置目的与ansible主机列表文件目的一致,所以他们的编写方法也一样,主要有这么几种表示样式

单个主机:
  - hosts: 192.168.100.100
  - hosts: master.ansible.com
多个主机:
  - hosts: 192.168.100.*
  - hosts: *.ansible.com
特定主机:
  - hosts: web:mysql
  - hosts: web:&mysql
  - hosts: web:!mysql

注意:

如果主机数量过多的话,我们可以通过serial属性来限制一次性多少台主机执行任务,从而减轻所有任务执行时候的并行压力

  • serial:"20%" # 每次只同时处理20%的主机
  • serial:"2" # 每次只同时处理2台主机

3. remote_user属性

1) 简介

因为ansible是基于ssh协议与明白通信的,所以ansible肯定以某个指定用户身份到目标主机上执行任务。所以playbook在执行各种ansible指令是,肯定有一个属性是来指定这些ansible指定以什么样的身份到目标主机执行,这个属性就是remote_user

用户身份虽然简单,但它不仅仅涉及到了登录用户,也涉及到了用户在执行命令时候的权限控制,即sudo的方式

remote_user的作用就类似于ansible命令中"-u 登录用户" + "-k 登录密码" + "-K 提权密码"

2) 属性样式

由于playbook是由大量功能任务组成的,而这些功能任务有可能在不同的目标主机上以不同用户来运行。所以在playbook中remote_user基于使用范围和目的的不同,有两种表现形式

默认登录用户:
  默认登录用户也称全局登录用户,用于所有task任务的默认执行用户
表现形式是:
- hosts: web
  remote_user: root
或者:
- hosts: mysql
  remote_user: othername
特殊登录用户:
  特殊登录用户是针对task人物列表中某个具体任务来说的,我们需要在task任务中采取如下形式切换用户,实现特定效果
表现形式:
- hosts: web
  remote_user: root                # 默认连接用户
  tasks:
    - name: 以普通用户连接,再提权到其他用户
      ping:                        # 没错,可以不写值
      remote_user: putong          # 用 putong 连接 SSH
      become: yes                  # 开启提权(替代 sudo: yes)
      become_user: othername       # 提权到 othername(替代 sudo_user)

注意:

  • 在具体的task中想要使用become_user必须要先开启提权功能,即要有become: yes,如果只有become: yes而没有become_user,则会以root用户身份执行任务
  • 子任务在切换任务时,要和全局默认的登录用户识别清楚。

4. tasks属性

1) 简介

playbook文件的主要作用就是实现各种各样的功能。每一个功能都是由大量的ansible指令来组成的。所以对于playbook来说每一个特定的ansible动作都是一个子功能任务。所以playbook的功能主题就是大量的task列表。而且这些任务在执行的时候有一个非常重要的功能特性:幂等性。简单来说就是执行多次任务和执行一次任务的效果是相同的。

playbook在执行的时候,根据task列表的顺序,诸葛在hosts目标主机上执行。默认情况下任何一个任务中途发生错误整个任务都会自动中断。所以默认的task在执行时有一个隐患:在某些条件长江下的逻辑感不强。

我们有相应的属性来解决这种隐患:notify+handler

每一个具体的task主要有两部分组成

  • task名称: 通过name属性来设定该任务中的子命令名称,建议详细一些
  • task动作: ansible命令实现特定功能的模块及其使用方法

2) 属性样式

task名称,我们使用name属性表示就可以了,格式如下:
- hosts: web
  remote_user: root
  tasks:
  - name: test connection
注意:
  name的内容尽量详细一点,但是不需要过于详细,能看明白就可以了
task动作,主要涉及到了ansible的模块及可执行命令两部分内容,它一般有两种格式:
  1) action: 模块 具体动作
  2) 模块: 具体动作
注意:
  方法2一目了然,所以我们推荐使用方法2
  "具体动作"会根据模块的不同,编写的样式也不一样
  对于其他模块来说,具体动作就是"key=value"样式

3. tasks示例

1) 查看hosts主机的文件示例

查看host主机文件示例

03-playbook-action.yml 文件内容如下:
- hosts: web
  remote_user: root
  tasks:
  - name: test connection
    ping:
  - name: hostname
    shell: hostname

2) 文件执行

# 测试
ansible-playbook /etc/ansible/my-playbook.yaml --syntax-check
# 模拟执行
ansible-playbook /etc/ansible/my-playbook.yaml --check --diff
# 逐步执行
ansible-playbook /etc/ansible/my-playbook.yaml --step
# 执行
ansible-playbook /etc/ansible/my-playbook.yaml -v   # -v的作用时显示信息多一点

在一个任务中,如果存在多个action动作,只有最后一个action动作生效

# abc.yaml
- hosts: "3"
  remote_user: root
  tasks:
  - name: hostname
    shell: hostname
    shell: ls -a

检查效果

[root@my-project playbook]# ansible-playbook abc.yaml -v
Using /etc/ansible/ansible.cfg as config file
[WARNING]: While constructing a mapping from /root/playbook/abc.yaml, line 5, column 5, found a duplicate dict key (shell). Using last defined value only.

PLAY [3] ************************************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************************
ok: [3]

TASK [hostname] *****************************************************************************************************************************************************************************************
changed: [3] => {"changed": true, "cmd": "ls -a", "delta": "0:00:00.004367", "end": "2026-08-21 11:12:37.040147", "msg": "", "rc": 0, "start": "2026-08-21 11:12:37.035780", "stderr": "", "stderr_lines": [], "stdout": ".\n..\nanaconda-ks.cfg\n.ansible\n.bash_history\n.bash_logout\n.bash_profile\n.bashrc\n.cache\n.copilot\n.cshrc\n.dotnet\n.lesshst\n.ssh\n.tcshrc\n.vscode-server", "stdout_lines": [".", "..", "anaconda-ks.cfg", ".ansible", ".bash_history", ".bash_logout", ".bash_profile", ".bashrc", ".cache", ".copilot", ".cshrc", ".dotnet", ".lesshst", ".ssh", ".tcshrc", ".vscode-server"]}

PLAY RECAP **********************************************************************************************************************************************************************************************
3                          : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

结果显示:

  • 我们要看详情应该结合-v或者-vv更详细的信息来辨别
  • 一个任务中只能有一个action动作执行成功,默认是最后一条

三. 简单实践

# 使用playbook给web_servers部署zabbix_agent

- name: 部署zabbix-agent
  hosts: "2"
  become: yes
  gather_facts: yes

# 修改阿里云yum源
# mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup
# mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup
# yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpm
# sed -i 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
# sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
  tasks:
  - name: 挂载光盘
    mount:
      src: /dev/sr0
      path: /media/cdrom
      state: mounted
      fstype: iso9660

  - name: 备份原epel
    shell: mv /etc/yum.repos.d/epel.repo /etc/yum.repos.d/epel.repo.backup ; mv /etc/yum.repos.d/epel-testing.repo /etc/yum.repos.d/epel-testing.repo.backup
    ignore_errors: yes

  - name: 更新阿里云epel
    yum:
      name: https://mirrors.aliyun.com/epel/epel-release-latest-9.noarch.rpm
      state: present
      disable_gpg_check: yes

  - name: 修改yum源文件
    shell: sed -i -e 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|' -e 's|^metalink|#metalink|' /etc/yum.repos.d/epel*

# 安装依赖
# yum -y install pcre pcre-devel net-snmp net-snmp-devel curl-devel libssh2-devel libevent libevent-devel curl curl-devel perl-DBI gcc make      
  - name: 安装依赖工具
    yum:
      name: 
      - pcre
      - pcre-devel
      - net-snmp
      - net-snmp-devel
      - libssh2-devel
      - libevent-devel
      - libevent
      - curl
      - curl-devel
      - perl-DBI
      - gcc
      - make
      state: present

#groupadd zabbix
#useradd -M -s /sbin/nologin -g zabbix zabbix 
  - name: 创建组
    group:
      name: zabbix
      system: yes

  - name: 创建用户
    user:
      name: zabbix
      system: yes
      group: zabbix
      shell: /sbin/nologin
      state: present
      create_home: yes

# 下载
# wget -O zabbix-7.0.29.tar.gz https://cdn.zabbix.com/zabbix/sources/stable/7.0/zabbix-7.0.29.tar.gz
# wget https://cdn.zabbix.com/zabbix/sources/stable/7.0/zabbix-7.0.29.tar.gz.sha256
# 3. 校验:-c 读取 sha256 文件里的值,和同名文件比对,输出 OK 即通过
# printf '%s  %s\n' "$(cat zabbix-7.0.29.tar.gz.sha256)" "zabbix-7.0.29.tar.gz" | sha256sum -c - 

  - name: 下载源码包
    get_url:
      url: https://cdn.zabbix.com/zabbix/sources/stable/7.0/zabbix-7.0.29.tar.gz
      dest: /root/zabbix-7.0.29.tar.gz
      checksum: "sha256:https://cdn.zabbix.com/zabbix/sources/stable/7.0/zabbix-7.0.29.tar.gz.sha256"
      force: no
      timeout: 60

# 解压编译安装
# tar xf zabbix-7.0.29.tar.gz 
# 2. 配置
# cd zabbix-7.0.29
# ./configure --prefix=/usr/local/zabbix --enable-agent
# 3. 编译安装
# make && make install
  - name: 解压
    unarchive:
      remote_src: yes
      src: /root/zabbix-7.0.29.tar.gz
      dest: /usr/local
  - name: 配置编译参数
    shell: ./configure --prefix=/usr/local/zabbix --enable-agent
    args:
      chdir: /root    
  - name: 编译安装
    make:
      chdir: /root/zabbix-7.0.29
      target: install

# ln -s /usr/local/zabbix/bin/* /usr/local/bin/;ln -s /usr/local/zabbix/sbin/* /usr/local/sbin/
#  - name: 创建软链接
#    shell: ln -s /usr/local/zabbix/bin/* /usr/local/bin/ && ln -s /usr/local/zabbix/sbin/* /usr/local/sbin/
  - name: 创建软链接
    file:
      src: /usr/local/zabbix/bin/zabbix_get
      dest: /usr/local/bin/zabbix_get
      state: link
    file:
      src: /usr/local/zabbix/bin/zabbix_sender
      dest: /usr/local/bin/zabbix_sender
      state: link

# mkdir -p /usr/local/zabbix/etc/zabbix_agentd.conf.d
# mkdir /usr/local/zabbix/logs
# chown -R zabbix:zabbix /usr/local/zabbix/logs
  - name: 创建数据存放目录并授权1
    file:
      path: /usr/local/zabbix/etc/zabbix_agentd.conf.d
      owner: zabbix
      group: zabbix
      state: directory
  - name: 创建数据存放目录并授权2
    file:
      path: /usr/local/zabbix/logs
      owner: zabbix
      group: zabbix
      state: directory

# 修改配置文件
  - name: 复制zabbix配置文件
    copy:
      dest: /usr/local/zabbix/etc/zabbix_agentd.conf
      src: /root/zabbix_agentd.conf
      backup: yes
      owner: zabbix
      group: zabbix

# 写启动脚本
  - name: 写启动脚本
    copy:
      dest: /lib/systemd/system/zabbix-agent.service
      src: /root/zabbix-agent.service
      backup: yes

#  重新加载
  - name: 重新加载
    shell: systemctl daemon-reload

# 启动服务
  - name: 启动服务并设置开机自启动
    service: 
      name: zabbix-agent.service
      state: started
      enabled: yes