Ansible基础:(三)playbook

admin 2022年09月25日 549次浏览

1、playbook简介

playbook 是由一个或多个 “play” 组成的列表,play 的主要功能在于把预定义的一组主机,装扮成事先通过 ansible 中的 task 定义好的角色。task 实际是调用 ansible 的一个模块,将多个 play 组织在一个 playbook 中,按照事先编排的机制执行预定义的动作。playbook 文件采用 YAML 语言编写

2、YAML语言

YAML 是一个高可读性,用来表达资料序列的格式,更多介绍参见:YAML官网

2.1、YAML语法简介

  • 在单一文件的第一行,用三个 “-” 开始
  • 第二行开始写 playbook 的内用,一般建议写 playbook 的功能介绍
  • 使用 “#” 注释代码
  • 严格缩进,不能空格和 tab 混用
  • 缩进的级别必须一致,同样的缩进代表形同的级别,程序判别配置的级别是通过缩进结合换行来实现的
  • YAML 文件内容区分大小写,key / value 的值均需大小写敏感
  • 多个 key / value 可以写在同一行,同行使用逗号(,)分隔
  • value 可以是一个字符串,也可以是一个列表
  • 一个完整的代码块功能,需要包括 name 和 task
  • 一个 name 只能包含一个 task
  • YAML 文件的扩展名一般为 yml 或 yaml

2.2、list列表

列表由多个元素组成

  • 定义列表

    # 使用 - 定义列表
    - apple
    - orange
    - mango
    
    # 使用 [] 定义列表
    [apple,orange,mango]
    

2.3、dictionary字典

字典由多个 key 和 value 组成

  • 定义字典

    name: wang
    age: 25
    job: dev
    children:
      - name: zhangsan
        age: 15
        job: it
      - name: wangwu
        age: 21
        job: dev
    
    {name:"wang",age:25,job:"dev"}
    

2.4、常见数据格式

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

    <servers>
        <server>
            <name>server1</name>
            <owner>user</owner>
            <passwd>123456</passwd>
        </server>
    </servers>
    
  • JSON:对象表记法,用于数据交换或配置,不支持注释

    {
        servers:
        [
            {
                name:server1
                owner:user
                passwd:123456
            }
        ]
    }
    
  • YMAL:主要用于配置

    servers:
    - name: server1
      owner: user
      passwd: 123456
    

3、playbook核心元素

  • hosts:需要执行任务的远程主机列表
  • tasks:任务集
  • variables:内置变量或自定义变量在 playbook 中调用
  • templates:模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • handlers 和 notify 结合使用,由特定条件触发的操作,满足条件即可执行,否则不执行
  • tags:标签,指定某条任务执行,用于选择运行 playbook 中的部分代码

3.1、playbook命令

  • 语法

    ansible-playbook <filename.yml> [选项]
    
  • 常用选项

    --check:只检测会发生的改变,不实际执行
    --list-hosts:列出需要执行任务的主机
    --list-tags:列出tag
    --list-tasks:列出task
    --limit <主机列表>:只针对主机列表中的主机执行
    
  • 使用示例

    # 检测playbook
    ansible-playbook --check install_httpd.yml
    
    # 执行playbook
    ansible-playbook install_httpd.yml
    
    # 只在特定主机上执行
    ansible-playbook install_httpd.yml --limit=192.168.137.11
    

3.2、hosts组件

hosts 主要用于指定需要执行任务的主机,需事先在主机清单中配置

- hosts:
  svr1
  192.168.137.12

3.3、remote_user组件

用于执行任务的用户,可用于 host 和 task 中,其可以用于 play 全局或某个任务

- hosts: svr1
  remote_user: root
  
  tasks: 
  - name: test ping
    ping:
    remote_user: root

3.4、task列表和action组件

paly 的主体部分是 taks 列表,task 列表中由一个或多个 task,各 task 按次序逐个在 hosts 中指定的所有主机上运行,等在所有主机上执行完第一个 task 后,才开始执行第二个 task
task 的目的是使用指定的参数执行模块,而且在模块参数中可以使用变量
每个 task 都应该有 name,用于 playbook 的执行结果输出,建议其内容能清晰的描述任务执行步骤;未提供 name,则 action 的结果将用于输出

3.4.1、task的两种格式

需要注意的是,在模块名称的冒号后面有一个空格

  • action:模块名 参数

  • 模块:参数(常用)

3.4.2、示例

---
- hosts: svr1
  remote_user: root
  # 不收集facts信息
  gather_facts: no

  tasks:
    - name: install httpd
      yum: name=httpd
    - name: start httpd
      service: name=httpd state=started enabled=yes

3.5、handlers与notify组件

handlers 本质上就是一个 task list,类似于 MySQL 中的触发器的触发行为,playbook 中的 task 和普通的 task 相同,唯独不同的是 notify 用于对关注的资源发生变化时,才会采取一定的动作。notify 对应的动作可用于在每个 play 的最后被触发,这样可以避免多次有发生改变时每次都执行指定的操作,而是仅在所有变化都完成后,一次性的执行指定操作

