有了这款运维自动化神器,可以抛弃 Ansible 了!
The following article is from NetDevOps加油站 Author 九净
文末赠书
作者:九净
来源:NetDevOps加油站
背景
今天开始一个新的大坑,绝对是巨坑了,给大家安利一款网络运维自动化工具Nornir(北欧神话里的命运女神三姐妹的名字)。
提起运维自动化的工具,扛把子目前还是ansible。究其原因还是高度的封装,良好的生态,基于这两个大杀器,简单写个yaml文件就可以编排出一个符合我们预期的自动化场景。
但是,看过我文章的小伙伴都知道,我对ansible是爱恨交加,大爱无言,就此掠过,我就说说“恨”:
国产网络设备的适配之路,难于上青天,说多了都是泪,国产的除了华为官方支持,其他的我真是见不到了。基于ssh采集设备信息时没大问题,但是配置起来,那就是几乎不敢用,因为网络配置回显提示不断在变化,low level的调用,无法加以分情况的判断。 性能问题,逻辑设计过于复杂,层层的调用等各种原因导致其性能不佳,主要体现在并发不行,执行效率略低,大家对之诟病不少。如果网络设备多点,就得多弄几台服务器了。也有人提出ansible可以调优,但是对于大多数用户来说,过于复杂。性能问题也主要针对一个中大型的网络环境,其实几台设备,无所谓效率,for循环就可以了。 它想简化或者弱化编程语言的内容,倡导低代码开发,但是在一些复杂场景,个人觉得适得其反,循环判断等的使用,让人感觉犬牙交错,不如if else while for等简单快捷易读。 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
从配置上来看,我们也可以看出它的两个主要功能:
指定加载资产的方式和路径 指定运行的方式,比如默认的线程及并发量
资产清单相关配置
plugin: SimpleInventory,我们就用默认的即可,它的意思是用SimpleInventory这个插件来加载清单。
我们可以重写这个插件来对接我们的CMDB或者是csv文件都可以,只要按标准格式返回资产数据即可。
默认它有几个重要的参数就是资产相关的文件的path。
资产清单相关配置,一般放到inventory的文件夹内,内含三个文件:
host.yaml
设备清单,字典的方式梳理所有设备,key值为设备名称,value值是个字典,
设备的属性分为三个大部分:
设备基本信息:包含设备的IP或者hostname,用户名密码,连接的端口,设备的platform,这些参数都可以无缝对接netmiko和napalm。 所属组groups,list形式,每个组都有很多属性,比如接入交换机有些基本的配置,类似的。 参数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,手动狗头!
送书活动
赠书规则
赠书本数:本次共包邮送书 3 本
Python猫技术交流群开放啦!群里既有国内一二线大厂在职员工,也有国内外高校在读学生,既有十多年码龄的编程老鸟,也有中小学刚刚入门的新人,学习氛围良好!想入群的同学,请在公号内回复『交流群』,获取猫哥的微信(谢绝广告党,非诚勿扰!)~
还不过瘾?试试它们