侧边栏壁纸
  • 累计撰写 73 篇文章
  • 累计创建 23 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

【Ansible】Ansible Playbook(二)

Administrator
2025-06-26 / 0 评论 / 0 点赞 / 9 阅读 / 14588 字 / 正在检测是否收录...

一、循环

Ansible 提供了多种循环机制来简化重复性任务的操作。循环可以让你对一组数据项执行相同的任务,而不需要为每个项单独编写任务。

例如,拷贝文件和创建目录等任务。当需要使用PlayBook多次创建文件或目录时,我们需要重复的书写。如下:

- name: 创建多个文件(不使用循环)
  hosts: localhost
  tasks:
    - name: 创建文件1
      file:
        path: /tmp/file1.txt
        state: touch
    
    - name: 创建文件2
      file:
        path: /tmp/file2.txt
        state: touch
    
    - name: 创建文件3
      file:
        path: /tmp/file3.txt
        state: touch    

使用循环的方式书写,整体的框架只需要写一次,如下:

- name: 创建多个文件
  hosts: localhost
  tasks:
    - name: 创建文件1,2,3
      file:
        path: "{{ item }}"
        state: touch
      loop:
        - /tmpt/file1.txt
        - /tmp/file2.txt
        - /tmp/file3.txt

具体格式解析:

- name: 任务描述
  module_name:
    参数1: "{{ item }}"  # 循环变量
    参数2: 值
  loop:
    - 值1
    - 值2
    - 值3

所以,循环是帮助我们节省重复书写的内容,实现方式接近于变量。需要变动的地方就用变量代替,不变的地方就写死。

二、多循环

很多时候一个任务中,我们有许多需要变动的值,而这个任务又需要重复的执行多次。这个时候用单循环无法解决我们的需求,就需要使用多循环了。

例如,需要创建多个文件,且每个文件的权限不一致,我们就可以使用多循环的方式,将pathmode的值用循环变量代替。如下:

- name: create
    file:
      path: "{{ item.path }}"
      state: touch
      mode: "{{ item.mode }}"
    loop:
      - { path: '/opt/file1.txt', mode: '0644' }
      - { path: '/opt/file2.txt', mode: '0600' }

有一个场景如果需要多次执行并简化playbook内容必须要用到多循环:COPY

三、变量

变量是存储和引用数据的重要方式,它们使得 Playbook 更加灵活和可重用。

  1. 当某些值可能会被经常用到时,就可以将他定义成一个变量。自定义

  2. ansible 内置了很多变量,可以直接拿来用

1. 自定义变量

当某些值可能会被经常用到时,就可以将其定义成一个变量。

假如,我们在复制文件时,有巨多的文件都存储在/opt/xxx/xxx/xxx/xxx下,此时就可以将这个路径存储为一个变量,后续使用时直接调用这个变量即可。

另外,若我们需要大量修改这个目录的路径时,只需要修改变量的值即可,不需要再修改每个内容的具体值,既方便也不容易出错。

注意,写在playbook中的变量属于局部变量,无法被其他playbook调用。

示例:

---
- name: 使用变量管理文件路径示例
  hosts: all
  vars:
    # 定义基础路径变量
    source_dir: "/root/apps/config_files/production"
    destination_dir: "/etc/application/config"
    
    # 可以定义子路径变量
    log_config_path: "{{ source_dir }}/logging"
    db_config_path: "{{ source_dir }}/database"
    
  tasks:
    - name: 创建目录
      file:
        path: "{{ destination_dir }}"
        state: directory
        recurse: yes
        mode: '0755'
      
    - name: 复制日志配置文件
      copy:
        src: "{{ log_config_path }}/log4j.properties"
        dest: "{{ destination_dir }}/log4j.properties"
        remote_src: no  # 如果源文件在控制节点上
        
    - name: 复制数据库配置文件
      copy:
        src: "{{ db_config_path }}/db.conf"
        dest: "{{ destination_dir }}/db.conf"
        
    - name: 复制所有配置文件(使用通配符)
      copy:
        src: "{{ source_dir }}/*.conf"
        dest: "{{ destination_dir }}/"

2. 主机清单存储变量

当我们需要变量跨playbook调用时,可以将变量定义在主机清单文件中,但此方法的前提是调用该主机或主机组。