在 notify 中列出来的操作称之为 handler,其实就是 notify 调用 handler 中定义的操作(notify 中的名称必须和 handlers 中名称相同)

  • 示例

    ---
    - hosts: svr1
      remote_user: root
      gather_facts: no
    
      tasks:
        - name: install httpd
          yum: name=httpd
        - name: install configure file
          copy: src=/files/httpd.conf dest=/etc/httpd/conf/httpd.conf
          notify: restart httpd
        - name: start httpd
          service: name=httpd state=started enabled=yes
    
      handlers:
        - name: restart httpd
          service: name=httpd state=restarted
    

3.6、tags组件

在 playbook 文件中,可以利用 tags 组件,为特定 task 指定标签,当在执行 playbook 时,可以只执行特定的 task,而非整个 playbook 文件

  • 示例

    # YAML文件
    ---
    - hosts: svr1
      remote_user: root
      gather_facts: no
    
      tasks:
        - name: install httpd
          yum: name=httpd
        - name: install configure file
          copy: src=/files/httpd.conf dest=/etc/httpd/conf/httpd.conf
          notify: restart httpd
          tags: config
        - name: restart httpd
          service: name=httpd state=started enabled=yes
          tags: service
    
      handlers:
        - name: restart httpd
          service: name=httpd state=restarted
          
    # 执行指定tags
    ansible-playbook install_httpd.yml -t config,service
    

4、变量

4.1、定义变量

变量名只能由字母、数字、下划线组成,且只能以字母开头

  • 语法

    变量名=值
    
  • 示例

    http_port=80
    

4.2、变量调用

在 playbook 中,使用 {{ 变量名 }} 的方式来调用变量,且在变量名前后建议添加空格,有时需要使用 “ {{ 变量名 }} ” 的方式调用才会生效

4.3、变量定义方式

在所有变量定义方式中,在 playbook 命令行中定义的变量的优先级最高

4.3.1、使用setup模块中的变量

ansible 的 setup facts 远程主机上的所有变量都可以直接使用,但是只能在 playbook 中使用,不能使用 ansible 命令调用

需要注意的是,使用 setup 模块中的变量,不能将 gather_facts 禁用

# 创建var.yml变量文件
---
- hosts: all
  remote_user: root

  tasks:
    - name: create file
      file: name=/files/{{ ansible_nodename}}.txt state=touch
      
# 使用变量文件
ansible-playbook var.yml

4.3.2、在playbook命令行中定义变量

通过命令行指定变量,其优先级最高

# 创建var.yml变量文件
---
- hosts: all
  remote_user: root

  tasks:
    - name: install package
      yum: name={{ pkname }} state=present
      
# 定义变量
ansible-playbook -e pkname=httpd var.yml

4.3.3、在playbook文件中定义变量

---
- hosts: all
  remote_user: root
  vars:
    - username: user01
    - groupname: group01

  tasks:
    - name: create group
      group: name={{ groupname }} state=persent
    - name: create user
      user: name={{ username }} state=persent

4.3.4、使用变量文件

可以在一个独立的 playbook 文件中定义变量,在另一个 playbook 文件中引用变量文件中的变量,比 playbook 中定义的变量优先级高

# 创建var.yml
---
pk_name: httpd
svr_name: httpd

# 引用var.yml
---
- hosts: all
  remote_user: root
  vars_files:
    - /files/var.yml

  tasks:
    - name: install package
      yum: name={{ pk_name }} state=present
    - name: start httpd
      service: name={{ svr_name }} state=started enabled=yes

4.3.5、主机清单文件中定义变量

在主机清单文件中定义变量时,主机变量优先于组变量

  • 主机变量

    在主机清单中为指定主机定义变量名,便于在 playbook 中使用

    [appservers]
    192.168.137.11 host=node1 http_port=8080
    192.168.137.12 host=node2 http_port=8081
    
  • 组变量

    [appservers:vars]
    domain=123.com
    
  • 使用变量名

    # 修改主机名称
    ansible appservers -m hostname -a 'name={{ host }}.{{ domain }}'
    

5、when判断

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

  • 示例

    # 重新启动RedHat系统的主机
    ---
    - hosts: svr1
      remote_user: root
    
      tasks:
        - name: restart redhat hosts
          command: /sbin/reboot -h now
          # 判断是否是RedHat系统
          when: ansible_os_family == "RedHat"
    

6、whith_items迭代(循环)

