Ansible 网络示例

本文档介绍了一些使用 Ansible 管理网络基础设施的示例。

先决条件

此示例需要以下内容

  • 已安装 Ansible 2.10(或更高版本)。有关详细信息,请参阅 安装 Ansible

  • 一个或多个与 Ansible 兼容的网络设备。

  • 对 YAML 的基本了解 YAML 语法

  • 对 Jinja2 模板的基本了解。有关详细信息,请参阅 模板化(Jinja2)

  • 基本 Linux 命令行使用。

  • 对网络交换机和路由器配置的基本了解。

库存文件中的组和变量

一个 inventory 文件是一个 YAML 或 INI 样式的配置文件,它定义了主机到组的映射。

在我们的示例中,库存文件定义了 eosiosvyos 组以及一个名为 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”功能允许您将敏感数据(如密码或密钥)保存在加密文件中,而不是以纯文本形式保存在您的剧本或角色中。然后,可以分发或放置在源代码控制中这些 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)具有不同特权模式的概念。某些网络模块(例如修改系统状态(包括用户)的模块)只能在高特权状态下工作。Ansible 支持在使用 connection: ansible.netcommon.network_cli 时使用 become。这允许为需要它们的特定任务提升特权。添加 become: yesbecome_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:使用剧本收集事实并创建备份文件

Ansible 事实模块收集系统信息“事实”,这些信息可用于剧本的其余部分。

Ansible Networking 附带许多网络特定事实模块。在此示例中,我们使用 _facts 模块 arista.eos.eos_factscisco.ios.ios_factsvyos.vyos.vyos_facts 连接到远程网络设备。由于凭据没有通过模块参数明确传递,因此 Ansible 使用库存文件中的用户名和密码。

Ansible 的“网络事实模块”从系统收集信息并将结果存储在以 ansible_net_ 为前缀的事实中。这些模块收集的数据记录在模块文档的“返回值”部分中,在本例中为 arista.eos.eos_factsvyos.vyos.vyos_facts。我们可以使用事实,例如 ansible_net_version,在“显示一些事实”任务中稍后使用。

为了确保我们调用正确的模式(*_facts),任务是根据库存文件中定义的组有条件地运行的。有关 Ansible 剧本中条件语句用法的更多信息,请参阅 使用 when 语句的基本条件

在此示例中,我们将创建一个包含一些网络交换机的库存文件,然后运行一个剧本来连接到网络设备并返回有关它们的某些信息。

步骤 1:创建库存

首先,创建一个名为 inventory 的文件,其中包含

[switches:children]
eos
ios
vyos

[eos]
eos01.example.net

[ios]
ios01.example.net

[vyos]
vyos01.example.net

步骤 2:创建剧本

接下来,创建一个名为 facts-demo.yml 的剧本文件,其中包含以下内容

- 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:运行剧本

要运行剧本,请在控制台提示符中运行以下命令

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:检查剧本结果

接下来,查看我们创建的包含交换机事实的文件内容

cat /tmp/switch-facts

您还可以查看备份文件

find /tmp/backups

如果 ansible-playbook 失败,请按照 网络调试和故障排除指南 中的调试步骤操作。

示例 2:使用平台无关模块简化剧本

(此示例最初出现在 Sean Cavanaugh 在 网络自动化中 cli_command 深入解析 博客文章中 -@IPvSean)。

如果您的环境中存在两个或多个网络平台,您可以使用平台无关模块来简化您的剧本。您可以使用平台无关模块,例如 ansible.netcommon.cli_commandansible.netcommon.cli_config 来代替平台特定模块,例如 arista.eos.eos_configcisco.ios.ios_configjunipernetworks.junos.junos_config。这将减少剧本中所需的任务和条件语句的数量。

注意

平台无关模块需要 ansible.netcommon.network_cli 连接插件。

使用平台特定模块的示例剧本

此示例假设存在三个平台,Arista EOS、Cisco NXOS 和 Juniper JunOS。如果没有平台无关模块,示例剧本可能包含以下三个使用平台特定命令的任务

---
- 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 平台无关模块的简化剧本

您可以使用平台无关的 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,则此剧本可以进一步简化为

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

实施说明

演示变量

虽然这些任务不是编写数据到磁盘所必需的,但它们在本示例中用于演示访问有关给定设备或命名主机的一些事实的方法。

Ansible hostvars 允许您访问命名主机的变量。如果没有它,我们将返回当前主机的详细信息,而不是命名主机。

有关更多信息,请参阅 有关 Ansible 的信息:神奇变量

获取运行配置

arista.eos.eos_configvyos.vyos.vyos_config 模块具有一个 backup: 选项,当设置此选项时,模块会在进行任何更改之前从远程设备创建当前 running-config 的完整备份。备份文件写入剧本根目录中的 backup 文件夹。如果目录不存在,则创建该目录。

为了演示如何将备份文件移动到另一个位置,我们注册了结果并将文件移动到 backup_path 中存储的路径。

请注意,使用这种方式从任务中使用变量时,我们使用双引号 (") 和双花括号 ({{...}}) 来告诉 Ansible 这是一个变量。

故障排除

如果您收到连接错误,请仔细检查清单和剧本中是否存在拼写错误或缺少的行。如果问题仍然存在,请按照 网络调试和故障排除指南 中的调试步骤操作。