Ansible剧本、变量、判断、循环

文章目录

Ansible剧本与变量判断循环

  • playbook 剧本是由一个或多个"play"组成的列表

  • play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按

  • 事先编排的机制执行预定义的动作

  • Playbook 文件是采用YAML语言编写的

YAML语言

YAML官方网站:YAML 官方网站

Ansible官方文档:Ansible官方文档YAML语法

YAML:YAML Ain't Markup Language,即YAML不是标记语言。不过,在开发的这种语言时,YAML的

意思其实是:"Yet Another Markup Language"(仍是一种标记语言)YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者,目前很多最新的软件比较流行采用此格式的文件存放配置信息,如:ubuntu,anisble,docker,kubernetes等

YAML语法简介

  • 在单一文件第一行,用连续三个连字号"-" 开始,还有选择性的连续三个点号( ... )用来表示文件的结尾

  • 次行开始正常写Playbook的内容,一般建议写明该Playbook的功能

  • 使用#号注释代码

  • 缩进必须是统一的,不能空格和tab混用

  • 缩进的级别也必须是一致的,同样的缩进代表同样的级别,程序判别配置的级别是通过缩进结合换行来实现的

  • YAML文件内容是区别大小写的,key/value的值均需大小写敏感

  • 多个key/value可同行写也可换行写,同行使用,分隔

  • key后面冒号要加一个空格 比如: key: value

  • value可是个字符串,也可是另一个列表

  • YAML文件扩展名通常为yml或yaml

支持的数据类型

YAML 支持以下常用几种数据类型:

  • 标量:单个的、不可再分的值

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)

  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)

scalar

key对应value

shell 复制代码
name: csq
age: 18

使用缩进的方式

shell 复制代码
name:
   csq
age:
   18

标量是最基本的,不可再分的值,包括:

  • 字符串

  • 布尔值

  • 整数

  • 浮点数

  • Null

  • 时间

  • 日期

字典

字典由多个key与value构成,key和value之间用 :分隔, 并且 : 后面有一个空格,所有k/v可以放在一行,或者每个 k/v 分别放在不同行

shell 复制代码
account: { name: csq, age: 18 }

使用缩进方式

shell 复制代码
account:
   name: csq
   age: 18

范例

shell 复制代码
#不同行
name: Example Developer
job: Developer
skill: Elite(社会精英)

#同一行,也可以将key:value放置于{}中进行表示,用,分隔多个key:value
{name: "Example Developer", job: "Developer", skill: "Elite"}

List列表

列表由多个元素组成,每个元素放在不同行,且元素前均使用"-"打头,并且 - 后有一个空格, 或者将所有元素用 [ ] 括起来放在同一行

格式

shell 复制代码
course: [ linux , golang , python ]

也可与写成以-开头的多行

shell 复制代码
course:
   - linux
   - golang
   - python

数据里面也可以包含字典

shell 复制代码
course:
   - linux: csq
   - golang: buhui
   - python: buhui

范例

shell 复制代码
#不同行,行以-开头,后面有一个空格
- Apple
- Orange
- Strawberry
- Mango
#同一行
[Apple,Orange,Strawberry,Mango]

yaml文件中的"|"和">" 符号

| 控制符

| 这个控制符的作用是保留文本每一行尾部的换行符。

|会保证整段文本最后有且只有一个换行符;使用|+可以保留整段文本最后的所有换行符;使用|-可以删除整段文本最后的所有换行符。

yaml 复制代码
# --------"|"示例begin--------
# YAML格式
key: |
  a
  b
  c
 
 
nextKey: ...
# 实际效果
"key": "a\nb\nc\n"
# ---------"|"示例end---------
 
 
# --------"|+"示例begin--------
# YAML格式
key: |+
  a
  b
  c
   
  
nextKey: ...
# 实际效果
"key": "a\nb\nc\n\n\n"
# ---------"|+"示例end---------
 
 
# --------"|-"示例begin--------
# YAML格式
key: |-
  a
  b
  c
   
  
nextKey: ...
# 实际效果
"key": "a\nb\nc"
# ---------"|-"示例end---------

>控制符

>这个控制符的作用是将每一行尾部的换行符替换为空格,也就是将多行文本视为一行。

>会保证文本最后有且只有一个换行符。使用>+可以保留文本最后的所有换行符,使用>-可以删除文本最后的所有换行符。

shell 复制代码
# --------">"示例begin--------
# YAML格式
key: >
  a
  b
  c
 
 
nextKey: ...
# 实际效果
"key": "a b c\n"
# ---------">"示例end---------
 
# --------">+"示例begin--------
# YAML格式
key: >+
  a
  b
  c
   
  
nextKey: ...
# 实际效果
"key": "a b c\n\n\n"
# ---------">+"示例end---------
 
# --------">-"示例begin--------
# YAML格式
key: >-
  a
  b
  c
   
  
nextKey: ...
# 实际效果
"key": "a\nb\nc"
# ---------">-"示例end---------

三种常见的数据格式

yaml转json:https://www.bejson.com/json/json2yaml/

  • XML:Extensible Markup Language,可扩展标记语言,可用于数据交换和配置

  • JSON:JavaScript Object Notation, JavaScript 对象表记法,主要用来数据交换或配置,不支持注释

  • YAML:YAML Ain't Markup Language YAML 不是一种标记语言, 主要用来配置,大小写敏感,不支持tab

Palybook核心组件

Playbook核心组件官方文档:https://docs.ansible.com/projects/ansible/latest/reference_appendices/playbooks_keywords.html

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

  • Hosts 执行的远程主机列表

  • Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最少元素需包括 name 和 task,一个name只能包括一个task

  • Variables 内置变量或自定义变量在playbook中调用

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

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

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

