使用 Ansible 网络角色

角色是一组 Ansible 默认值、文件、任务、模板、变量和其他协同工作的 Ansible 组件。正如您在 运行您的第一个命令和剧本 中看到的,从命令到剧本的转变使运行多个任务以及按相同顺序重复相同任务变得容易。从剧本到角色的转变使重用和共享您的有序任务变得更加容易。您可以查看 Ansible Galaxy,它允许您共享您的角色并使用其他人的角色,无论是直接使用还是作为灵感。

了解角色

那么角色到底是什么,为什么您应该关心它?Ansible 角色基本上是分解成已知文件结构的剧本。从剧本迁移到角色使共享、阅读和更新您的 Ansible 工作流变得更容易。用户可以编写自己的角色。因此,例如,您不必编写自己的 DNS 剧本。相反,您指定一个 DNS 服务器和一个角色来为您配置它。

为了进一步简化您的工作流,Ansible 网络团队编写了一系列针对常见网络用例的角色。使用这些角色意味着您不必重新发明轮子。与其编写和维护您自己的 create_vlan 剧本或角色,您可以专注于设计、编码和维护描述您的网络拓扑和清单的解析器模板,让 Ansible 的网络角色完成工作。请参阅 Ansible Galaxy 上的 与网络相关的角色

一个 DNS 剧本示例

为了演示角色的概念,下面的示例 playbook.yml 是一个包含两个任务剧本的单个 YAML 文件。此 Ansible 剧本配置了 Cisco IOS XE 设备上的主机名,然后它配置了 DNS(域名系统)服务器。

---
- name: configure cisco routers
  hosts: routers
  connection: ansible.netcommon.network_cli
  gather_facts: no
  vars:
    dns: "8.8.8.8 8.8.4.4"

  tasks:
   - name: configure hostname
     cisco.ios.ios_config:
       lines: hostname {{ inventory_hostname }}

   - name: configure DNS
     cisco.ios.ios_config:
       lines: ip name-server {{dns}}

如果您使用 ansible-playbook 命令运行此剧本,您将看到下面的输出。此示例使用 -l 选项将剧本限制为仅在 rtr1 节点上执行。

[user@ansible ~]$ ansible-playbook playbook.yml -l rtr1

PLAY [configure cisco routers] *************************************************

TASK [configure hostname] ******************************************************
changed: [rtr1]

TASK [configure DNS] ***********************************************************
changed: [rtr1]

PLAY RECAP *********************************************************************
rtr1                       : ok=2    changed=2    unreachable=0    failed=0

此剧本配置了主机名和 DNS 服务器。您可以在 Cisco IOS XE rtr1 路由器上验证该配置

rtr1#sh run | i name
hostname rtr1
ip name-server 8.8.8.8 8.8.4.4

将剧本转换为角色

下一步是将此剧本转换为可重用的角色。您可以手动创建目录结构,也可以使用 ansible-galaxy init 创建角色的标准框架。

[user@ansible ~]$ ansible-galaxy init system_demo
[user@ansible ~]$ cd system_demo/
[user@ansible system_demo]$ tree
.
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
  └── main.yml

此第一个演示仅使用 tasksvars 目录。目录结构将如下所示

[user@ansible system_demo]$ tree
.
├── tasks
│   └── main.yml
└── vars
    └── main.yml

接下来,将原始 Ansible 剧本中 varstasks 部分的内容移动到角色中。首先,将两个任务移动到 tasks/main.yml 文件中

[user@ansible system_demo]$ cat tasks/main.yml
---
- name: configure hostname
  cisco.ios.ios_config:
    lines: hostname {{ inventory_hostname }}

- name: configure DNS
  cisco.ios.ios_config:
    lines: ip name-server {{dns}}

接下来,将变量移动到 vars/main.yml 文件中

[user@ansible system_demo]$ cat vars/main.yml
---
dns: "8.8.8.8 8.8.4.4"

最后,修改原始 Ansible 剧本以删除 tasksvars 部分并添加关键字 roles 以及角色的名称,在本例中为 system_demo。您将拥有此剧本

---
- name: configure cisco routers
  hosts: routers
  connection: ansible.netcommon.network_cli
  gather_facts: false

  roles:
    - system_demo

总之,此演示现在总共有三个目录和三个 YAML 文件。有 system_demo 文件夹,它代表该角色。此 system_demo 包含两个文件夹,tasksvars。每个文件夹中都有一个 main.ymlvars/main.yml 包含来自 playbook.yml 的变量。 tasks/main.yml 包含来自 playbook.yml 的任务。 playbook.yml 文件已修改为调用角色,而不是直接指定 vars 和 tasks。以下是当前工作目录的树