当有需要执行重复性工作时,可以使用迭代机制。对迭代项的引用,固定变量名为 item,要在 task 中使用 with_items 指定需要迭代的元素列表

  • 列表元素格式

    • 字符串
    • 字典
  • 示例

    (1)、使用字符串执行迭代

    ---
    - hosts: svr1
      remote_user: root
    
      tasks:
        - name: create several user
          user: name={{ item }} state=present
          with_items:
            - user1
            - user2
    

    (2)、使用字典执行迭代

    ---
    - hosts: svr1
      remote_user: root
    
      tasks:
        - name: create several goup
          group: name={{ item }} state=present
          with_items:
            - group_1
            - group_2
        - name: create several user
          user: name={{ item.name }} group={{ item.group }} state=present
          with_items:
            - {name: 'user1',group: 'group_1'}
            - {name: 'user2',group: 'group_2'}
    

7、roles角色

role(角色)主要是用于层次性、结构化的组织 playbook ,roles 能够根据层次性结构自动装载变量文件、tasks 及 handlers 等,要使用 roles 只需要在 playbook 中使用 include 指令即可。简单来说,roles 就是通过分别将变量、文件、任务、模板及处理器放到单独的目录中,并可以快捷的包含它们的一种机制。角色一般使用于较为复杂的运维环境,提高代码的复用性

roles 是多个角色的集合,可以将多个 role 分别存放于 roles 目录下的子目录中

7.1、roles目录结构

roles 的目录结构为:roles/project/:项目名称下有以下子目录

  • files/:存放由 copy 或 script 等模块调用的文件
  • template/:template 模块查找所需要模板文件的目录
  • tasks/:定义 task、role 的基本元素,至少因该包含一个名为 main.yml 的文件,其他文件需要在此文件中通过 include 进行包含( 建议一个任务创建一个task
  • handlers/:至少因该包含一个名为 main.yml 的文件,其他文件需要在此文件中通过 include 进行包含
  • vars/:定义变量,至少因该包含一个名为 main.yml 的文件,其他文件需要在此文件中通过 include 进行包含
  • meta/:定义当前角色的特殊设定及其依赖关系,至少因该包含一个名为 main.yml 的文件,其他文件需要在此文件中通过 include 进行包含
  • default/:设定默认变量时使用此目录中的 main.yml 文件,比 vars 的优先级低

7.2、创建role的步骤

  • roles 默认存放路径:/etc/ansible/roles

  • 创建以 roles 命名的目录

  • 在 roles 目录中分别创建以各角色命名的目录,如 mysql 等

  • 在每个角色目录中分别创建 files、handlers、meta、tasks、templates、vars 目录,暂时使用不到的目录可以创建空目录,也可以不创建

  • 在 playbook 中调用各角色

  • 目录结构示例

    httpd-role.yml
    └── roles
        └── httpd
            ├── files
            │   └── main.yml
            ├── tasks
            │   ├── groupadd.yml
            │   ├── install.yml
            │   ├── main.yml
            │   ├── restart.yml
            │   └── useradd.yml
            └── vars
                └── main.yml
    

7.3、playbook调用角色

  • 普通调用角色

    ---
    - hosts: svr1
      remote_user: root
      roles:
        - httpd
    
  • 调用角色并传递参数

    ---
    - hosts: svr1
      remote_user: root
      roles:
        - httpd
        - { role:httpd, username:user01}
    
  • 基于条件调用角色

    ---
    - hosts: svr1
      remote_user: root
      roles:
        - httpd
        - { role: httpd, username: user01, when: ansible_os_family == "RedHat"}
    
  • roles中使用tags

    # 在playbook文件中使用
    ---
    - hosts: svr1
      remote_user: root
      roles:
        - { role: httpd, tags: ['httpd', 'web'] }
        - { role: httpd, tags: ['httpd', 'web'], when: ansible_os_family == "RedHat" }
    
    # 或者在执行时使用
    ansible-playbook --tags="httpd, web" httpd-role.yml
    

7.4、使用示例

创建一个 httpd 部署 roles

# 创建相关目录
mkdir roles/httpd/{tasks,files,handlers}

#创建各tasks
vim tasks/install.yml
- name: install httpd
  yum: name=httpd

vim tasks/config.yml
- name: config file
  copy: src=httpd.conf dest=/etc/httpd/conf backup=yes
  notify: restart service
  
vim tasks/index.yml
- name: index.html
  copy: src=index.html dest=/var/www/html/
  
vim tasks/service.yml
- name: start service
  service: name=httpd state=started enabled=yes

vim handlers/main.yml
- name: restart service
  service: name=httpd state=restarted
  
vim tasks/main.yml
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml

# 准备相关文件
ls /etc/ansible/roles/httpd/files/
httpd.conf  index.html

# 在playbook中调用roles
vim httpd_install_role.yml
---
- hosts: host
  remote_user: root
  gather_facts: no
  roles:
    - httpd

# 最终roles文件结构
tree /etc/ansible/roles/
/etc/ansible/roles/
└── httpd
    ├── files
    │   ├── httpd.conf
    │   └── index.html
    ├── handlers
    │   └── main.yml
    └── tasks
        ├── config.yml
        ├── index.yml
        ├── install.yml
        ├── main.yml
        └── service.yml

# 执行playbook
 ansible-playbook httpd_install_role.yml