文章來源於呵呵ADC ,作者劉超
先解釋一下標題,引用Nornir作者之一的Patrick Ogenstad測試結果,
原文連結https://networklore.com/ansible-nornir-speed/。
配置1萬台設備,Ansible需要2300秒,Nornir只需要17秒,處理5000台設備Ansible需要900秒,Nornir只需要9秒,就是那麼快….

Nornir是三位北歐神話中負責塑造人類命運的神靈。現實中代表了三位作者,分別是David Barroso(Napalm作者),Kirk Byers(netmiko作者)和Patrick Ogenstad。

實戰效果
本文最終實現效果為通過Nornir自動化配置 Citrix ADC 的時區,啟用功能模組和模式。配置2個VS 分別為 vs22 和 vs33,分別綁定 service group sg22 和 sg33。vs33 修改負載均衡演算法為輪詢,會話保持方法為源 IP。
安裝Nornir
我的環境都裝的最新版本
- pip install nornirpip
- install nornir-jinja2
- pip install nornir-netmiko
- pip install nornir-utils
inventory文件
創建inventory資料夾,在資料夾下創建三個文件分別為default.yaml , groups.yaml , hosts.yaml。
default.yaml 的作用是就用來填補 hosts.yaml 裡沒有的參數,也就是說在運行 Nornir 腳本時,如果 Nornir 發現 hosts.yaml 裡沒有設備的 username 和 password,那麼它會直接去看 defaults.yaml 是否有對應的參數並使用。本文用不到留空就好。
在 groups.yaml 裡創建了一個叫做 dc_adc 的分組(組名自訂,隨便叫)。另外 Nornir 是通過netmiko 基於 SSH 和設備通訊的,netmiko 支援 Citrix ADC,它定義的 platform 就叫 netscaler,這是固定的。設備用戶名密碼定義在這裡。
這裡有個小坑,如果密碼是純數位,則必須加引號,比如 password: ‘123’,如果不含數位或者是字母+數位(字母開頭或者數位開頭都無所謂)的組合,則無須加引號。
- dc_adc:
- platform: netscaler
- username: nsroot
- password: citrix@123
hosts.yaml 檔如下,vpx1 給設備起個名字,groups 屬於 groups.yaml 檔裡定義的組 dc_adc,hostname 為設備的 nsip。data 部分為具體配置的內容,這裡相對比較靈活也比較費勁,因為格式是純自己設計自由寫的,只要滿足 YAML 的語法就行隨意發揮,當然要和後面的範本配合來寫。這裡也是基礎架構即代碼所宣導的聲明式語法,這裡就是聲明了配置 Citrix ADC 的時區為 “GMT+08:00-CST-Asia/Shanghai”,要啟用功能模組 LB,RESPONDER,SSL 和模式 MBF。要配置2個 VS 分別為 vs22 和 vs33,分別綁定 service group sg22 和 sg33。vs33 要負載均衡演算法為輪詢,會話保持方法為源 IP,聲明完了扔給自動化框架去實現就好了。
- vpx1:
- groups:
- dc_adc
- hostname: 192.168.26.90
- data:
- site: beijing
- type: adc
- timezone: “GMT+08:00-CST-Asia/Shanghai”
- feature_list:
- – LB
- – RESPONDER
- – SSL
- mode_list:
- MBF
- lb_list:
- vs_name: vs22
- ipaddr: 22.22.22.22
- protocol: http
- vs_port: 80
- method:
- persistence:
- sg_name: sg22
- sg_port: 80
- server_list:
- – 172.16.10.10
- – 172.16.10.11
- – 172.16.10.12
- vs_name: vs33
- ipaddr: 33.33.33.33
- protocol: http
- vs_port: 80
- method: roundrobin
- persistence: sourceip
- sg_name: sg33
- sg_port: 80
- server_list:
- 172.16.10.15
- 172.16.10.16
- 172.16.10.17
config文件
在專案根目錄下創建 config.yaml, 分別設置 host_file , group_file , defaults_file 為上一步在inventory 目錄下創建的 hosts.yaml,groups.yaml,defaults.yaml 文件。Nornir 快的原因也在這裡體現,多執行緒併發執行配置任務在這裡設置。
- 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
template文件
在btemplatesb目錄下創建2個檔,ns_global.templateb和bns_lb.template。ns_global.template用於生成配置時區,啟用功能和模式的命令列,ns_lb.templateb 用於生成配置 vs,sg的命令列。
這裡的 template 使用 jinjia2 範本語法,簡單介紹{{}}中間為變數部分,host.name 為從hosts.yaml 部分的 timezone 欄位獲取內容,因此 set ns param -timezone {{ host.timezone }}將生成配置命令 set ns param -timezone “GMT+08:00-CST-Asia/Shanghai”。
{% for %}為迴圈語法,host.feature_list 從 hosts.yaml 部分的 feature_list 欄位獲取內容即得到清單 [LB,RESPONDER,SSL] , 對該列表執行 for 迴圈即取出列表的每一個值賦值給變數i,因此通過範本可以生成三條命令 enable ns feature LB, enable ns feature RESPONDER, enable ns feature SSL
- set ns param -timezone {{ host.timezone }}
- {% for i in host.feature_list %}
- enable ns feature {{ i }}
- {% endfor %}
- {% for i in host.mode_list %}
- enable ns mode {{ i }}
- {% endfor %}
jinjia2 語法也支援 if-else 判斷,這裡因為要判斷 hosts.yaml 檔的 data 部分是不是聲明了method 和 persistence,如果有就生成包含 -lbMethod 和 -persistenceType 的配置命令,如果沒有就不帶選項。這裡也許有更優化的寫法,後續可以研究看看。
- {% for i in host.lb_list %}
- {% if i.method and i.persistence %}
- add lb vserver {{ i.vs_name }} {{ i.protocol }} {{ i.ipaddr }} {{ i.vs_port }} -lbMethod {{ i.method }} -persistenceType {{ i.persistence }}
- {% elif i.method %}
- add lb vserver {{ i.vs_name }} {{ i.protocol }} {{ i.ipaddr }} {{ i.vs_port }} -lbMethod {{ i.method }}
- {% elif i.persistence %}
- add lb vserver {{ i.vs_name }} {{ i.protocol }} {{ i.ipaddr }} {{ i.vs_port }} -persistenceType {{ i.persistence }}
- {% else %}
- add lb vserver {{ i.vs_name }} {{ i.protocol }} {{ i.ipaddr }} {{ i.vs_port }}
- {% endif %}
- add serviceGroup {{ i.sg_name }} {{ i.protocol }}
- {% for n in i.server_list %}
- bind serviceGroup {{ i.sg_name }} {{ n }} {{ i.sg_port }}
- {% endfor %}
- bind lb vserver {{ i.vs_name }} {{ i.sg_name }}
- {% endfor %}
final_task文件
在根目錄下創建 final_task.py 檔,Nornir 是通過 python 來執行最終配置的,代碼具體作用可參見注釋。
- from nornir import InitNornir
- from nornir_netmiko.tasks import netmiko_send_config
- from nornir_jinja2.plugins.tasks import template_file
- from nornir_utils.plugins.functions import print_result
- # 載入設定檔config.yaml
- nr = InitNornir(
- config_file=“config.yaml”,
- )
- # 過濾台北的adc
- ns = nr.filter(
- type=“adc”,
- site=‘taipei’
- )
- # 配置NS的函數
- def config_ns(task):
- # 讀取ns_global_template範本,並通過參數用範本生成具體配置
- ns_global_template = task.run(
- task=template_file, template=‘ns_global.template’, path=‘./templates/’
- )
- # 傳入配置, 注意需要”.split(‘\n’)”通過換行把配置轉換為清單
- task.run(netmiko_send_config,config_commands=ns_global_template.result.split(‘\n’), cmd_verify=True)
- # 讀取ns_lb_template範本,通過參數用範本生成具體配置
- ns_lb_template = task.run(
- task=template_file, template=‘ns_lb.template’, path=‘./templates/’
- )
- # 傳入配置, 注意需要”.split(‘\n’)”通過換行把配置轉換為清單
- task.run(netmiko_send_config,config_commands=ns_lb_template.result.split(‘\n’), cmd_verify=True)
- # 保存配置
- task.run(netmiko_send_config, config_commands=‘save ns conf’,cmd_verify=True)
- # 執行配置NS並列印結果
- run_result = ns.run(config_ns)
- print_result(run_result)
最終專案檔案結構