[webservers]
web1.example.com source_dir="/root/apps/config_files/production"  # 给单个主机添加变量
[webservers:vars]
ntp_server=ntp.example.com  # 给整个组webservers添加变量
proxy=proxy.example.com
timezone=UTC

通过这个方法定义好的变量,可以再playbook中直接应用,方法还是{{ 变量名 }}的形式

3. 内置变量

Ansible提供了很多内置变量,这些变量由Ansible自动设置并提供系统信息、执行上下文等重要数据。

当我们运行PlayBook时,Ansible自动就会获取目标主机的基本信息,这些基本信息我们可以通过ansible web -m setup >> vars.txt的方式获取到(web是主机组名)。这里面记录的就是内置变量。

获取之后,我们就可以通过PlayBook的方式调用内置变量,实现我们的目的。例如,使所有目标主机echo自己的IP地址信息。

- name: vars
  hosts: webservers
  tasks:
    - name: vars
      shell:
        echo "{{ ansible_default_ipv4.address }}" >> vars.txt

综合应用

[root@ansible1 ~]# cat 03_playbook.yml
- name: create directory and file
  hosts: all
  vars:
    dir: "/root"
    file_dir1: "{{ dir }}/ansible1"
    file_dir2: "{{ dir }}/ansible2"
    file_dir3: "{{ dir }}/ansible3"
    file_dir4: "{{ dir }}/ansible4"
    file_dir5: "{{ dir }}/ansible5"
    file_dir6: "{{ dir }}/ansible6"
  tasks:
  - name: create directory
    file:
      path: "{{ item.path }}"
      owner: "{{ item.owner }}"
      group: "{{ item.group }}"
      mode: "{{ item.mode }}"
      state: directory
    loop:
    - { path: '/root/ansible1', mode: '0755', owner: 'root', group: 'root' }
    - { path: '/root/ansible2', mode: '0755', owner: 'root', group: 'root' }
    - { path: '/root/ansible3', mode: '0777', owner: 'root', group: 'root' }
    - { path: '/root/ansible4', mode: '0755', owner: 'root', group: 'root' }
    - { path: '/root/ansible5', mode: '0755', owner: 'root', group: 'root' }
    - { path: '/root/ansible6', mode: '0644', owner: 'root', group: 'root' }
  - name: create file
    file:
      path: "{{ item.path }}"
      owner: "{{ item.owner }}"
      group: "{{ item.group }}"
      mode: "{{ item.mode }}"
      state: touch
    loop:
    - { path: '{{ file_dir1 }}/file1.txt', mode: '0755', owner: 'root', group: 'root' }
    - { path: '{{ file_dir2 }}/file2.txt', mode: '0755', owner: 'root', group: 'root' }
    - { path: '{{ file_dir3 }}/file3.txt', mode: '0777', owner: 'root', group: 'root' }
    - { path: '{{ file_dir4 }}/file4.txt', mode: '0755', owner: 'root', group: 'root' }
    - { path: '{{ file_dir5 }}/file5.txt', mode: '0755', owner: 'root', group: 'root' }
    - { path: '{{ file_dir6 }}/file6.txt', mode: '0644', owner: 'root', group: 'root' }
[root@ansible1 ~]#

四、Facts

ansible执行时,默认会有一个任务先运行:Gathering Fact

TASK [Gathering Facts] ****************************************
ok: [192.168.xxx.xxx]

这并不是我们在playbook中定义的任务,这是默认执行的任务。

ansible factsansible在被纳管主机上自动检测的变量。facts组件是ansible用于采集被纳管主机信息的一个功能,采集的信息包括IP地址、操作系统、以太网设备、mac地址、硬件信息等相关数据。

那么,采集这些信息有什么用呢?很多时候我们需要根据远程主机的信息作为判断条件操作。例如:根据被纳管主机的操作系统版本,安装不同的软件包。或者获取每台设备上的内存剩余等。

ansible为我们提供了setup模块,专门获取被纳管主机的所有facts信息。setup模块获取的整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最外层的值。我们可以通过ansible Ad-Hoc进行查看。

ansible localhost -m setup >> facts.txt

你可以进行过滤筛选出你想要的信息:

ansible localhost -m setup -a 'filter=ansible_fqdn'

facts收集到的信息,会被存储为变量,可以称为事实变量,这些变量有新旧两种书写方式:

五、条件判断

