查看原文
其他

有了这款运维自动化神器,可以抛弃 Ansible 了!

Python猫 2022-04-12

The following article is from NetDevOps加油站 Author 九净

△点击上方“Python猫”关注 ,回复“1”领取电子书

文末赠书

作者:九净

来源:NetDevOps加油站

背景

今天开始一个新的大坑,绝对是巨坑了,给大家安利一款网络运维自动化工具Nornir(北欧神话里的命运女神三姐妹的名字)。

提起运维自动化的工具,扛把子目前还是ansible。究其原因还是高度的封装,良好的生态,基于这两个大杀器,简单写个yaml文件就可以编排出一个符合我们预期的自动化场景。

但是,看过我文章的小伙伴都知道,我对ansible是爱恨交加,大爱无言,就此掠过,我就说说“恨”:

  1. 国产网络设备的适配之路,难于上青天,说多了都是泪,国产的除了华为官方支持,其他的我真是见不到了。基于ssh采集设备信息时没大问题,但是配置起来,那就是几乎不敢用,因为网络配置回显提示不断在变化,low level的调用,无法加以分情况的判断。
  2. 性能问题,逻辑设计过于复杂,层层的调用等各种原因导致其性能不佳,主要体现在并发不行,执行效率略低,大家对之诟病不少。如果网络设备多点,就得多弄几台服务器了。也有人提出ansible可以调优,但是对于大多数用户来说,过于复杂。性能问题也主要针对一个中大型的网络环境,其实几台设备,无所谓效率,for循环就可以了。
  3. 它想简化或者弱化编程语言的内容,倡导低代码开发,但是在一些复杂场景,个人觉得适得其反,循环判断等的使用,让人感觉犬牙交错,不如if else while for等简单快捷易读。
  4. ansible是基于Python开发的,我感觉是有点矛盾的,有时候刻意的弱化Python,某些情况下debug及其麻烦,如果能用pycharm debug一个脚本该多好;有时候又宣称是Python开发的,可以二次开发,自己写一些module,但是这个过程又是debug麻烦,且封装的过于高深,用户自己开发的时候,我觉得门槛过高。

不一一列举了,再写,这篇文章又偏了,可以改成细数ansible在略微复杂的网络中运维自动化的N种罪状。

Nornir简介

回归主题,介于以上种种,作为一个懂点Python的网络工程师,我们有没有一个更好的工具呢?

答案是有的,开题就告诉了大家,我们今天的主角闪亮登场——Nornir!

Nornir是一个用python编写的自动化框架,主要是针对网络运维自动化,只要你懂一点点Python,就可以非常方便的使用nornir了。

由于Nornir允许用户使用纯Python代码,所以我们可以使用与其他Python代码相同的方法对其进行故障排除和调试,这就解决了那些低代码的自动化工具的调试和排障困难的问题。

Nornir自比是自动化界的Flask,侧面反映它的强大与灵活。(笔者是一个django的死忠粉,手动狗头)。

flask是一个Python的web开发框架,flask没有限制过多的接口,所以用户可以基于恰到好处的接口,基于自己的方式构建一个功能强大的web网站。nornir也是同样的事情,它无外乎实现了几种核心的功能,比如管理好资产、变量,内置一些与设备的常见的连接方式,自动关联并批量执行、支持插件这些自动化框架最基本的功能,你可以写自己的各种插件,实现任何你想实现的功能,而且是基于Python的,想想就让人很兴奋,再也不用去看那些过于复杂的playbook或者类似的配置文件了。

说了这么多,我们来看看nornir的runbook长什么样子吧。

from nornir import InitNornir
from nornir_utils.plugins.functions import print_result
from nornir_napalm.plugins.tasks import napalm_get

nr = InitNornir(
config_file="nornir.yaml", dry_run=True
)

results = nr.run(
task=napalm_get, getters=["facts", "interfaces"]
)
print_result(results)

