Ansible 角色管理

发布于:2025-08-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

Ansible 角色管理

异步并行

配置 async

ansible 默认行为:必须等当前任务执行完成,才能执行下一个任务。

有些操作需要很长时间才能完成,例如下载一个大文件,重启服务器等。使用异步并行模式,ansible可以很快在受管主机上这些执行命令,但是需要等待命令执行完成才能将主机置于相应状态。

Ansible使用async触发异步并行运作任务:

  • async:async的值是ansible等待运行这个任务的最大超时值(如果执行超时任务会强制中断导致失败)。
  • poll:ansible检查这个任务是否完成的时间间隔。ansible poll_interval 默认值是 15。

示例1: 任务执行失败,在规定时间内容任务没有执行完成。

---
- name: connection
  hosts: node1
  tasks:
    - name: conneciton 
      shell: sleep 10
      async: 5
      poll: 2

示例2: 放入后台下载,立刻执行下一个任务。

---
- name: connection
  hosts: node1
  tasks:
    - name: download
      get_url: 
        url: http://192.168.48.100/ISOS/openEuler-24.03-LTS-x86_64-dvd.iso
        dest: /home/yy
      async: 100
      poll: 0

示例3: ansible 默认行为,等该任务执行完,再执行下一个任务。

---
- name: connection
  hosts: node1
  tasks:
    - name: conneciton 
      shell: sleep 10
      async: 0
      poll: 2
async_status 模块

使用 async_status 模块检查之前的任务是否运行完成。

与async配套使用

示例:

---
- name: test async_status
  hosts: node1
  tasks:
    - shell: sleep 10 
      async: 20
      poll: 0
      register: out
    
    - name: wait for
      async_status:
        # 通过任务的 ansible_job_id 属性跟踪任务
        jid: "{{ out.ansible_job_id }}"
      register: job_result
      # 根据当前任务执行结果的finished值,判断跟踪任务是否执行完成
      until: job_result.finished
      retries: 30
      delay: 2

选项说明:

  • retries,设置重试次数,默认值为3。
  • delay,设置检测时间间隔,默认5秒检测一次
wait_for 模块

使用 wait_for 模块检查之前的任务是否达到预期状态。

示例1: 测试文件是否存在

---
- name: test wait for
  hosts: node1
  tasks:
    - shell: sleep 10 && touch /tmp/hello
      # async时间要大于sleep的时间
      async: 20
      poll: 0
      register: out

    - name: wait for create /tmp/hello
      wait_for:
        path: /tmp/hello
        state: present
        delay: 5
        timeout: 30
        sleep: 2

选项说明:

  • delay,设置检测前延迟时间。
  • timeout,设置检测超时时间。
  • sleep,设置检测时间间隔。

示例2: 测试主机端口是否打开

---
- name: test wait_for
  hosts: node1,node2
  tasks:
    - name: reboot node1
      shell: shutdown -r now "Ansible updates triggered"
      async: 1
      poll: 0
      when: inventory_hostname == "node1"
    
    - name: wait for node1 come back
      wait_for:
        host: node1
        port: 22
        state: started
        delay: 10
        sleep: 2
        timeout: 300
      when: inventory_hostname == "node2"

Including 和 importing 文件

如果playbook很长或很复杂,可以将其分成较小的文件以便于管理。

采用模块化方式将多个playbook组合为一个main playbook或者将文件中的任务列表插入play。这样可以更轻松地在不同项目中重用play或任务。

ansible重用内容主要有两种方式:

  • 使用任何 include 关键字任务(include_tasks、include_role 等),它将是动态的。
  • 使用任何 import 关键字任务(import_playbook、import_tasks、import_role等),它将是静态的。
  • 只使用include的任务(用于 task 级别和 Playbook 级别)仍然可用,**此功能将在 2.12 版中删除
playbook 级别

import_playbook 支持导入外部playbooks。

  • 导入的内容是完整的playbook,只能在play级别使用。
  • 导入的多个playbooks,则按导入顺序执行。

示例:

  • 主剧本内容如下

    - name: prepare the web server
      import_playbook: pre_web.yml
    
    - name: prepare the vsftpd server
      import_playbook: pre_vsftpd.yml
    
    - name: prepare the databse server
      import_playbook: pre_db.yml
    
  • pre_web.yml 内容如下:

    cat > pre_web.yml << EOF
    - name: Play web
      hosts: node1
      tasks:
        - name: install httpd
          yum:
            name: httpd
            state: present
    EOF
    
  • pre_vsftpd.yml 内容如下:

    cat > pre_vsftpd.yml << EOF
    - name: Play vsftpd
      hosts: node1
      tasks:
        - name: install vsftpd
          yum:
            name: vsftpd
            state: present
    EOF
    
  • pre_db.yml 内容如下:

    cat > pre_db.yml << EOF
    - name: Play db
      hosts: node1
      tasks:
        - name: install mariadb-server
          yum:
            name: mariadb-server
            state: present
    EOF
    