核心组件 说明
tasks Playbook 中要执行的具体任务列表(比如安装软件、修改配置等),是 Playbook 的核心内容。
vars 存储变量的集合(键值对形式),任务中可通过"{{ 变量名 }}"调用这些变量。
vars_files 需要导入的外部变量文件列表(将变量单独存放在文件中,便于管理和复用)。
roles 要引入的 "角色" 列表(角色是预定义的任务、变量、模板等的集合,用于简化复杂场景)。
remote_user 登录目标主机时使用的用户名(通过连接插件,如 SSH,登录并执行任务)。
name 用于标识 Playbook 或任务的名称,便于文档说明和执行结果中区分不同部分。
hosts 目标主机或主机组的列表(指定 Playbook 要在哪些主机上执行,支持组名、主机名或模式)。
gather_facts 布尔值(true/false),控制是否自动收集目标主机的事实信息(如主机属性、系统信息等)。
become 布尔值(true/false),控制执行任务时是否需要权限提升(如切换到 root 用户执行)。
ignore_errors 利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它task
handlers 包含被视为处理程序的任务的部分,这些任务不会正常执行,只有在任务的每个部分完成后收到通知时才会执行。(搭配notify使用)
notify 当任务返回"changed=True"状态时要通知的处理程序列表(搭配handlers使用)
tags 应用于任务或包含任务的标签,这允许从命令行中选择任务的子集

利用playbook部署tomcat

shell 复制代码
#部署tomcat
- hosts: web
  tasks:
    - name: 安装jdk11
      yum:
        name: java-11-openjdk
        state: present
    - name: 分发tomcat
      unarchive:
        src: /download/apache-tomcat-9.0.112.tar.gz
        dest: /usr/local/
    - name: 设置软链接简化路径
      file:
        src: /usr/local/apache-tomcat-9.0.112
        path: /usr/local/tomcat
        state: link
    - name: 分发systemctl文件
      copy:
        src: /lib/systemd/system/tomcat.service
        dest: /lib/systemd/system/tomcat.service
    - name: 启动tomcat服务
      systemd:
        name: tomcat
        state: started
        daemon_reload: true
        enabled: true

利用playbook部署nginx

shell 复制代码
- hosts: web
  tasks:
    - name: 配置yum源
      yum_repository:
        name: nginx-last-packages
        description: nginx-last-packages
        baseurl: http://nginx.org/packages/centos/8/$basearch/
        enabled: true
        gpgcheck: false
    - name: 清除缓存
      shell: yum clean packages
    - name: 安装nginx
      yum:
        name: nginx
        state: latest
    - name: 配置nginx用户组
      group:
        name: ansible-www
        gid: 3999
    - name: 配置nginx用户
      user:
        name: ansible-www
        uid: 3999
        group: ansible-www
        create_home: true
        shell: /sbin/nologin
    - name: 修改nginx主配置文件
      lineinfile:
        path: /etc/nginx/nginx.conf
        regexp: '^user'
        line: "user ansible-www;"
    - name: 配置nginx站点目录配置文件
      copy:
        src: ./bird.conf
        dest: /etc/nginx/conf.d/bird.conf
    - name: 创建nginx站点目录
      file:
        path: /app/code/bird/
        state: directory
    - name: 复制站点压缩包到远程主机/app/code/并解压
      unarchive:
        src: ./bird.tar.gz
        dest: /app/code/bird/
        remote_src: false
    - name: 启动nginx
      systemd:
        name: nginx
        state: started

利用playbook部署rsync

shell 复制代码
#部署rsync
- hosts: nfs01
  tasks:
    - name: 安装rsync
      yum:
        name: rsync
        state: present
    - name: 修改配置文件
      copy:
        src: ./rsyncd.conf
        dest: /etc/rsyncd.conf
        backup: true
    - name: 添加rsync用户
      user:
        name: rsync
        create_home: false
        shell: /sbin/nologin
        system: true
    - name: 创建密码文件,并写入密码
      lineinfile:
        path: /etc/rsync.password
        line: rsync_backup:Abc@1234
        create: true
        mode: 0600
    - name: 创建共享目录
      file:
        path: /backup
        state: directory
        owner: rsync
        group: rsync
    - name: 启动rsync服务
      systemd:
        name: rsyncd
        state: restarted
        enabled: true

利用playbook修改用户密码

shell 复制代码
- hosts: web
  tasks:
    - name: "开始修改用户密码"
      user:
        name: csq
        password: "{{ 'Abc@1234csq' | password_hash('sha512','hehedahehda') }}"
        state: present

Playbook中使用变量

ansible定义变量方法 说明
palybook中定义 在剧本中创建与使用,仅限于当前play部分使用.vars
独立文件中定义(变量文件) 把写入变量到文件中,通过vars_files指定调取.play中指定变量文件
分组变量 推荐,根据分组自动调用.all组创建与使用.最方便(group_vars)
Facts变量(远程主机的系统变量) 剧本运行的时默认的任务,收集信息,根据信息创建变量 如果不用,建议关闭功能.加速
register变量 类似于shell中````功能,先执行命令结果保留下来
主机清单变量 批量修改主机名。批量修改密码(每台机器都不同)
命令行传递参数 使用ansible-playbook -e "hostname=csq user=root"传递参数
ansible魔法变量 不用加载Facts变量就可使用 hostvars:每个主机详细信息 groups:显示当前主机所属的组 group_names:列出当前主机所在的主机组名称 inventory_hostname:显示当前主机的主机名

palybook中定义vars

shell 复制代码
- hosts: web
  vars:  #通过vars定义变量
    - username: csq
    - password: Abc@1234csq
  tasks:
    - name: "打印修改参数"
      debug:
        msg: "用户名: {{ username }} 密码: {{ password }}"
    - name: "开始修改用户密码"
      user:
        name: csq
        password: "{{ 'password' | password_hash('sha512','hehedahehda') }}"
        state: present

独立文件中定义(变量文件)

shell 复制代码
[root@m01 /server/ansible]# cat vars.yaml 
username: ansible-www
uid_gid: 3999
nginx_dir: /app/code/bird/
nginx_conf: /etc/nginx/conf.d/
[root@m01 /server/ansible]# cat 04-modify-nginx-install.yaml 
#部署nginx
- hosts: web
  vars_files: ./vars.yaml  #在此处定义变量文件
  tasks:
    - name: 配置yum源
      yum_repository:
        name: nginx-last-packages
        description: nginx-last-packages
        baseurl: http://nginx.org/packages/centos/8/$basearch/
        enabled: true
        gpgcheck: false
    - name: 清除缓存
      shell: yum clean packages
    - name: 安装nginx
      yum:
        name: nginx
        state: latest
    - name: 配置nginx用户组
      group:
        name: "{{ username }}"
        gid: "{{ uid_gid }}"
    - name: 配置nginx用户
      user:
        name: "{{ username }}"
        uid: "{{ uid_gid }}"
        group: "{{ username }}"
        create_home: true
        shell: /sbin/nologin
    - name: 修改nginx主配置文件
      lineinfile:
        path: /etc/nginx/nginx.conf
        regexp: '^user'
        line: "user {{ username }};"
    - name: 配置nginx站点目录配置文件
      copy:
        src: ./bird.conf
        dest: "{{ nginx_conf }}/bird.conf"
    - name: 创建nginx站点目录
      file:
        path: "{{ nginx_dir  }}"
        state: directory
    - name: 复制站点压缩包到远程主机/app/code/并解压
      unarchive:
        src: ./bird.tar.gz
        dest: "{{ nginx_dir  }}"
        remote_src: false
    - name: 启动nginx
      systemd:
        name: nginx
        state: restarted