[user@ansible ~]$ tree
.
├── playbook.yml
└── system_demo
    ├── tasks
       └── main.yml
    └── vars
        └── main.yml

运行剧本会导致相同的行为,但输出略有不同

[user@ansible ~]$ ansible-playbook playbook.yml -l rtr1

PLAY [configure cisco routers] *************************************************

TASK [system_demo : configure hostname] ****************************************
ok: [rtr1]

TASK [system_demo : configure DNS] *********************************************
ok: [rtr1]

PLAY RECAP *********************************************************************
rtr1             : ok=2    changed=0    unreachable=0    failed=0

如上所示,每个任务现在都以角色名称为前缀,在本例中为 system_demo。当运行包含多个角色的剧本时,这将有助于查明任务是从哪里调用的。此剧本返回了 ok 而不是 changed,因为它对我们开始使用的单个文件剧本具有相同的行为。

和以前一样,剧本将在 Cisco IOS-XE 路由器上生成以下配置

rtr1#sh run | i name
hostname rtr1
ip name-server 8.8.8.8 8.8.4.4

这就是为什么 Ansible 角色可以简单地认为是解构的剧本。它们简单、有效且可重用。现在,另一个用户可以简单地包含 system_demo 角色,而不必创建自定义的“硬编码”剧本。

变量优先级

如果您想更改 DNS 服务器怎么办?您不应该更改角色结构中的 vars/main.yml。Ansible 具有许多位置,您可以在其中为给定剧本指定变量。请参阅 使用变量 以了解有关变量和优先级的详细信息。实际上有 21 个地方可以放置变量。虽然此列表乍一看似乎令人不知所措,但绝大多数用例只需要了解放置最低优先级变量的位置以及如何传递最高优先级变量。请参阅 变量优先级:我应该将变量放在哪里? 以获取有关变量放置位置的更多指导。

最低优先级

最低优先级是角色内的 defaults 目录。这意味着您可以潜在地指定变量的所有其他 20 个位置都将比 defaults 具有更高的优先级,无论如何。要立即使来自 system_demo 角色的 vars 具有最低优先级,请将 vars 目录重命名为 defaults

[user@ansible system_demo]$ mv vars defaults
[user@ansible system_demo]$ tree
.
├── defaults
│   └── main.yml
├── tasks
│   └── main.yml

在剧本中添加一个新的 vars 部分以覆盖默认行为(其中变量 dns 设置为 8.8.8.8 和 8.8.4.4)。对于此演示,将 dns 设置为 1.1.1.1,因此 playbook.yml 变成

---
- name: configure cisco routers
  hosts: routers
  connection: ansible.netcommon.network_cli
  gather_facts: no
  vars:
    dns: 1.1.1.1
  roles:
    - system_demo

rtr2 上运行此更新后的剧本

[user@ansible ~]$ ansible-playbook playbook.yml -l rtr2

rtr2 Cisco 路由器上的配置将如下所示

rtr2#sh run | i name-server
ip name-server 1.1.1.1

在剧本中配置的变量现在优先于 defaults 目录。事实上,您配置变量的任何其他位置都将优先于 defaults 目录中的值。

最高优先级

在角色的 defaults 目录中指定变量始终具有最低优先级,而使用 -e--extra-vars= 作为额外变量指定 vars 始终具有最高优先级,无论如何。使用 -e 选项重新运行剧本会覆盖 defaults 目录(8.8.4.4 和 8.8.8.8)以及包含 1.1.1.1 DNS 服务器的剧本中新创建的 vars

[user@ansible ~]$ ansible-playbook playbook.yml -e "dns=192.168.1.1" -l rtr3

Cisco IOS XE 路由器上的结果将只包含最高优先级的设置 192.168.1.1

rtr3#sh run | i name-server
ip name-server 192.168.1.1

这有什么用?你为什么应该关心?额外变量通常由网络运营商用来覆盖默认值。一个强大的例子是 AWX 上的作业模板调查功能或 Red Hat Ansible 自动化平台。通过 Web UI,可以提示网络运营商使用 Web 表单填写参数。对于非技术性的剧本编写者来说,这对于使用其 Web 浏览器执行剧本来说非常简单。

更新已安装的角色

角色的 Ansible Galaxy 页面列出了所有可用的版本。要将本地安装的角色更新到新的或不同的版本,请使用 ansible-galaxy install 命令,并带有版本和 --force 选项。您可能还需要手动更新任何依赖的角色以支持此版本。请参阅 Galaxy 中的角色 **Read Me** 选项卡以获取依赖角色的最低版本要求。

[user@ansible]$ ansible-galaxy install mynamespace.my_role,v2.7.1 --force

另请参阅

Ansible Galaxy 文档

Ansible Galaxy 用户指南