task 级别

示例:

  • 主剧本内容如下:

    ---
    - name: Install web server
      hosts: node1
      tasks:
        - name: import a task file
          import_tasks: tasks.yaml
          #include: tasks.yaml
          #include_tasks: tasks.yaml
    
  • tasks.yaml 内容如下:

    - name: Install the httpd
      yum:
        name: httpd
        state: present
    
    - name: Starts httpd
      service:
        name: httpd
        state: started
    
task 级别

示例:

  • 主剧本内容如下:

    ---
    - name: Install web server
      hosts: node1
      tasks:
        - name: import a task file
          import_tasks: tasks.yaml
          #include: tasks.yaml
          #include_tasks: tasks.yaml
    
  • tasks.yaml 内容如下:

    - name: Install the httpd
      yum:
        name: httpd
        state: present
    
    - name: Starts httpd
      service:
        name: httpd
        state: started
    

Ansible 角色

Ansible 角色介绍

可以把 Ansible 角色(Role)理解成 “预制好的‘功能工具箱’” —— 就像你组装家具时,商家会把 “拧螺丝的扳手、装木板的卡扣、贴防撞条的胶” 打包成一个 “组装套件”,不用你再零散找工具。

比如要部署一个网站,你不用在 Playbook 里写 “安装 nginx、改配置、传静态文件、启服务” 这些零散步骤,而是直接拿一个叫 “nginx_role” 的 “工具箱”:

  • 这个 “箱子” 里早就按规矩分好了格子:
    • “tasks” 格放着 “怎么装 nginx、怎么启服务” 的操作指南;
    • “templates” 格塞着带变量的 nginx 配置模板(像能自动填服务器 IP 的填空题);
    • “files” 格存着要传到服务器的静态网页文件;
    • “handlers” 格里藏着 “配置改了就重启 nginx” 的触发开关。

用的时候也简单,在 Playbook 里写一句 “用 nginx_role 这个箱子”,Ansible 就会自动打开箱子,按顺序用里面的工具完成部署 —— 下次另一个项目要装 nginx,直接再拿这个 “箱子” 用,不用重新凑工具;团队里谁要改 nginx 配置,直接去 “templates” 格子里改模板就行,不用翻整个 Playbook。

在生产环境中play会更长更复杂,有许多包含或导入的文件,以及用于管理各种情况的任务和处理程序。

随着开发的playbook越来越多,有很多机会重复利用以前编写的playbook中的代码。例如,为某一应用配置MySQL数据库的play ,可以通过不同的主机名、用户和密码等为另一个应用配置MySQL数据库。

**Ansible提供了角色,可以轻松实现重复利用Ansible代码。**在准化目录结构中打包所有任务、变量、文件、模板,以及调配基础架构或部署应用所需的其他资源。只需将角色从一个项目复制到另一个项目,在play中调用该角色即可。

Ansible 角色结构

顶级目录定义角色本身的名称。子目录按照各个文件在角色中的用途进行命名:

  • defaults,此目录中的main.yml文件包含角色变量的默认值。
    • 几乎任何其他变量都会覆盖角色的默认变量,如清单变量 、play中vars声明的变量等。
    • 这些变量旨在让人们在编写使用该角色的play时可以准确地自定义或控制它将要执行的操作,应该在play中更改和自定义default变量值。
  • file,此目录包含由角色任务引用的静态文件。
  • handlers,此目录中的main.yml文件包含角色的处理程序定义。
  • meta,此目录中的main.yml文件包含与角色相关的信息,如作者、许可证、平台和可选的角色依赖项。
  • tasks,此目录中的main.yml文件包含角色的任务定义。
  • templates,此目录包含由角色任务引用的Jinja2模板。
  • tests,此目录可以包含清单和test.yml playbook,可用于测试角色。
  • vars,此目录中的main.yml文件定义角色变量值。
    • vars中变量具有较高的优先级,facts、include_vars 加载的变量、register变量和角色参数可以覆盖角色vars目录中定义的变量。
    • vars中变量优先级高于清单变量和play中vars声明的变量。在playbook中使用时不应更改。
    • vars中变量旨在供角色的内部功能使用。
  • README.md,提供人类可读的基本角色描述、有关如何使用该角色的文档和示例,以及其发挥作用所需要满足的任何非Ansible要求。