ansible中的条件判断通过when实现,允许根据变量、facts或任务结果来控制任务执行。

示例:

tasks:
  - name: Shutdown Debian systems
    command: /sbin/shutdown -t now
    when: ansible_facts['os_family'] == "Debian"
  • 该任务表示,当目标主机的系统是Debian时才会执行该任务。

六、逻辑运算符

ansible的条件判断中支持and、or及括号组合条件

when: >
  (ansible_distribution == "Ubuntu" and ansible_distribution_major_version == "22.04") 
  or (ansible_distribution == "CentOS" and ansible_distribution_major_version == "8")

七、Handlers 服务状态

Handlers 是 Ansible 中一种特殊的任务类型,用于在 playbook 执行过程中管理服务重启和配置变更后的操作。

基本概念

  • 只在被通知(notify)时才会执行的任务

  • 通常用于服务重启、重新加载配置等操作

  • 在 play 的所有普通任务执行完毕后才会运行

  • 即使被多次通知,也只会执行一次

举例:

如下,是NFS服务配置的其中一个任务,这个任务的作用是启动NFS服务。假设我现在将NFS的配置文件改动并重新执行这个PlayBook上传到目标主机上,这个配置会生效么?

很显然不会,因为这里写的是started,而不是restarted。那是不是代表,我这要把这里的started替换成restarted就可以了呢?不行,因为ansible的特点是每一次执行它会帮助我们查询状态,如果restarted不就代表状态被改变了吗,那么回显一定是黄色的,这不方便我们判断playbook执行的结果。

所以,我们应该在这里做Handlers,帮助我们去检测运行状态。

    - name: 启动NFS服务
      service:
        name: nfs-server
        state: started
        enabled: yes

我们的需求是:

  • 当第一次进行NFS服务安装时,帮助我们启动服务

  • 当配置文件没有发生变化时,不做任何动作

  • 当配置文件发生变化时,重启服务

下面这个playbook就是我们修改完成的,notify表示当此任务的状态发生改变后,需要执行handlers中的任务。注意:

  1. handlersname必须和notify定义的内容一致,否则无法识别到

  2. handlers中的任务会在你所有预定义的任务执行完毕,最后再执行

- name: nfs
  hosts: nfs_servers  # 在inventory文件中定义的主机组
  become: yes         # 使用root权限

  tasks:
    # 安装必要的软件包
    - name: 安装NFS服务端软件
      yum:
        name: nfs-utils
        state: present

    # 创建共享目录
    - name: 创建共享目录
      file:
        path: /data/share
        state: directory
        mode: '0777'

    # 配置NFS导出
    - name: 上传NFS配置文件
      copy:
        src: files/exports  # 本地文件路径: playbook/files/exports
        dest: /etc/exports
      notify: restart NFS

    # 启动NFS服务
    - name: start NFS
      systemd:
        name: nfs-server
        state: started
        enabled: yes
  handlers:
    - name: restart NFS
      systemd:
        name: nfs-server
        state: restarted

八、指定任务执行顺序

ansible中,有几种方式可以控制playbook从特定任务开始执行,而不是从头开始运行整个playbook

tasks

通过在执行playbook时添加--start-at-stack参数,指定从哪个任务开始依次运行:

ansible-playbook playbook.yml --start-at-task="任务描述"
  • 这里的“任务描述”就是我们在playbook当中定义的任务名

通过添加--list-tasks参数可获取playbook中所有的tasks

ansible-playbook --list-tasks playbook.yaml

选择 tag

tasks没有那么的灵活,只能控制从哪个tasks开始运行。无法实现只运行某个任务、或跳过特定的任务等目的。

可以通过为每个任务添加标签,然后实现只运行特定标签的任务,或跳过特定标签的任务。

tags需要与任务的名称对齐,如下:

tasks:
  - name: 安装软件包
    yum:
      name: nginx
      state: present
    tags: install

  - name: 配置服务
    template:
      src: nginx.conf.j2
      dest: /etc/nginx/nginx.conf
    tags: config
&&
ansible-playbook playbook.yml --tags(-t) "config,install"
ansible-playbook playbook.yml --skip-tag=config,install

但是,执行时一定会按照tagplaybook中的顺序执行,即使你故意写反,它也一定按照任务顺序执行。

0
博主关闭了所有页面的评论