以上是一个简单的官方示例,通过一个官方的内置插件nornir_napalm(其实需要单独安装,并不在本体里),集成了napalm(这又是一个我要吐槽的工具包,功能甚少,缺乏高层构建,改天再写写文章)。通过napalm获取了端口和基本的fact信息。

从代码上来看,清晰易读,加载了nornir的yaml配置文件,获取设备的清单及其他变量分组等等,然后全部设备批量执行信息获取,输出结果。

整个代码,核心逻辑实际只有1行,获取信息,比ansible的,我觉得要简单好多,对于一个稍微懂点Python的网工而言。

对于绝大多数的使用,nornir不需要用户知道过多的python知识,什么并发、异步、写log、回调,统统都走开,你只需要会最基本的Python技能即可,知晓基本的数据类型、定义变量、循环、判断、函数的定义与使用,基本就足够了。Noinir也是这样主张的,Python其实是一门易上手的语言,但是任务编程语言的精通都是需要时间和精力的。但是幸运的是,作为网络工程师,我们只是想写一些脚本,实现自动化,并不是要成为一位master。所以Nornir认为我们掌握基本的Python知识即可。(对于绝大多数网络运维工程师,我觉得这个是适用的,有意精通此道的,仍需不断努力精进)

说实话,作为一名NetDevOps工程师,多进程、多线程、协程等等这些我在日常中几乎没有使用过,包括我也从来没写过这方面的内容,因为我认为这块对于一个网络运维工程师来说,过于深奥,使用起来坑很多,其实是过于简单的使用并发推配置,我都是坚决反对的,无知者无畏,对于生产中的网络配置,我从来都是怀揣着一颗敬畏之心。我也推荐大家使用一些自动化框架或者其他工具实现并发,同时如果是推送配置,一定要慎重,可以的话尽量设计的是有检查机制或者可以终止的,防止手抖了后没有后悔的机会,不行连并发都别用。

Nornir的安装、版本及插件说明

官方是建议大家使用虚拟环境安装的,我也建议大家使用虚拟环境安装,因为它里面的很多版本管理的比较精细,不建议放到我们的系统或者自己常用的Python环境中去。

它支持3.6.2及以上的Python版本,这点我表示很赞,就不该给python2活路,赶紧演进。我建议大家使用3.7、3.8的版本。之前也讲过,我们用的Python都是最基础的Python知识,所以脚本的版本兼容会比较好一些。笔者使用的是3.8.3的版本,究竟原因,是因为我懒,装了一个anaconda。

本系列讲的是基于Nornir3.0.0这个版本,同时解释一下,网上关于Nornir的讲解本来就少(基本都是国外的),大多数是基于2.4和2.5的版本,3.0版本今年才发布(2020年),发生了一些变化,导致了一些配置文件的不兼容,所以大家不管是看我的还是其他人的视频或者文章也好,一定要留意版本。

老规矩,pip install nornir即可安装

$ pip install nornir
Collecting nornir
Downloading nornir-3.0.0-py3-none-any.whl (28 kB)
Requirement already satisfied: typing_extensions<4.0,>=3.7 in /home/dbarroso/.virtualenvs/tmp-nornir/lib/python3.8/site-packages (from nornir) (3.7.4.2)
Requirement already satisfied: mypy_extensions<0.5.0,>=0.4.1 in /home/dbarroso/.virtualenvs/tmp-nornir/lib/python3.8/site-packages (from nornir) (0.4.3)
Collecting ruamel.yaml<0.17,>=0.16
Using cached ruamel.yaml-0.16.10-py2.py3-none-any.whl (111 kB)
Collecting ruamel.yaml.clib>=0.1.2; platform_python_implementation == "CPython" and python_version < "3.9"
Using cached ruamel.yaml.clib-0.2.0-cp38-cp38-manylinux1_x86_64.whl (578 kB)
Installing collected packages: colorama, ruamel.yaml.clib, ruamel.yaml, nornir
Successfully installed nornir-3.0.0 ruamel.yaml-0.16.10 ruamel.yaml.clib-0.2.0

