使用 Ansible 网络角色

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

理解角色

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

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

DNS playbook 示例

为了演示角色的概念,下面的playbook.yml示例是一个包含两个任务 playbook 的单个 YAML 文件。此 Ansible Playbook 配置 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命令运行此 playbook,您将看到下面的输出。此示例使用-l选项将 playbook 限制为仅在**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

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

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

将 playbook 转换为角色

下一步是将此 playbook 转换为可重用的角色。您可以手动创建目录结构,也可以使用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

此第一个演示仅使用**tasks**和**vars**目录。目录结构如下所示

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

接下来,将原始 Ansible Playbook 中的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 Playbook 以删除tasksvars部分,并添加关键字roles以及角色的名称,在本例中为system_demo。您将拥有此 playbook

---
- 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

运行 playbook 会产生相同的行为,但输出略有不同

[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。在运行包含多个角色的 playbook 时,这将有助于查明任务是从哪里调用的。此 playbook 返回ok而不是changed,因为它与我们开始使用的单个文件 playbook 具有相同的行为。

与之前一样,playbook 将在 Cisco IOS-XE 路由器上生成以下配置

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

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

变量优先级

如果要更改 DNS 服务器怎么办?您不需要更改角色结构中的vars/main.yml。Ansible 有很多地方可以为给定的 playbook 指定变量。有关变量和优先级的详细信息,请参阅使用变量。实际上有 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

向 playbook 添加一个新的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**上运行此更新后的 playbook

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

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

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

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

最高优先级

在角色内的defaults目录中指定变量将始终具有最低优先级,而使用-e--extra-vars=作为额外变量指定vars将始终具有最高优先级,无论是什么。使用-e选项重新运行 playbook 会覆盖defaults目录(8.8.4.4 和 8.8.8.8)以及 playbook 中新创建的包含 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 Automation Platform。通过 Web UI 可以提示网络运营商使用 Web 表单填写参数。对于非技术性的剧本编写者来说,这可以通过他们的 Web 浏览器非常简单地执行剧本。

更新已安装的角色

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

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

另请参阅

Ansible Galaxy 文档

Ansible Galaxy 用户指南