group_vars分组变量

shell 复制代码
[root@m01 /server/ansible]# tree group_vars/
group_vars/
└── all
    └── vars.yaml
[root@m01 /server/ansible]# cat 04-modify-nginx-install.yaml 
#部署nginx
- hosts: web    #不用添加变量文件,自动识别
  tasks:
    - name: 配置yum源
      yum_repository:
        name: nginx-last-packages
        description: nginx-last-packages
        baseurl: http://nginx.org/packages/centos/8/$basearch/
        enabled: true
        gpgcheck: false
    - name: 清除缓存
      shell: yum clean packages
    - name: 安装nginx
      yum:
        name: nginx
        state: latest
    - name: 配置nginx用户组
      group:
        name: "{{ username }}"
        gid: "{{ uid_gid }}"
    - name: 配置nginx用户
      user:
        name: "{{ username }}"
        uid: "{{ uid_gid }}"
        group: "{{ username }}"
        create_home: true
        shell: /sbin/nologin
    - name: 修改nginx主配置文件
      lineinfile:
        path: /etc/nginx/nginx.conf
        regexp: '^user'
        line: "user {{ username }};"
    - name: 配置nginx站点目录配置文件
      copy:
        src: ./bird.conf
        dest: "{{ nginx_conf }}/bird.conf"
    - name: 创建nginx站点目录
      file:
        path: "{{ nginx_dir  }}"
        state: directory
    - name: 复制站点压缩包到远程主机/app/code/并解压
      unarchive:
        src: ./bird.tar.gz
        dest: "{{ nginx_dir  }}"
        remote_src: false
    - name: 启动nginx
      systemd:
        name: nginx
        state: restarted

Facts变量(远程主机的系统变量)

facts变量,运行剧本的时候,默认所有节点的fact变量的任务

  • 如果需要直接使用,主机名字,发行版本
  • 不需要则关闭,建议全局是关闭,使用的时候再去开启
shell 复制代码
#在ansible.cfg配置文件中[defaults]添加
gathering=explicit
#常见的fact变量使用
主机名: "{{ ansible_hostname }}"
所有有ip: "{{ ansible_all_ipv4_addresses }}"
内存总大小: "{{ ansible_memtotal_mb }}"
系统发行版本: "{{ ansible_distribution }}"
系统版本: "{{ ansible_distribution_major_version }}"
cpu架构: "{{ ansible_architecture }}"
系统版本昵称: "{{ ansible_distribution_release }}"
第1块网卡的ip地址: "{{ ansible_default_ipv4.address }}"

范例:打印Facts变量(通过setup模块)

shell 复制代码
[root@m01 /server/ansible]# ansible nfs01 -m setup
10.0.0.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "172.16.1.102",
            "10.0.0.102"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::5af3:9a3d:a6fd:ddff",
            "fe80::84d:ff1a:2696:841d",
            "fe80::f51d:e68f:f840:24af",
            "fe80::eb8b:46e3:add2:d0d7",
            "fe80::4454:49bf:ea82:21e1",
            "fe80::a39d:5c8f:f395:7339"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "11/12/2020",
        "ansible_bios_vendor": "Phoenix Technologies LTD",
        "ansible_bios_version": "6.00",
        "ansible_board_asset_tag": "NA",
        "ansible_board_name": "440BX Desktop Reference Platform",
        "ansible_board_serial": "None",
        "ansible_board_vendor": "Intel Corporation",
        "ansible_board_version": "None",
        "ansible_chassis_asset_tag": "No Asset Tag",
        "ansible_chassis_serial": "None",
        "ansible_chassis_vendor": "No Enclosure",
        "ansible_chassis_version": "N/A",
        "ansible_cmdline": {
            "BOOT_IMAGE": "/vmlinuz-4.19.90-52.22.v2207.ky10.x86_64",
            "audit": "0",
            "quiet": true,
            "rd.lvm.lv": "klas/swap",
            "resume": "/dev/mapper/klas-swap",
            "rhgb": true,
            "ro": true,
            "root": "/dev/mapper/klas-root"
        },
        "ansible_date_time": {
            "date": "2025-11-12",
            "day": "12",
            "epoch": "1762937751",
            "hour": "16",
            "iso8601": "2025-11-12T08:55:51Z",
            "iso8601_basic": "20251112T165551888691",
            "iso8601_basic_short": "20251112T165551",
            "iso8601_micro": "2025-11-12T08:55:51.888691Z",
            "minute": "55",
            "month": "11",
            "second": "51",
            "time": "16:55:51",
            "tz": "CST",
            "tz_dst": "CST",
            "tz_offset": "+0800",
            "weekday": "星期三",
            "weekday_number": "3",
            "weeknumber": "45",
            "year": "2025"
        },
        "ansible_default_ipv4": {
            "address": "10.0.0.102",
            "alias": "ens33",
            "broadcast": "10.0.0.255",
            "gateway": "10.0.0.2",
            "interface": "ens33",
            "macaddress": "00:50:56:2d:c8:b7",
            "mtu": 1500,
            "netmask": "255.255.255.0",
            "network": "10.0.0.0",
            "type": "ether"
        },
.....
.....
.....

template中使用Facts变量

在palybook中调用Facts变量