安装之后,可以打开ipython试试,没报错即可。

$ python
>>> from nornir import InitNornir
>>>

关于插件,我们也得唠唠,2.4 2.5的时候,很多东西都是内置的,但是3.0版本发生了很大的变化,官方把一些插件,分拆了出去,nornir变得更加纯粹了。比如以前的时候nornir支持netmiko和napalm等,现在统统分拆出去了,创建了新工具包,比如nornir_napalm就是nornir的一个对napalm封装,同样的也有nornir_netmiko,很多很多工具包都被这样分解出去了。有点像flask,它只提供最基础的web开发框架,如果想实现一些admin后台或者表单相关的,需要安装对应的flask工具包。

nornir的官方网站是https://nornir.tech/ 在https://nornir.tech/nornir/plugins/ 我们可以看到官方的插件list,插件list分成几种:任务类的、连接类的、资源管理类的、进程管理、函数功能等等,比如netmiko就是一个任务类和连接类的插件包

每个都会连接到github上,非常棒的是nornir_netmiko的作者就是netmiko的作者。所以回归到我们之前说的第一个问题,国产化问题,ansible的大难题(开源版本至少是这样的,不知道有没有收费的隐藏资源),在nornir面前就不再是问题了,因为netmiko对国产设备支持的还是比较好的,目前ruijieos都支持了,撒花!所以nornir可以非常方便的对国产设备进行批量操作,包含配置下发。

一个简单的Nornir runbook

讲了这么多,我们赶紧来简简单单看看nornir是如何简单的开发出一个runbook的吧。

Nornir的文件组织架构及基本配置

一个nornir的runbook,类似ansible的,也有配置和设备清单及playbook的类似概念。

以上就是一个nornir的文件结构。

配置文件 config.yaml

我们先看看它的配置文件,nornir的配置文件使用的是可读性和书写便利性比较好的yaml文件。

我们打开config.yaml文件,当然你也可以改成其他名称。

---
inventory:
plugin: SimpleInventory
options:
host_file: "inventory/hosts.yaml"
group_file: "inventory/groups.yaml"
defaults_file: "inventory/defaults.yaml"

runner:
plugin: threaded
options:
num_workers: 100

从配置上来看,我们也可以看出它的两个主要功能:

  1. 指定加载资产的方式和路径
  2. 指定运行的方式,比如默认的线程及并发量

资产清单相关配置

plugin: SimpleInventory,我们就用默认的即可,它的意思是用SimpleInventory这个插件来加载清单。

我们可以重写这个插件来对接我们的CMDB或者是csv文件都可以,只要按标准格式返回资产数据即可。

默认它有几个重要的参数就是资产相关的文件的path。

资产清单相关配置,一般放到inventory的文件夹内,内含三个文件:

host.yaml

设备清单,字典的方式梳理所有设备,key值为设备名称,value值是个字典,

设备的属性分为三个大部分:

  1. 设备基本信息:包含设备的IP或者hostname,用户名密码,连接的端口,设备的platform,这些参数都可以无缝对接netmiko和napalm。
  2. 所属组groups,list形式,每个组都有很多属性,比如接入交换机有些基本的配置,类似的。
  3. 参数data,字典格式,用户可以根据需求自己定义,比如定义一个role后续筛选,或者自己的一些配置预定义等等
groups.yaml

设备会划拨给一些组,组里会有一些公用的属性,这个后续我们再详细分解

default.yaml

全局默认的一些参数,按下不表,后续章节我们再详细分解

这三个最最核心的我觉得是hosts,资产清单是最最核心的。

初始化对象,尝试打印出资产清单

我们通过引入InitNornir初始化一个Nornir对象

