Ansible 网络示例
本文档介绍了一些使用 Ansible 管理网络基础设施的示例。
先决条件
此示例需要以下内容
已安装 **Ansible 2.10**(或更高版本)。有关更多信息,请参阅 安装 Ansible。
一个或多个与 Ansible 兼容的网络设备。
对 YAML 的基本了解 YAML 语法。
对 Jinja2 模板的基本了解。有关更多信息,请参阅 模板 (Jinja2)。
基本的 Linux 命令行使用。
网络交换机和路由器配置的基本知识。
清单文件中的组和变量
一个 inventory
文件是一个类似 YAML 或 INI 的配置文件,它定义了主机到组的映射。
在我们的示例中,清单文件定义了组 eos
、ios
、vyos
和一个名为 switches
的“组组”。有关子组和清单文件的更多详细信息,请参阅 Ansible 清单组文档。
由于 Ansible 是一个灵活的工具,因此有多种方法可以指定连接信息和凭据。我们建议在清单文件中使用 [my_group:vars]
功能。
[all:vars]
# these defaults can be overridden for any group in the [group:vars] section
ansible_connection=ansible.netcommon.network_cli
ansible_user=ansible
[switches:children]
eos
ios
vyos
[eos]
veos01 ansible_host=veos-01.example.net
veos02 ansible_host=veos-02.example.net
veos03 ansible_host=veos-03.example.net
veos04 ansible_host=veos-04.example.net
[eos:vars]
ansible_become=yes
ansible_become_method=enable
ansible_network_os=arista.eos.eos
ansible_user=my_eos_user
ansible_password=my_eos_password
[ios]
ios01 ansible_host=ios-01.example.net
ios02 ansible_host=ios-02.example.net
ios03 ansible_host=ios-03.example.net
[ios:vars]
ansible_become=yes
ansible_become_method=enable
ansible_network_os=cisco.ios.ios
ansible_user=my_ios_user
ansible_password=my_ios_password
[vyos]
vyos01 ansible_host=vyos-01.example.net
vyos02 ansible_host=vyos-02.example.net
vyos03 ansible_host=vyos-03.example.net
[vyos:vars]
ansible_network_os=vyos.vyos.vyos
ansible_user=my_vyos_user
ansible_password=my_vyos_password
如果您使用 ssh-agent,则不需要 ansible_password
行。如果您使用 ssh 密钥但不使用 ssh-agent,并且您有多个密钥,请在 [group:vars]
部分使用 ansible_ssh_private_key_file=/path/to/correct/key
指定要用于每个连接的密钥。有关 ansible_ssh_
选项的更多信息,请参阅 连接到主机:行为清单参数。
警告
切勿以明文形式存储密码。
用于密码加密的 Ansible vault
Ansible 的“Vault”功能允许您将敏感数据(如密码或密钥)保存在加密文件中,而不是以明文形式保存在 playbook 或角色中。然后可以分发这些 vault 文件或将其置于源代码控制中。有关更多信息,请参阅 使用加密变量和文件。
以下是如何在变量中指定 SSH 密码(使用 Ansible Vault 加密)的示例
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: vyos.vyos.vyos
ansible_user: my_vyos_user
ansible_ssh_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
39336231636137663964343966653162353431333566633762393034646462353062633264303765
6331643066663534383564343537343334633031656538370a333737656236393835383863306466
62633364653238323333633337313163616566383836643030336631333431623631396364663533
3665626431626532630a353564323566316162613432373738333064366130303637616239396438
9853
常用清单变量
以下变量在清单中的所有平台上都很常见,尽管可以为特定的清单组或主机覆盖它们。
- ansible_connection:
Ansible 使用 ansible-connection 设置来确定如何连接到远程设备。在使用 Ansible Networking 时,将其设置为适当的网络连接选项,例如
ansible.netcommon.network_cli
,以便 Ansible 将远程节点视为具有有限执行环境的网络设备。如果没有此设置,Ansible 将尝试使用 ssh 连接到远程并执行网络设备上的 Python 脚本,这将失败,因为网络设备上通常不提供 Python。- ansible_network_os:
通知 Ansible 此主机对应于哪个网络平台。在使用
ansible.netcommon.*
连接选项时,这是必需的。- ansible_user:
要以其身份连接到远程设备(交换机)的用户。如果没有此设置,将使用运行
ansible-playbook
的用户。指定网络设备上连接的用户- ansible_password:
与
ansible_user
对应的登录密码。如果未指定,将使用 SSH 密钥。- ansible_become:
如果应使用 enable 模式(特权模式),请参阅下一节。
- ansible_become_method:
应使用哪种类型的 become,对于
network_cli
,唯一有效的选择是enable
。
权限提升
某些网络平台(如 Arista EOS 和 Cisco IOS)具有不同特权模式的概念。某些网络模块(例如修改系统状态(包括用户)的模块)仅在高特权状态下才能工作。在使用 connection: ansible.netcommon.network_cli
时,Ansible 支持 become
。这允许为需要它们的特定任务提升权限。添加 become: yes
和 become_method: enable
会通知 Ansible 在执行任务之前进入特权模式,如下所示
[eos:vars]
ansible_connection=ansible.netcommon.network_cli
ansible_network_os=arista.eos.eos
ansible_become=yes
ansible_become_method=enable
有关更多信息,请参阅 在网络模块中使用 become 指南。
跳板主机
如果 Ansible 控制节点没有到远程设备的直接路由,并且您需要使用跳板主机,请参阅 Ansible 网络代理命令 指南,了解如何实现此操作的详细信息。
示例 1:使用 playbook 收集事实并创建备份文件
Ansible 事实模块收集系统信息“事实”,这些信息可用于 playbook 的其余部分。
Ansible Networking 附带许多网络特定的 facts 模块。在本例中,我们使用 _facts
模块 arista.eos.eos_facts、cisco.ios.ios_facts 和 vyos.vyos.vyos_facts 连接到远程网络设备。由于凭据未通过模块参数显式传递,因此 Ansible 使用清单文件中的用户名和密码。
Ansible 的“网络 Fact 模块”从系统收集信息并将结果存储在以 ansible_net_
为前缀的 facts 中。这些模块收集的数据在模块文档的“返回值”部分有记录,在本例中为 arista.eos.eos_facts 和 vyos.vyos.vyos_facts。我们可以使用这些 facts,例如 ansible_net_version
,在后面的“显示一些 facts”任务中使用。
为了确保我们调用正确的模式(*_facts
),任务将根据清单文件中定义的组有条件地运行,有关在 Ansible Playbook 中使用条件的更多信息,请参阅 使用 when 的基本条件。
在本例中,我们将创建一个包含一些网络交换机的清单文件,然后运行一个 playbook 来连接到网络设备并返回有关它们的一些信息。
步骤 1:创建清单
首先,创建一个名为 inventory
的文件,其中包含
[switches:children]
eos
ios
vyos
[eos]
eos01.example.net
[ios]
ios01.example.net
[vyos]
vyos01.example.net
步骤 2:创建 playbook
接下来,创建一个名为 facts-demo.yml
的 playbook 文件,其中包含以下内容
- name: "Demonstrate connecting to switches"
hosts: switches
gather_facts: no
tasks:
###
# Collect data
#
- name: Gather facts (eos)
arista.eos.eos_facts:
when: ansible_network_os == 'arista.eos.eos'
- name: Gather facts (ios)
cisco.ios.ios_facts:
when: ansible_network_os == 'cisco.ios.ios'
- name: Gather facts (vyos)
vyos.vyos.vyos_facts:
when: ansible_network_os == 'vyos.vyos.vyos'
###
# Demonstrate variables
#
- name: Display some facts
debug:
msg: "The hostname is {{ ansible_net_hostname }} and the OS is {{ ansible_net_version }}"
- name: Facts from a specific host
debug:
var: hostvars['vyos01.example.net']
- name: Write facts to disk using a template
copy:
content: |
#jinja2: lstrip_blocks: True
EOS device info:
{% for host in groups['eos'] %}
Hostname: {{ hostvars[host].ansible_net_hostname }}
Version: {{ hostvars[host].ansible_net_version }}
Model: {{ hostvars[host].ansible_net_model }}
Serial: {{ hostvars[host].ansible_net_serialnum }}
{% endfor %}
IOS device info:
{% for host in groups['ios'] %}
Hostname: {{ hostvars[host].ansible_net_hostname }}
Version: {{ hostvars[host].ansible_net_version }}
Model: {{ hostvars[host].ansible_net_model }}
Serial: {{ hostvars[host].ansible_net_serialnum }}
{% endfor %}
VyOS device info:
{% for host in groups['vyos'] %}
Hostname: {{ hostvars[host].ansible_net_hostname }}
Version: {{ hostvars[host].ansible_net_version }}
Model: {{ hostvars[host].ansible_net_model }}
Serial: {{ hostvars[host].ansible_net_serialnum }}
{% endfor %}
dest: /tmp/switch-facts
run_once: yes
###
# Get running configuration
#
- name: Backup switch (eos)
arista.eos.eos_config:
backup: yes
register: backup_eos_location
when: ansible_network_os == 'arista.eos.eos'
- name: backup switch (vyos)
vyos.vyos.vyos_config:
backup: yes
register: backup_vyos_location
when: ansible_network_os == 'vyos.vyos.vyos'
- name: Create backup dir
file:
path: "/tmp/backups/{{ inventory_hostname }}"
state: directory
recurse: yes
- name: Copy backup files into /tmp/backups/ (eos)
copy:
src: "{{ backup_eos_location.backup_path }}"
dest: "/tmp/backups/{{ inventory_hostname }}/{{ inventory_hostname }}.bck"
when: ansible_network_os == 'arista.eos.eos'
- name: Copy backup files into /tmp/backups/ (vyos)
copy:
src: "{{ backup_vyos_location.backup_path }}"
dest: "/tmp/backups/{{ inventory_hostname }}/{{ inventory_hostname }}.bck"
when: ansible_network_os == 'vyos.vyos.vyos'
步骤 3:运行 playbook
要运行 playbook,请在控制台提示符下运行以下命令
ansible-playbook -i inventory facts-demo.yml
这应该返回类似于以下内容的输出
PLAY RECAP
eos01.example.net : ok=7 changed=2 unreachable=0 failed=0
ios01.example.net : ok=7 changed=2 unreachable=0 failed=0
vyos01.example.net : ok=6 changed=2 unreachable=0 failed=0
步骤 4:检查 playbook 结果
接下来,查看我们创建的文件的内容,其中包含交换机 facts
cat /tmp/switch-facts
您还可以查看备份文件
find /tmp/backups
如果 ansible-playbook 失败,请按照 网络调试和故障排除指南 中的调试步骤操作。
示例 2:使用平台无关模块简化 playbook
(此示例最初出现在 Sean Cavanaugh 的 网络自动化 cli_command 深入指南 博客文章中 -@IPvSean)。
如果您的环境中存在两个或多个网络平台,则可以使用平台无关模块来简化 playbook。您可以使用平台无关模块,例如 ansible.netcommon.cli_command
或 ansible.netcommon.cli_config
,来代替特定于平台的模块,例如 arista.eos.eos_config
、cisco.ios.ios_config
和 junipernetworks.junos.junos_config
。这减少了 playbook 中需要的任务和条件的数量。
注意
平台无关模块需要 ansible.netcommon.network_cli 连接插件。
使用平台特定模块的示例 playbook
此示例假设三个平台:Arista EOS、Cisco NXOS 和 Juniper JunOS。在没有平台无关模块的情况下,示例 playbook 可能包含以下三个具有平台特定命令的任务
---
- name: Run Arista command
arista.eos.eos_command:
commands: show ip int br
when: ansible_network_os == 'arista.eos.eos'
- name: Run Cisco NXOS command
cisco.nxos.nxos_command:
commands: show ip int br
when: ansible_network_os == 'cisco.nxos.nxos'
- name: Run Vyos command
vyos.vyos.vyos_command:
commands: show interface
when: ansible_network_os == 'vyos.vyos.vyos'
使用 cli_command
平台无关模块的简化 playbook
您可以使用平台无关的 ansible.netcommon.cli_command
模块替换这些平台特定模块,如下所示
---
- hosts: network
gather_facts: false
connection: ansible.netcommon.network_cli
tasks:
- name: Run cli_command on Arista and display results
block:
- name: Run cli_command on Arista
ansible.netcommon.cli_command:
command: show ip int br
register: result
- name: Display result to terminal window
debug:
var: result.stdout_lines
when: ansible_network_os == 'arista.eos.eos'
- name: Run cli_command on Cisco IOS and display results
block:
- name: Run cli_command on Cisco IOS
ansible.netcommon.cli_command:
command: show ip int br
register: result
- name: Display result to terminal window
debug:
var: result.stdout_lines
when: ansible_network_os == 'cisco.ios.ios'
- name: Run cli_command on Vyos and display results
block:
- name: Run cli_command on Vyos
ansible.netcommon.cli_command:
command: show interfaces
register: result
- name: Display result to terminal window
debug:
var: result.stdout_lines
when: ansible_network_os == 'vyos.vyos.vyos'
如果您按平台类型使用组和 group_vars,则可以进一步简化此 playbook 为
---
- name: Run command and print to terminal window
hosts: routers
gather_facts: false
tasks:
- name: Run show command
ansible.netcommon.cli_command:
command: "{{show_interfaces}}"
register: command_output
您可以在 平台无关示例 中看到使用 group_vars 的完整示例以及配置备份示例。
使用 ansible.netcommon.cli_command
的多个提示
ansible.netcommon.cli_command
也支持多个提示。
---
- name: Change password to default
ansible.netcommon.cli_command:
command: "{{ item }}"
prompt:
- "New password"
- "Retype new password"
answer:
- "mypassword123"
- "mypassword123"
check_all: True
loop:
- "configure"
- "rollback"
- "set system root-authentication plain-text-password"
- "commit"
有关此命令的完整文档,请参阅 ansible.netcommon.cli_command。
实施说明
演示变量
虽然这些任务不需要将数据写入磁盘,但它们在本例中用于演示访问有关给定设备或命名主机的一些 facts 的某些方法。
Ansible hostvars
允许您访问命名主机的变量。如果没有它,我们将返回当前主机的详细信息,而不是命名主机的详细信息。
有关更多信息,请参阅 关于 Ansible:魔法变量。
获取运行配置
arista.eos.eos_config 和 vyos.vyos.vyos_config 模块具有 backup:
选项,设置该选项后,模块将在进行任何更改之前创建来自远程设备的当前 running-config
的完整备份。备份文件写入 playbook 根目录中的 backup
文件夹。如果目录不存在,则会创建它。
为了演示如何将备份文件移动到其他位置,我们注册结果并将文件移动到存储在 backup_path
中的路径。
请注意,以这种方式使用任务中的变量时,我们使用双引号("
)和双花括号({{...}}
)来告诉 Ansible 这是一个变量。
故障排除
如果您收到连接错误,请仔细检查清单和 playbook 中是否存在错别字或缺少的行。如果问题仍然存在,请按照 网络调试和故障排除指南 中的调试步骤操作。