shell 复制代码
#使用jinja2模板中的变量分发motd
[root@m01 /server/ansible]# cat motd.j2 
主机名: {{ ansible_hostname }}
所有ip: {{ ansible_all_ipv4_addresses }}
内存总大小: {{ansible_memtotal_mb}}
系统发行版本: {{ansible_distribution}}
系统版本:  {{ansible_distribution_major_version }}
cpu架构: {{ ansible_architecture }}
系统版本昵称: {{ ansible_distribution_release }}
第1块网卡的ip地址: {{ ansible_default_ipv4.address }}
#playbook
---
- hosts: all
  gather_facts: true
  tasks:
    - name: test
      debug:
        msg: |
          主机名: {{ ansible_hostname }}
          所有ip: {{ ansible_all_ipv4_addresses }}
          内存总大小: {{ansible_memtotal_mb}}
          系统发行版本: {{ansible_distribution}}
          系统版本:  {{ansible_distribution_major_version }}
          cpu架构: {{ ansible_architecture }}
          系统版本昵称: {{ ansible_distribution_release }}
          第1块网卡的ip地址: {{ ansible_default_ipv4.address }}
          系统版本: {{ ansible_os_family }}
    - name: 分发motd
      template:
        src: motd.j2
        dest: /etc/motd

把运行结果当作变量使用(register变量)

在playbook中可以使用register将捕获命令的输出保存在临时变量中,然后使用debug模块进行显示输

范例:register变量输出形式

shell 复制代码
#playbook
- hosts: nfs01
  tasks:
    - name: get hostname
      shell: hostname
      register: name

    - name: print hostname
      debug:
        msg: "{{name}}"
#执行playbook
[root@m01 /server/ansible]# ansible-playbook -i /etc/ansible/hosts test.yaml
PLAY [nfs01] ************************************************************************************************************************************************************************

TASK [get hostname] *****************************************************************************************************************************************************************
changed: [10.0.0.102]

TASK [print hostname] ***************************************************************************************************************************************************************
ok: [10.0.0.102] => {
    "msg": {
        "changed": true,
        "cmd": "hostname",
        "delta": "0:00:00.001587",
        "end": "2025-11-13 09:00:27.204286",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2025-11-13 09:00:27.202699",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "nfs1",
        "stdout_lines": [
            "nfs1"
        ]
    }
}

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

范例:利用debug模块输出变量

shell 复制代码
- hosts: nfs01
  tasks:
    - name: get hostname
      shell: hostname
      register: name

    - name: print hostname
      debug:
        msg: |
          输出register注册的name变量的全部信息: "{{ name }}"
          显示命令的输出结果为字符串形式: "{{ name.stdout }}"
          显示命令: "{{ name.cmd }}"
          显示命令成功与否: "{{ name.rc }}"
          显示命令的输出结果为列表形式: "{{ name.stdout_lines }}"
          显示命令的输出结果的列表中的第一个元素: "{{ name.stdout_lines[0] }}"
          显示命令的执行结果为列表形式: "{{ name['stdout_lines'] }}"

范例:使用register创建IP命名的目录

shell 复制代码
#类似于shell中 ip=`hostname -I` 反引号功能
#创建以远程主机IP命名的目录
- hosts: all
  tasks:
    - name: 创建IP变量
      shell: hostname -I | awk '{print $1}'
      register: name
    - name: 创建以IP命名的目录
      file:
        path: "/tmp/{{name.stdout}}"
        state: directory

主机清单变量

shell 复制代码
#主机清单文件
[root@m01 /server/ansible]# cat /etc/ansible/hosts 
[nfs01]
10.0.0.102 hostname=nfs01
[by01]
10.0.0.110
[web]
10.0.0.10[3:4]
10.0.0.10[8:9]
[db01]
10.0.0.105


#编写playbook
---
- hosts: nfs01
  tasks:
    - name: 修改主机名
      hostname:
        name: "{{ hostname }}"
        use: systemd
    - name: 打印主机名
      debug:
        msg: "主机名为: {{hostname}}"

使用变量部署服务

利用playbook部署mysql

shell 复制代码
#1.创建分组变量目录db01
mkdir -p group_vars/db01
#2.使用group_vars分组变量
cat > group_vars/db01/vars.yaml <<EOF
mysql_tools: ["ncurses-devel","libaio-devel","openssl-devel","wget"]
mysql_user: mysql
mysql_password: Abc@1234
EOF
#3.编写palybook
[root@m01 /server/ansible]# cat 07-installmysql.yaml 
#mysql部署
- hosts: db01
  tasks:
    - name: "二进制安装{{ mysql_user }}8.4依赖"
      yum:
        name: "{{ item }}"
        state: present
      loop: "{{ mysql_tools }}"
    - name: "分发{{ mysql_user }}二进制8.4压缩包"
      unarchive:
        src: ./mysql-8.4.6-linux-glibc2.28-x86_64.tar.xz
        dest: /usr/local/
    - name: "设置{{ mysql_user }}虚拟用户"
      user:
        name: "{{ mysql_user }}"
        shell: /sbin/nologin
        create_home: false
        system: true
    - name: "设置{{ mysql_user }}根目录软链接"
      file:
        src: /usr/local/mysql-8.4.6-linux-glibc2.28-x86_64
        path: /usr/local/mysql
        state: link
    - name: "设置{{ mysql_user }}根目录权限"
      file:
        path: /usr/local/mysql/
        state: directory
        owner: "{{ mysql_user }}"
        group: "{{ mysql_user }}"
        recurse: true
    - name: "分发{{ mysql_user }}配置文件"
      copy:
        src: my.cnf
        dest: /etc/my.cnf
        owner: "{{ mysql_user }}"
        group: "{{ mysql_user }}"
    - name: "创建数据目录"
      file:
        name: /usr/local/data/3306
        state: directory
        owner: "{{ mysql_user }}"
        group: "{{ mysql_user }}"
    - name: "配置PATH环境变量"
      lineinfile:
        path: /etc/profile
        line: 'export PATH=${PATH}:/usr/local/mysql/bin'
    - name: "初始化数据库"
      shell: /usr/local/mysql/bin/mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/data/3306/
    - name: "分发mysql8.4启动服务文件"
      copy:
        src: ./mysqld.service
        dest: /lib/systemd/system/mysqld.service
    - name: "启动mysql8.4"
      systemd:
        name: mysqld
        enabled: true
        state: restarted
    - name: "设置mysql密码"
      shell: /usr/local/mysql/bin/mysqladmin -uroot password '{{ mysql_password }}'

变量优先级

变量优先级官方文档:Ansible变量优先级

Playbook逻辑控制语句

条件判断语句when

when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试

when的比较运算符