from nornir import InitNornir
nr = InitNornir(
config_file="nornir.yaml"
)

然后我们就可以直接打印出我们的设备清单了。

# list hosts
print(nr.inventory.hosts)
{'dev01': Host: dev01, 'dev02': Host: dev02, 'dev03': Host: dev03}

它返回的是一个字典,key是设备名称,value是一个复杂的nornir内置的host对象,可以获取yaml文件内的一切,甚至更多。后续我也会尝试讲解一下Nornir的内置的一些重要的基本类。

给每台设备一个自定义task运行

很多自动化框架的逻辑,基本就是有设备清单,然后在设备清单中做出筛选(默认全部),然后每台设备去执行自己的task。nornir也是这个逻辑。

我们已经有了资产清单,我们想给每个设备安排一个任务,该怎么处理呢?

我们可以自己定义一个灵活的task,它的写法如下。

from nornir import InitNornir
from nornir_utils.plugins.functions import print_result

devices = InitNornir(
config_file="nornir.yaml"
)


def hi(task):
words = f"Hi!I'm a network device. My name is {task.host.name}"
return words


results = devices.run(task=hi,name='A task for saying hi!')

print_result(results)

自定义函数|task

重点是hi这个函数,它的第一个参数是task,这个地方可以简单理解成一个任务的上下文。

后续是我们自己定义的参数,第一个,我们写的简单点,默认就让每台设备介绍一下自己。

每台设备都可以从task中取出自己的name,如上task.host.name

然后我们把想要返回的打印到屏幕上的return即可。

实际过程中,我们可以写成每个设备执行自己的业务逻辑,比如信息采集、配置推送、起关端口等等,这个逻辑内部的很多都是可以受我们控制的,比如基本设备信息都可以从task中获取,然后调用netmiko或者ncclient等等,当然netmiko都有官方的插件包。这样就非常灵活了,我们简单写几个代码,借助netmiko批量配置就非常简单,后续也会展开介绍。

Nornir的灵活有一部分就体现在task里,可以非常灵活的定制自己的业务逻辑。

批量执行自定义的task

第二个重点来了,devices.run,devices就是我们初始化的Nornir对象,早期版本及官方版本会使用nr作为代替,类似pd代替pandas,有一些博主的视频代码里会写成筛选出来的设备,比如路由就写routers作为Nornir对象的变量名,这样可读性更好,有点所有设备执行任务的感觉。这个run有几个重要参数,我们今天初步介绍,最重要的是task,就是我们要调用哪个函数,这个时候我们传入自己定义函数(本例是hi),name是打印的时候显示的会比较好的而设计的,不写也没事。

漂亮的打印出来

我们调用官方的插件包nornir_utils,这个需要pip安装。引入print_result,直接打印返回的结果即可。

我们看看效果

非常仿Ansible,有木有,每台设备并发执行,结果统统显示出来。

小结与脑洞大开

以上就是一个Nornir的最最基础的使用方式了,在定义好hosts文件之后,我们可以写自己的task函数,可以写的很简单,也可以写的很复杂,开个脑洞,比如基于netmiko或者paramiko,配置备份,传到指定FTP,或者git仓库,作为一个版本备份及管理的脚本;中间的设备可以不停的筛选,同时根据返回的信息不停的判断,从而执行一些复杂场景,比如一些应急场景,或者涉及到多台设备的联动配置等等。

再奉上一段代码,我们后续也会深入讲解,基于官方netmiko插件包写的。

对设备进行一个批量执行,我们之前也讲过很多netmiko的例子,这个官方的插件包与Nornir无缝对接,我们不用再去构建连接,Nornir自动帮我们创建连接

from nornir import InitNornir
from nornir_utils.plugins.functions import print_result
from nornir_netmiko import netmiko_send_command

nr = InitNornir(
config_file="nornir.yaml"
)