说明:并非每个角色都拥有所有目录,部分目录可以省略。

ansible-galaxy 命令后续详细介绍。

Ansible 角色目录位置

默认role使用以下三个目录:

  • ~/.ansible/roles
  • /usr/share/ansible/roles
  • /etc/ansible/roles

优先级从上到下依次降低。

可以在ansible.cfg配置文件[defaults]块中通过变量roles_path定义role位置:

[defaults]
roles_path  = ./roles
......

多个路径使用冒号分隔:

roles_path = /etc/ansible/roles:/home/student/web/roles

创建角色

[yy@controller web 11:30:08]$ vim ansible.cfg
[defaults]
roles_path  = ./roles
[yy@controller web 11:28:04]$ mkdir roles
[yy@controller web 11:29:06]$ ansible-galaxy init apache
- Role apache was created successfully
[yy@controller web 11:29:26]$ mv apache/ roles
[yy@controller web 11:29:37]$ ansible-galaxy list
# /home/yy/web/roles
- apache, (unknown version)
[yy@controller web 11:32:03]$ cd roles/apache/

  • 从tasks开始,tasks/main.yml内容如下:

    ---
    # tasks file for apache
    - name: install web
      yum:
        name: "{{ web_package }}"
        state: latest
    
    - name: "start {{ web_service }}"
      service:
        name: "{{ web_service }}"
        state: started
        enabled: yes
    
    - name: prepare motd
      template:
        src: motd.j2
        dest: /etc/motd
    
    - name: prepare yy site
      template:
        src: yy.conf.j2
        dest: /etc/httpd/conf.d/yy.conf
      notify:
        - restart_web
    
    - name: prepare DocumentRoot 
      file:
        path: "/var/www/html/{{ ansible_hostname }}" 
        state: directory
    
    - name: prepare index.html
      template:
        src: index.html.j2
        dest: "/var/www/html/{{ ansible_hostname }}/index.html"
    
  • defaults/main.yml vim 内容如下:

    ---
    # defaults file for apache
    web_package: httpd
    web_service: httpd
    
  • templates/motd.j2 内容如下:

    hello guys!
    Welcome to {{ ansible_fqdn }}!
    
  • templates/yy.conf.j2 内容如下:

    # {{ ansible_managed }}
    <VirtualHost *:80>
        ServerAdmin yy@{{ ansible_fqdn }}
        ServerName {{ ansible_fqdn }}
        ErrorLog logs/{{ ansible_hostname }}-error.log
        CustomLog logs/{{ ansible_hostname }}-common.log common
        DocumentRoot /var/www/html/{{ ansible_hostname }}/
    
        <Directory /var/www/html/{{ ansible_hostname }}/>
           Options +Indexes +FollowSymlinks +Includes
           Order allow,deny
           Allow from all
        </Directory>
    </VirtualHost>
    
  • handlers/main.yml 内容如下:

    ---
    # handlers file for apache
    - name: restart_web
      service:
        name: "{{ web_service }}"
        state: restarted
    
  • templates/index.html.j2 内容如下:

    Welcome to {{ ansible_fqdn }} !
    
  • meta/main.yml 内容如下:

    ---
    galaxy_info:
      author: yy
      description: yy web
      company: yy world
      license: license (GPLv2, CC-BY, etc)
      min_ansible_version: 2.4
    
      platforms:
      - name: Fedora
        versions:
        - all
        - 25
      - name: SomePlatform
        versions:
        - all
      galaxy_tags: [apache,web]
    dependencies: []
    
调用角色

playbook中可以直接使用roles。role中的tasks,handlers,variables和依赖都会按顺序引入到playbook中。role中的任何copy,script,template或者include任务都可以引用相关文件、模板、任务,而且可以不指定绝对路径或者相对路径,Ansible会在role的files,templates和tasks目录中查找。

调用角色:

  • 语法一:

    ---
    - hosts: servers
      roles:
        - rolename
    
  • 语法二:调用时候传递变量给角色。

    ---
    - hosts: servers
      roles:
        - role: role1
          var1: value1
        - { role: role2, var2: value2, var3: value3 }
    

示例1:

---
- name: deploy apache
  hosts: node1
  roles:
    - apache

使用系统角色

系统角色介绍

可以把 系统角色 理解成操作系统里的 “专职岗位”—— 就像公司里有 “财务岗”“行政岗”,每个岗位有固定职责,系统角色也有明确的 “权限范围”,规定了 “哪些操作能做、哪些不能做”,核心是帮系统管理权限、保障安全。