运算符 说明 示例(假设 num=5
== 等于 when: num == 5
!= 不等于 when: num != 3
> 大于 when: num > 2
< 小于 when: num < 10
>= 大于等于 when: num >= 5
<= 小于等于 when: num <= 5

when的逻辑运算符

  • or:逻辑或,当左右和右边两个表达式任意一个为真,则返回真
  • and:逻辑与,当左边和右边两个表达式同时为真,则返回真
  • not:逻辑否,对表达式取反
  • ():当一组表达式组合在一起,形成一个更大的表达式,组合内的所有表达式都是逻辑与的关系

条件判断

  • is exists: 用于路径存在时返回真
  • is not exists: 用于路径不存在时返回真
  • 也可以在整个条件表达式的前面使用not来取反

正则过滤器

yaml 复制代码
变量 is match('正则表达式模式')

判断执行结果

  • succeeded:任务执行成功则返回true
  • failed:任务执行失败则返回true
  • changed:任务执行状态为changed则返回true
  • skipped:任务跳过则返回true

判断变量

  • defined:判断变量是否已定义,已定义则返回真
  • undefined:判断变量是否未定义,未定义则返回真
  • none:判断变量的值是否为空,如果变量已定义且值为空,则返回真

判断是否在集合

  • in: 用于检查一个元素是否在指定列表或集合中

范例1:使用when判断操作系统,不同操作系统安装不同软件

shell 复制代码
---
- hosts: all
  gather_facts: true
  tasks:
    - name: "kylin系统安装软件"
      yum:
        name: tree,telnet,nmap,nc
        state: latest
      when: ansible_distribution is match("Kylin")
    - name: "ubuntu系统安装软件"
      apt:
        name: lolcat,lrzsz,cmatrix
        state: latest
      when: ansible_distribution is match("Ubuntu")

范例2:failed_when配合检查功能,检查nginx配置文件语法问题,有问题直接报错,没问题继续往下执行

shell 复制代码
#部署nginx
- hosts: web
  tasks:
    - name: 配置yum源
      yum_repository:
        name: nginx-last-packages
        description: nginx-last-packages
        baseurl: http://nginx.org/packages/centos/8/$basearch/
        enabled: true
        gpgcheck: false
    - name: 清除缓存
      shell: yum clean packages
    - name: 安装nginx
      yum:
        name: nginx
        state: latest
    - name: 配置nginx用户组
      group:
        name: ansible-www
        gid: 3999
    - name: 配置nginx用户
      user:
        name: ansible-www
        uid: 3999
        group: ansible-www
        create_home: true
        shell: /sbin/nologin
    - name: 修改nginx主配置文件
      lineinfile:
        path: /etc/nginx/nginx.conf
        regexp: '^user'
        line: "user ansible-www;"
    - name: 配置nginx站点目录配置文件
      copy:
        src: ./bird.conf
        dest: /etc/nginx/conf.d/bird.conf
    - name: 创建nginx站点目录
      file:
        path: /app/code/bird/
        state: directory
    - name: 复制站点压缩包到远程主机/app/code/并解压
      unarchive:
        src: ./bird.tar.gz
        dest: /app/code/bird/
        remote_src: false
    - name: check nginx
      shell: nginx -t
      register: check_nginx_conf
      failed_when: check_nginx_conf.rc != 0      #如果返回值为非0就不往下执行任务
    - name: 启动nginx
      systemd:
        name: nginx
        state: started

loop循环

对循环ansible有固定内置变量名为"item"

要在task中使用loop(with_items)给定要迭代的元素列表

列表元素格式:

  • 字符串

  • 字典

批量添加用户设置密码,批量创建目录

shell 复制代码
- hosts: web
  tasks:
    - name: "批量创建目录"
      file:
        path: "{{ item }}"
        state: directory
      loop:   
        - '/tmp/csq'           #字符串元素
        - '/tmp/zhw'           #字符串元素
        - '/tmp/hehe'          #字符串元素
        - '/tmp/heheda'        #字符串元素
    - name: "批量创建用户设置密码"#字符串元素
      user:
        name: "{{ item.username }}"
        uid: "{{ item.uid }}"
        password: "{{ item.password | password_hash('sha512','cfcfcfhehehddd') }}"
      loop:
        - { username: "csq", uid: "3091",password: "Abc@1234csq" }   #字典元素
        - { username: "zhw", uid: "3092",password: "Abc@1234zhw" }   #字典元素
        - { username: "xbzz", uid: "3093",password: "Abc@1234xbzz" } #字典元素
        - { username: "byd", uid: "3094",password: "Abc@1234byd" }   #字典元素

Block块

当想在满足一个条件下,执行多个任务时,就需要分组了。而不再每个任务都是用when

shell 复制代码
- hosts: test2
  remote_user: root
  tasks:
  - block:
     - name: install httpd memcached
       yum: name={{ item }} state=installed
       with_items:
        - httpd
        - memcached
     - template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
     - service: name=httpd state=started enabled=true
    when: ansible_distribution is match ("Kylin")  # 当系统为CentOS才会执行上面的block

处理异常也会很方便

rescue关键字在任务执行过程中捕获错误,并执行指定的任务

always关键字定义的任务始终会被执行,不管前面的任务执行成功还是失败

shell 复制代码
- hosts: test2
  remote_user: root
  tasks:
  - block:
    - debug: msg="i execute normally"    # 失败不会执行
    - command: /bin/false   
    - debug: msg="i never execute,cause ERROR" 
    
    rescue:
    - debug: msg='I caught an error'  # 捕获错误但是最后还会执行
    - command: /bin/false
    - debug: msg="I also never execute"
    
    always:
    - debug: msg="this always executes" # 不管前面的任务执行成功还是失败都会执行

template模板

模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja2语法

jinja2语言

Jinja 是一款快速、富有表现力且可扩展的模板引擎。特别 模板中的占位符允许编写与 Python 相似的代码 语法。然后通过模板数据来渲染最终文档

官方文档:https://jinja.palletsprojects.com/en/stable/

jinja2 语言支持多种数据类型和操作

  • 字面量,如: 字符串:使用单引号或双引号,数字:整数,浮点数

  • 列表:[item1, item2, ...]

  • 元组:(item1, item2, ...)

  • 字典:{key1:value1, key2:value2, ...}

  • 布尔型:true/false

  • 算术运算:+, -, *, /, //, %, **

  • 比较操作:==, !=, >, >=, <, <=

  • 逻辑运算:and,or,not

  • 流表达式:For,If,When

算术运算

  • +:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2

  • -:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1

  • /:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 0.5

  • //:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2

  • %:计算整数除法的余数。 {{ 11 % 7 }} 等于 4

  • *:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ '=' * 80 }} 会打印 80 个等号的横条\

  • **:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8