執行效果
執行final_task.py,執行輸出的內容很清楚,如果範本或者config檔寫的有問題很容易排錯。
- config_ns***********************************************************************
- * vpx1 ** changed : True *******************************************************
- vvvv config_ns ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO
- —- template_file ** changed : False —————————————— INFO
- set ns param -timezone GMT+08:00-CST-Asia/Hsinchu
- enable ns feature LB
- enable ns feature RESPONDER
- enable ns feature SSL
- enable ns mode MBF
- —- netmiko_send_config ** changed : True ————————————- INFO
- set ns param -timezone GMT+08:00-CST-Asia/Shanghai
- Warning: The configuration must be saved and the system rebooted for these settings to take effect
- Done
- > enable ns feature LB
- Done
- > enable ns feature RESPONDER
- Done
- > enable ns feature SSL
- Done
- > enable ns mode MBF
- Done
- >
- >
- —- template_file ** changed : False —————————————— INFO
- add lb vserver vs22 http 22.22.22.22 80
- add serviceGroup sg22 http
- bind serviceGroup sg22 172.16.10.10 80
- bind serviceGroup sg22 172.16.10.11 80
- bind serviceGroup sg22 172.16.10.12 80
- bind lb vserver vs22 sg22
- add lb vserver vs33 http 33.33.33.33 80 -lbMethod roundrobin -persistenceType sourceip
- add serviceGroup sg33 http
- bind serviceGroup sg33 172.16.10.15 80
- bind serviceGroup sg33 172.16.10.16 80
- bind serviceGroup sg33 172.16.10.17 80
- bind lb vserver vs33 sg33
- —- netmiko_send_config ** changed : True ————————————- INFO
- add lb vserver vs22 http 22.22.22.22 80
- Done
- > add serviceGroup sg22 http
- Done
- > bind serviceGroup sg22 172.16.10.10 80
- Done
- > bind serviceGroup sg22 172.16.10.11 80
- Done
- > bind serviceGroup sg22 172.16.10.12 80
- Done
- > bind lb vserver vs22 sg22
- Done
- > add lb vserver vs33 http 33.33.33.33 80 -lbMethod roundrobin -persistenceType sourceip
- Done
- > add serviceGroup sg33 http
- Done
- > bind serviceGroup sg33 172.16.10.15 80
- Done
- > bind serviceGroup sg33 172.16.10.16 80
- Done
- > bind serviceGroup sg33 172.16.10.17 80
- Done
- > bind lb vserver vs33 sg33
- Done
- >
- >
- —- netmiko_send_config ** changed : True ————————————- INFO
- save ns conf
- Done
- >
- ^^^^ END config_ns ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
發表迴響