def show_cmds(task):
cmds = task.host.data['cmds']
outputs = []
for cmd in cmds:
outputs.append(task.run(netmiko_send_command,command_string=cmd))
return outputs
results = nr.run(task=show_cmds)
print_result(results)

这段代码也比较简单,我们就是获取了设备里配置的data中的cmds命令行列表,然后执行了官方插件的netmiko_send_command命令,传入了cmd命令,并将结果放入outputs返回,这中间可以做的实际非常多,我们可以用textfsm解析归档,可以show run 备份,可以下发配置,看看结果,每台设备执行的情况我们都可以一目了然。

这个设备是一台华为的ce系列交换机(模拟器),我们都知道,netmiko对国产化设备支持目前是比较好的,我们通过这种方式,对华为华三的配置都可以实现,ansible支持的网络设备实在有限,且和设备软件版本有一定关联,但是基于netmiko,我们使用ssh加命令行即可,目前为止,在一个中大型或者是不单纯的网络环境中,我个人习惯称之超融合网络,命令行辅之以其他方式,有能力的上层封装统一,能力暂时不足或者没特殊想法的单纯命令行一梭子到底即可,这是我认为的,目前NetDevOps的最佳实现。

在国外,NetDevOps的使用比较广泛的还有napalm、netbox,Nornir与之都可以很方便对接,它也是有一定生态的,同时也可以非常方便的自己写插件扩展,或者硬编码连接方式到task中非常暴力的执行命令等等。nornir的核心代码据说5000+,我看了看,真的是非常简单,但是考虑的很周全灵活,灵活我们讲了,简单的设计,还有一个非常好的结果就是执行效率高,在中大型网络环境中,真的是可以秒杀ansible,大家如果写过ansible,也应该深有体会,我们就是想执行一个show version,结果要等很长时间处理一堆东西,返回的巨慢,但是nornir就非常赞,很快就完成与设备的交互返回结果。

同时之前也说过,它是pure python写的,所以我们可以非常灵活的定制很多内容。这其实是一把双刃剑,根据使用者能力和脑洞,用好了可以帮我们解决很多问题,但是python本身就对使用者的Python有了一定要求,无法像ansible那样去低代码开发,所以Nornir的目标用户还是NetDevOps工程师多一些。

好吧,今天的分享就到这里结束了,后续有机会也与大家继续分享,毕竟这也是一个大坑。关于Nornir的相关博文非常少,中文的应该是没,也不成体系,本系列后续会不断给大家分享一些nornir的分析与讲解,希望在国内网工界引入这个非常棒的网络运维自动化框架,网络人专属的“ansible”,喷完了ansible,又碰瓷ansible,手动狗头!

送书活动

新一期的赠书活动,感谢北京大学出版社赞助。
1、内容全面:借助5大 Python工具库,实现数据分析从获取到建模全流程覆
2、贴合实际:不空讲 Python语法,清晰简明地介绍如何用Python来处理、分析数据
3、热点案例:覆盖6大热点应用领域,可直接参考研发,实现数据变现

赠书规则

赠书本数:本次共包邮送书 

参与方式:在Python猫读者群抽奖,仅限群友参与。后台发“交流群”,获取入群方式。
开奖时间:2021年5月30日18:00

Python猫技术交流群开放啦!群里既有国内一二线大厂在职员工,也有国内外高校在读学生,既有十多年码龄的编程老鸟,也有中小学刚刚入门的新人,学习氛围良好!想入群的同学,请在公号内回复『交流群』,获取猫哥的微信(谢绝广告党,非诚勿扰!)~


还不过瘾?试试它们




坚持原创很难,但我不会放弃!

Python 的缩进是不是反人类的设计?

冗长的 Python 代码,如何重构?

耗时两年,我终于出了一本电子书!

Python 性能测试工具 Locust 极简入门

由浅入深:Python 中如何实现自动导入缺失的库?


如果你觉得本文有帮助
请慷慨分享点赞,感谢啦

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存