比较操作符

  • == 比较两个对象是否相等

  • != 比较两个对象是否不等

  • > 如果左边大于右边,返回 true

  • >= 如果左边大于等于右边,返回 true

  • < 如果左边小于右边,返回 true

  • <= 如果左边小于等于右边,返回 true

逻辑运算符

  • 对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式

  • and 如果左操作数和右操作数同为真,返回 true

  • or 如果左操作数和右操作数有一个为真,返回 true

  • not 对一个表达式取反

  • (expr)表达式组

  • true / false true 永远是 true ,而 false 始终是 false

template中使用流程控制for和if

template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

for循环

格式

shell 复制代码
{% for i in EXPR %}
 ...
{% endfor %}
示例:
{% for i in range(1,10) %}
 server_name web{{i}};
{% endfor %}

if条件判断

在模版文件中还可以使用 if条件判断,决定是否生成相关的配置信息

shell 复制代码
{% if 条件表达式 %}
  # 条件为 true 时生成的内容
{% elif 另一个条件表达式 %}
  # 第一个条件为 false,第二个条件为 true 时生成的内容
{% else %}
  # 所有条件都为 false 时生成的内容
{% endif %}

template

template功能:可以根据和参考模块文件,动态生成相类似的配置文件

template文件必须存放于templates目录下,且命名为 .j2 结尾

yaml/yml 文件需和templates目录平级

jinja2-判断-分发keepalived的配置文件

jinja2-判断-分发keepalived的配置文件

方法1:分别准备2个文件,分发到lb01,lb02

方法2:分发1个文件,配置文件中使用jinja2的判断

shell 复制代码
global_defs {
    router_id lb01  #lb01或lb02 判断
}
vrrp_instance vir_3 {
    state MASTER  #MASTER BACKUP
    priority 100  #100 50
    interface ens33
    virtual_router_id 51

    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.3 dev ens33 label ens33:0
    }
}

方法2

shell 复制代码
#keepalived.conf.j2
! Configuration File for keepalived

global_defs {
    router_id {{ansible_hostname}}
}
vrrp_instance lb_vip_3 {
{% if ansible_hostname is match('lb01') %}
    state  MASTER
    priority 100
{% elif ansible_hostname is match('lb02') %}
    state  BACKUP
    priority 50
{% endif %}

    interface ens33
    virtual_router_id 51
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.3/24 dev ens33  label ens33:1
    }

}
#playbook
- hosts: web
  gather_facts: true
  tasks:
    - name: "分发配置文件"
      template:
        src: keepalived.conf.j2
        dest: /tmp/keepalived.conf
        
#结果
ansible lb -m shell -a "cat /tmp/keepalived.conf
#lb02
10.0.0.107 | CHANGED | rc=0 >>
! Configuration File for keepalived

global_defs {
    router_id lb02
}
vrrp_instance lb_vip_3 {
    state  BACKUP
    priority 50

    interface ens33
    virtual_router_id 51
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.3/24 dev ens33  label ens33:1
    }

}
#lb01
10.0.0.106 | CHANGED | rc=0 >>
! Configuration File for keepalived

global_defs {
    router_id lb01
}
vrrp_instance lb_vip_3 {
    state  MASTER
    priority 100

    interface ens33
    virtual_router_id 51
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        10.0.0.3/24 dev ens33  label ens33:1
    }

}

循环

使用jinja2循环nfs配置文件

shell 复制代码
#1.生成目标
/nfsdata 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)
/share 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)
/private 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)

#2.变量在group_vars/all/vars.yaml文件中定义列表变量
nfs_dirs:
  - /nfsdata
  - /share
  - /private
#3.生成jinja2模板exports.j2
{% for dir in nfs_dirs %}
#nfs服务端目录 {{ dir }}
{{dir}} 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)
{% endfor %}

#4.编写playbook
- hosts: nfs01
  tasks:
    - name: "jinja2循环生成内容"
      template:
        src: exports.j2
        dest: /tmp/exports
        
#5.生成文件内容
ansible nfs01 -m shell -a "cat /tmp/exports"
10.0.0.102 | CHANGED | rc=0 >>
#nfs服务端目录 /nfsdata
/nfsdata 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)
#nfs服务端目录 /share
/share 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)
#nfs服务端目录 /private
/private 172.16.1.0/24(rw,all_squash,anonuid=2999,anongid=2999)

使用jinja2模板循环生成nginx配置文件(静态)

shell 复制代码
#1.生成目标
server {
	listen 80;
	server_name bird.chenshiquan.xyz;
	access_log /var/log/nginx/bird-access.log main;
	error_log /var/log/nginx/bird-error.log notice;
	root /app/code/bird/;
	location / {
		index index.html
	}
}
server {
	listen 80;
	server_name test.chenshiquan.cn;
	access_log /var/log/nginx/bird-access.log main;
	error_log /var/log/nginx/bird-error.log notice;
	root /app/code/bird/;
	location / {
		index index.html
	}
}
server {
	listen 80;
	server_name china.chenshiquan.cn;
	access_log /var/log/nginx/bird-access.log main;
	error_log /var/log/nginx/bird-error.log notice;
	root /app/code/bird/;
	location / {
		index index.html
	}
}
#2.变量在group_vars/all/vars.yaml文件中定义列表变量
sites:
  - bird
  - test
  - china
#3.生成jinja2模板nginx.conf.j2
server {
	listen 80;
	server_name {{item}}.chenshiquan.cn;
	access_log /var/log/nginx/{{item}}-access.log main;
	error_log /var/log/nginx/{{item}}-error.log notice;
	root /app/code/{{item}}/;
	location / {
		index index.html
	}
}
#4.编写playbook
---
- hosts:
  tasks:
    - name: "jinja2模板循环生成nginx配置文件"
      template:
        src: nginx.conf.j2
        dest: /tmp/{{item}}.chenshiquan.xyz.conf
      loop: "{{sites}}"