比如常见的系统角色:

  • 管理员角色(如 Linux 的 root、Windows 的 Administrator):相当于 “公司老板”,拥有系统的 “全部权限”—— 能装软件、删文件、改核心配置,甚至能查看所有用户的文件,负责系统的 “全局管理”。
  • 普通用户角色(如 Linux 的普通账号、Windows 的标准用户):像 “公司员工”,权限有限 —— 只能操作自己的文件(比如自己电脑里的文档),不能改系统核心设置(比如不能删系统文件、不能装需要全局权限的软件),避免误操作搞崩系统。
  • 服务角色(如 Linux 的 nginx、mysql 账号):类似 “外包技工”,专门给某个程序 “打工”—— 比如 nginx 角色只负责运行 nginx 服务器,只能访问 nginx 的配置文件和网页文件,没有其他权限;就算程序出问题被攻击,也不会影响到系统其他部分,相当于 “隔离保护”。

简单说,系统角色就是给不同 “使用者”(人或程序)划好 “权限边界”,让该干活的能干活,不该碰的碰不到,既保证系统正常运行,又防止乱操作或攻击带来的风险。

自RHEL7.4开始,操作系统rhel-system-roles软件包提供多个Ansible角色。在RHEL8中,该软件包可从AppStream频道获取。系统角色的目的是标准化配置版本6.10及以上的任何RHEL主机。

举例而言,RHEL7的建议时间同步服务为chronyd服务,RHEL6的建议服务为ntpd服务。在混合了RHEL6和7主机的环境中,管理员必须管理这两个服务的配置文件。借助RHEL系统角色,管理员不再需要维护这两个服务的配置文件。管理员可以使用rhel-system-roles.timesync角色来配置RHEL6和7主机的时间同步。一个包含角色变量的简化YAML文件可以为这两种类型的主机定义时间同步配置。

系统角色安装和说明
[yy@controller ~]$ sudo yum install -y rhel-system-roles

# RHEL系统角色位于/usr/share/ansible/roles/
[yy@controller ~]$ ls -1 /usr/share/ansible/roles/

# Ansible默认roles_path包含/usr/share/ansible/roles,可以直接引用这些角色。

# 系统角色的文档位于/usr/share/doc/rhel-system-roles
[yy@controller ~]$ ls /usr/share/doc/rhel-system-roles

# 每个角色的文档目录均包含一个README.md文件。
# README.md文件含有角色的说明,以及角色用法信息。
# README.md文件也会说明影响角色行为的角色变量。
# README.md文件中含有playbook代码片段,用于演示常见配置场景的变量设置。
角色使用案例-timesync

rhel-system-roles.timesync角色说明文档位于/usr/share/doc/rhel-system-roles/timesync/README.md。此文件说明了影响角色行为的所有变量,还包含演示了不同时间同步配置的三个playbook代码片段。

为了手动配置NTP服务器,该角色具有一个名为timesync_ntp_servers的变量。此变量取一个要使用的NTP服务器的列表作为值。列表中的每一项均由一个或多个属性构成。

两个关键属性如下:

  • hostname,要与其同步的NTP服务器的主机名。

  • iburst,布尔值,用于启用或禁用快速初始同步。在角色中默认为no,但您通常应该将该属性设为yes。

    示例:

- name: Manage timesync with 3 servers
  hosts: all
  vars:
    timesync_ntp_servers:
      - hostname: ntp.aliyun.com
        iburst: true
  roles:
    - rhel-system-roles.timesync

[yy@controller web 13:57:29]$ vim ansible.cfg
roles_path  = ./roles:/usr/share/ansible/roles

安装角色
# 安装角色(下载角色)
[yy@controller ~]$ ansible-galaxy install geerlingguy.haproxy
# 一次性安装多个角色
[yy@controller ~]$ vim requires.yml 
# from galaxy
- name: docker
  src: https://github.com/geerlingguy/ansible-role-docker/archive/2.7.0.tar.gz
- name: haproxy
  src: https://github.com/geerlingguy/ansible-role-haproxy/archive/1.1.2.tar.gz

[yy@controller ~]$ ansible-galaxy install -r requires.yml 
- downloading role from https://github.com/geerlingguy/ansible-role-docker/archive/2.7.0.tar.gz
- extracting docker to /root/.ansible/roles/docker
- docker was installed successfully
- downloading role from https://github.com/geerlingguy/ansible-role-haproxy/archive/1.1.2.tar.gz
- extracting haproxy to /root/.ansible/roles/haproxy
- haproxy was installed successfully