...
#5.生成结果
ansible web -m shell -a "cat /tmp/*.chenshiquan.xyz.conf"
10.0.0.104 | CHANGED | rc=0 >>
server {
	listen 80;
	server_name bird.chenshiquan.cn;
	access_log /var/log/nginx/bird-access.log main;
	error_log /var/log/nginx/bird-error.log notice;
	root /app/code/bird/;
	location / {
		index index.html
	}
}
server {
	listen 80;
	server_name china.chenshiquan.cn;
	access_log /var/log/nginx/china-access.log main;
	error_log /var/log/nginx/china-error.log notice;
	root /app/code/china/;
	location / {
		index index.html
	}
}
server {
	listen 80;
	server_name test.chenshiquan.cn;
	access_log /var/log/nginx/test-access.log main;
	error_log /var/log/nginx/test-error.log notice;
	root /app/code/test/;
	location / {
		index index.html
	}
}
10.0.0.103 | CHANGED | rc=0 >>
server {
	listen 80;
	server_name bird.chenshiquan.cn;
	access_log /var/log/nginx/bird-access.log main;
	error_log /var/log/nginx/bird-error.log notice;
	root /app/code/bird/;
	location / {
		index index.html
	}
}
server {
	listen 80;
	server_name china.chenshiquan.cn;
	access_log /var/log/nginx/china-access.log main;
	error_log /var/log/nginx/china-error.log notice;
	root /app/code/china/;
	location / {
		index index.html
	}
}
server {
	listen 80;
	server_name test.chenshiquan.cn;
	access_log /var/log/nginx/test-access.log main;
	error_log /var/log/nginx/test-error.log notice;
	root /app/code/test/;
	location / {
		index index.html
	}
}

使用jinja2模板循环配置rsync文件

shell 复制代码
#1.生成目标
....
....
[data]
comment = date by chenshiquan 14:18 2025-11-12
path = /data
[backup]
comment = backup by chenshiquan 14:18 2025-11-12
path = /backup
[blog]
comment = blog by chenshiquan 14:18 2025-11-12
path = /nfs/backup/blog
#2.变量在group_vars/all/vars.yaml文件中定义列表变量
rsync_dirs:
  - {name: "date",dir: "/data"}
  - {name: "backup",dir: "/backup"}
  - {name: "blog",dir: "/nfs/backup/blog"}
#3.生成jinja2模板rsyncd.conf.j2
{% for dir in rsync_dirs %}
[{{dir.name}}]
comment = {{dir.name}} by chenshiquan 14:18 2025-11-12
path = {{dir.dir}}
{% endfor %}
#4.编写playbook
---
- hosts: backup
  tasks:
    - name: "jinja2模板循环生成rsync配置文件"
      template:
        src: rsyncd.conf.j2
        dest: /tmp/rsyncd.conf
      loop: "{{rsync_dirs}}"
...
#5.生成结果
[date]
comment = date by chenshiquan 14:18 2025-11-12
path = /data
[backup]
comment = backup by chenshiquan 14:18 2025-11-12
path = /backup
[blog]
comment = blog by chenshiquan 14:18 2025-11-12
path = /nfs/backup/blog

环境变量

临时修改环境变量

shell 复制代码
#playbook
- hosts: localhost
  gather_facts: true
  tasks:
    - shell: echo $PATH
      environment:
        PATH: /usr/local/app/bin:{{ ansible_env.PATH }}
      register: path_result

    - debug:
        msg: "{{path_result}}"
#输出详解
[root@m01 /server/ansible]# ansible-playbook -i /etc/ansible/hosts test.yaml
......
......
TASK [debug] ************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": {
        "changed": true,
        "cmd": "echo $PATH",
        "delta": "0:00:00.001392",
        "end": "2025-11-13 08:37:17.431355",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2025-11-13 08:37:17.429963",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "/usr/local/app/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin",
        "stdout_lines": [
            "/usr/local/app/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin"
        ]
    }
}
......
......

changed_when/failed_when

关闭 changed 状态

当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态,可以通过changed_when: false 关闭changed状态

shell 复制代码
---
- hosts: web
  tasks:
    - name: "check sshd service"
      shell: ps aux | grep sshd
      changed_when: false

利用 changed_when/failed_when 检查task返回结果

changed_when /failed_when检查task返回结果,决定是否继续向下执行

changed_when

shell 复制代码
---
- hosts: web
  tasks:
    - name: install nginx
      yum:
        name: nginx
    - name: move template
      template:
        src: "nginx.conf.j2"
        dest: /etc/nginx/nginx.conf
      notify:
        - restart nginx
    - name:
      shell: /usr/sbin/nginx -t
      register: check_nginx_conf
      changed_when:
        - check_nginx_conf.stdout is match('successful')  #如果返回值正则匹配不是successful就不执行下面内容
    - name: start nginx
      systemd:
        name: nginx
        state: restarted
        enabled: true
- handlers:
  - name: restart nginx
    systemd:
      name: nginx
      state: restarted

failed_when

shell 复制代码
---
- hosts: web
  tasks:
    - name: install nginx
      yum:
        name: nginx
    - name: move template
      template:
        src: "nginx.conf.j2"
        dest: /etc/nginx/nginx.conf
      notify:
        - restart nginx
    - name:
      shell: /usr/sbin/nginx -t
      register: check_nginx_conf
      failed_when:
        - check_nginx_conf.rc != 0  #如果返回值为非0就不执行下面内容
    - name: start nginx
      systemd:
        name: nginx
        state: restarted
        enabled: true
- handlers:
  - name: restart nginx
    systemd:
      name: nginx
      state: restarted

滚动执行

默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial 关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

范例1:每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所有主机

shell 复制代码
---
- hosts: all
  serial: 2
  tasks:
    - name: task one
      command: hostname
    - name: task two
      command: hostname

范例2:每次只同时处理20%的主机

shell 复制代码
---
- hosts: all
  serial: "20%"
  tasks:
    - name: task one
      command: hostname
    - name: task two
      command: hostname

Playbook调试

命令调试功能

shell 复制代码
--syntax-check      #对 playbook 执行语法检查,但不执行它
-C                  #不要进行任何更改
-v 或 -vv 或 -vvv    #显示过程
--step              #一步一步:在运行前确认每个任务
--limit             #只针对主机列表中的特定主机执行

指定报错的机器运行Playbook

手动/自动指定错误机器

playbook执行任务,有部分主机执行失败,下次执行时怎么指定只在失败的主机上执行任务?

ansible retry重试

手动指定错误机器不依赖retry

shell 复制代码
#使用--limit host1,host2...
ansible-playbook test.yaml --limit nfs01,backup

自动指定错误机器

shell 复制代码
#需要修改ansible.cfg配置文件在[defaults]下修改
retry_files_enabled = True
retry_files_save_path = /ansible_retry/
#执行剧本制造失败
[root@m01 /server/ansible]# cat /ansible_retry/test.retry 
10.0.0.101
10.0.0.102
10.0.0.103
#下次修改错误后,指定错误机器即可
ansible-playbook test.yaml --limit @/ansible_retry/test.retry

委派至错误主机执行playbook

利用委托技术,可以在非当前被控主机的其它主机上执行指定操作

shell 复制代码
#playbook,在10.0.0.102上执行hostname -I 而非主机localhost
- hosts: localhost
  tasks:
    - name: show ip address
      command: hostname -I
      delegate_to: 10.0.0.102

TAGS标签

Ansible 标签用于在大型 playbook 中精准执行或跳过特定任务,核心流程分两步

  1. 将标签添加到任务中,可以单独添加,也可以从block、playbook、role或导入继承标签,实现对目标任务的标记。

  2. 运行 playbook 时选择或跳过标记

    • --tags指定要运行的标签(仅执行标记的任务)

    • --skip-tags指定要跳过的标签

    • --tags tagged指定要执行标记了标签的任务

    • --tags untagged指定要执行没有标记标签的任务

    • --tags all执行所有任务

    • 如果把标签的名字定义为always,那么always标签所对应的任务就始终会被执行

标签基本用法

shell 复制代码
#部署nginx的playbook,在其中指定标签
- hosts: web
  gather_facts: true
  vars:
  - ubuntu: nginx=1.28.0-1~jammy
  - kylin: nginx-1:1.28.0
  tasks:
    #ubuntu安装nginx
    - block:
      - name: ubuntu安装源依赖
        apt:
          name: curl,gnupg2,ca-certificates,lsb-release,ubuntu-keyring
          state: latest
          update_cache: true
      - name: ubuntu配置源密钥
        apt_key:
          url: https://nginx.org/keys/nginx_signing.key
          keyring: /usr/share/keyrings/nginx-archive-keyring.gpg
          state: present
      - name: ubntu配置源仓库
        apt_repository:
          repo: "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu jammy nginx"
          filename: nginx
          state: present
          update_cache: true
      - name: ubuntu安装nginx
        apt:
          name: "{{ubuntu}}"
          state: present
          update_cache: true
      tags:
        - install_ubuntu_nginx
      when: ansible_distribution is match("Ubuntu")
    #kylin安装nginx
    - block:
      - name: 配置kylin的yum源
        yum_repository:
          name: nginx-last-packages
          description: nginx-last-packages
          baseurl: http://nginx.org/packages/centos/8/$basearch/
          enabled: true
          gpgcheck: false
      - name: 清除缓存
        shell: yum clean packages
      - name: kylin安装nginx
        yum:
          name: "{{kylin}}"
          state: present
      tags:
        - install_kylin_nginx
      when: ansible_distribution is match("Kylin")
    - name: 配置nginx用户组
      group:
        name: ansible-www
        gid: 3999
      tags:
        - add_group
        - nginx_config
    - name: 配置nginx用户
      user:
        name: ansible-www
        uid: 3999
        group: ansible-www
        create_home: true
        shell: /sbin/nologin
      tags:
        - add_user
        - nginx_config

#1.执行的时候不带任何tag参数,那么会执行所有标签对应的任务
ansible-playbook 19testnginx.yaml
#2.如果指定执行部分安装的任务,则可利用关键字tags指定需要执行的任务
ansible-playbook  19testnginx.yaml --tags install_ubuntu_nginx
#3.如果指定不执行tag packages对应的任务,则可利用关键字skip-tags
ansible-playbook  19testnginx.yaml --skip-tags install_ubuntu_nginx

Playbook的handlers与notify

Handlers本质是任务列表,类似MySQL触发器的触发行为,其包含的任务与一般task无本质区别,用于关注的资源发生变化时执行操作;而Notify对应的action会在每个play最后触发,可避免多次变化时重复执行操作,仅在所有变化完成后一次性执行,且Notify中列出的操作即调用Handlers中定义的操作

  • 如果多个task通知了相同的handlers, 此handlers仅会在所有tasks结束后运行一 次。
  • 只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
  • handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handler跳过执行,可以使用force_handlers: yes 强制执行handler
shell 复制代码
#playbook
---
- hosts: web
  tasks:
    - name: "jinja2模板循环生成nginx配置文件"
      template:
        src: nginx.conf.j2
        dest: /tmp/{{item}}.chenshiquan.xyz.conf
      loop: "{{sites}}"
      notify:
        - restart nginx
  handlers:
    - name: "restart nginx"
      systemd:
        name: nginx
        state: restarted
...
#template模块会对比本地模板文件(nginx.conf.j2)与远程主机目标文件
#(/tmp/{{item}}.chenshiquan.xyz.conf)的内容

#若两者内容相同,template任务不会对目标文件做任何修改(任务状态为ok)
#此时notify不会触发,handlers中定义的restart nginx操作不会执行

#若两者内容不同,template任务会更新目标文件(任务状态为changed),此时notify会标记对应的handler
#在整个 play 执行结束后,触发handlers中的restart nginx操作,重启 nginx 服务

写playbook的原则

  • 尽量使用include和role避免重复代码
  • 尽量把大文件分成小的文件
  • 重要的一点:多练习(操千曲而后晓声,观千剑而后识器)
相关推荐
凤凰战士芭比Q13 小时前
Ansible(安装、配置文件、命令行、常用模块)
linux·ansible
早睡冠军候选人4 天前
Ansible学习----管理复杂的 Play 和 Playbook 内容
运维·学习·云原生·ansible
雨奔4 天前
ansible使用教程
ansible
凡间客5 天前
Ansible安装与入门
linux·运维·ansible
LoneEon5 天前
告别手动操作:用 Ansible 统一管理你的 Ubuntu 服务器集群
运维·服务器·ansible
Empty_7775 天前
Ansible之Playbook简单应用
网络·ansible
小任今晚几点睡5 天前
Ansible 基础配置与负载均衡部署实践
运维·自动化·ansible·负载均衡
一条懒鱼6665 天前
Ansible之Playbook简单应用
网络·ansible
Lynnxiaowen6 天前
今天我们开始学习ansible之playbook的简单运用
linux·运维·学习·云计算·ansible