【分享】網絡自動化的項目實踐:場景、工具和方案
原創(chuàng)【51CTO.com原創(chuàng)稿件】網絡自動化是針對一組網絡設備批量執(zhí)行一連串的網絡操作。它可以歸納為三個組件:命令 + 操作 + 目標設備,適用于兩個場景。
場景1:針對既有網絡的操作和/或增量配置,提高重復性任務的效率。它又包括兩個方面(以思科設備為例):
- 日常的enable mode操作,例如采集一組設備的設備信息,接口狀態(tài)和描述檢查,設備版本查驗,配置文件一致性驗證等。
- 為現有網絡上平穩(wěn)運行的多個設備提供具備共性的增量配置。例如新增或刪除一個授權登錄的帳號,統(tǒng)一修改AAA認證服務器/日志/Netflow/NTP服務器地址,更新SNMP Community string,統(tǒng)一關閉某個端口等。
場景2:針對新建大規(guī)模數據中心,提供快速部署。主要是基于一個基線配置模板,調用特定于設備的Location/Type/Role/Loopback等信息的變量文件,來動態(tài)創(chuàng)建完整的配置文件。
一、流行的網絡自動化工具和手段
根據我個人的工作經驗和負責的項目,總結了如下幾個解決方案,并列舉了一些細節(jié):
1. Cisco Prime Infrastructure,封閉系統(tǒng),一個運行在虛擬服務器上的OVA文件。
- 內置專有OS,提供專有的Shell界面,不是工業(yè)標準的Linux shell。
- 無法獲知它的Inventory文件(CVS格式)/配置文件/模板/變量在系統(tǒng)中的保存位置。
- 無法獲知它的系統(tǒng)采用什么腳本編寫,也無法修改實現個性化。
- 系統(tǒng)不支持任何版本控制機制,無法將本地的配置文件Push到GitHub。
- 內置封閉的Web daemon提供用戶GUI接口,采用Oracle DB但是用戶沒有DB root帳號和Prime 用戶帳號,即無法編輯修改數據庫文件。
- Cicso PI是一個集網絡監(jiān)測、日志服務、Netflow采集分析、配置備份和網絡自動化為一體的綜合系統(tǒng),但是每一個單項拿出來都不如專門提供特定功能的系統(tǒng)強大,例如配置備份有RANCID,Syslog有Splunk, Netflow有Scrutinizer, 網絡監(jiān)測有Observium/Nagios/Check_MK。
2. RANCID, 在我所在公司的部署中,是通過與Observium集成來實現的:
- 通過RANCID自帶的腳本(generate-rancid.custom.php)讀取Observium inventory文件(和Linux server的/etc/hosts也有關聯)動態(tài)生成router.db,但是設備型號的描述粒度不夠細。
- 版本控制采用CVS或SVN,與Git相比略顯老舊。
- 通過clogin –c “show clock” “show version” ‘ls *aus*’命令來針對hostname中有‘aus’字符的所有網絡設備按順序執(zhí)行一組enable模式操作。
- 通過clogin –x commands.txt ‘ls *sv4*’命令來針對hostname中有‘sv4’字符的所有設備按順序執(zhí)行一組配置命令。
- 腳本執(zhí)行過程中和用戶沒有交互,只能采用rancid自己的帳號登錄設備進行操作,審計功能弱。
- 不如Python腳本調用command-set和device-group兩個Argument方便靈活。
- 沒有異常處理機制(例如針對100臺設備進行批量操作,萬一第30臺設備因故障登錄失敗,腳本將停止)。
3. Ansible,發(fā)展之初更多地面向服務器進行自動化部署
(1) 實現復雜,引入很多新概念,包括如下:
- Role/Playbook
- Jinja2 template
- Yaml grammar
- Host Inventory
- Engine/Modules/Plugins
(2) 一次Ansible操作的流程,可以顯示出完整的Ansible架構,如下圖:
(3) 看似一條簡單的命令“Ansible-playbook templates.yaml”實際上需要四個input (tasks, hosts, jinja-template, vars),每個input都是特定于設備的,即每臺設備都有專門針對自己的四個參數,如果設備的數量不夠大,很可能維護變量/模板/Inventory等文件的精力要抵消自動化提高的效率。說通俗一點就是,我采用Ansible節(jié)省了30分鐘時間,但是我事先需要花2個小時準備相關的、需要被Ansible在執(zhí)行過程中調用的基礎數據。
(4) 理論上更適合新建大規(guī)模數據中心的應用場景,網絡拓撲對稱且層次化,有規(guī)律可循。按照固定的Pattern來搭建,容易制定一個具有普適性的基線模板,只需為數不多的變量就可以生成不同site、type和role的設備配置文件。
(5) 由于我現在任職的公司主要是總部和分支機構之間的Corporation網絡,每個Remote site的組網原理類似Campus network,以其中一個分公司的LAN-Switch為例,共有57個個性化元素需要提取出來作為變量,工作量很大。其中的VLAN ID變量雖然只有6個,但是在288個接口上隨機分布,Jinca2模板必須為每個Interface預留VLAN ID變量的輸入;更復雜的是Interface description, 作為LAN-Switch我們需要對連接
WLC/VMW/NetApp/WAP/Zoom/Camera/Monitor系統(tǒng)的Port進行特別描述,但是46個接口描述變量在交換機的288個接口上也是隨機的,和其他分公司的LAN-Switch之間沒有共性,導致Ansible的變量文件幾近不可維護,花在維護變量和模版上的精力,遠遠大于自動化提高的效率。
4. 還有幾個技術方案我沒有深入研究,在NANOG會議資料中看到行業(yè)專家進行過權威陳述,摘要如下:
- Python with NAPALM (Python module): 思科目前只支持IOS-XR,不適合企業(yè)網絡。
- NETCONF/YANG: 12年前的IETF標準(RFC4741),截至目前只有JUNOS支持比較好。
- XML via CLI: Schema:尚未標準化。
- RESTful API: 工業(yè)標準還在制定中。
- OpenFlow: 目前最新版本1.6,只有一個技術規(guī)范不足以支撐SDN生態(tài)(IETF有8000+ RFC)。
二、網絡和網絡之間的差異
上面論述了目前業(yè)界比較流行的幾種解決方案。首先我們要有這樣的共識:到目前為止網絡自動化尚沒有完美的解決方案。不同的業(yè)務模式和公司規(guī)模導致它的組網模式和組網技術差異很大。
另外,同樣是網絡,ISP網絡(以中國電信的ChinaNet為例)主要是覆蓋全國甚至全球的Backbone(由所有POP和傳送網組成),以及提供接入線路可延伸到千家萬戶的城域網組成;云計算提供商(以AWS為例)則主要是在世界各地建立自營的大型互聯網數據中心,利用租用ISP的波分或裸光纖實現所有IDC互聯;企業(yè)網絡則主要是由規(guī)模相對較小的Production backbone/IDC和用于公司總部、分部之間互聯的Corporation網絡構成。
現階段可行的方案
這三類網絡擁有者對網絡自動化的需求是不一樣的。沒有任何一種網絡自動化方案可以適應、解決所有網絡架構。我這里提出的可行方案,是基于我公司的網絡具體現實而推薦的。
我公司的網絡屬于企業(yè)網絡,有如下幾個特點:
- 網絡結構穩(wěn)定,變化不頻繁,平均每年新增一個分支機構。
- 每次網絡的調整內容不復雜,Monitor由Solarwinds改為Observium后需要修改SNMP Community string, Netflow服務器由NFSEN改為Scrutinizer后需要修改Collector服務器地址。
- 面向公眾的大型數據中心已經遷移到AWS,公司只維護一個用于企業(yè)內部服務(人事、法律、財務數據,和源代碼、郵件、AD/LDAP/RSA等)的小型Internal DC,網絡規(guī)模24個Rack, 不到40臺交換機。
- 網絡由多個廠家設備組成,包括Cisco, Juniper, F5, CheckPoint等。
基于上面的分析,我們平時的網絡運營維護最大的特點是依次登錄多臺設備進行重復性的操作,或者是在現有網絡平穩(wěn)運行的基礎上對部分功能進行增量配置。我們認為采用Python結合Netmiko模塊是切實可行的,滿足現階段我們的需求。
三、Python和Netmiko介紹
這個方案是我公司的Best current practice。
Python是業(yè)界很流行的腳本語言,可讀性強,模塊和函數豐富,在網絡自動化方面有很多活躍社區(qū)作出貢獻。
Netmiko是一個開源Python模塊,由Kirk Byers(https://pynet.twb-tech.com/) 維護,所有源代碼和腳本、JSON文件、技術文檔和應用范例都在GitHub上供借鑒和下載(https://github.com/ktbyers/netmiko) 。
Netmiko簡化了針對網絡設備的SSH管理功能,例如:
1. 支持不同廠家設備和同廠家不同平臺設備,成功建立SSH連接。
- 基于Cisco和Juniper CLI的差異性,自動隱性輸入enable, conft。
- 針對Cisco WLC,自動屏蔽login字符錄入。
2. 針對多廠家環(huán)境可順利執(zhí)行Enable模式的所有操作并將設備的交互信息反饋到執(zhí)行腳本的機器。
3. 針對多廠家環(huán)境可順利執(zhí)行Configure模式的所有操作并將設備的交互信息反饋到執(zhí)行腳本的機器。
基于上述特點,和我公司的具體需求,我們重點實現了場景1的網絡自動化,可以將自動化的實現高度提煉為如下的結構:
- Python script + command-set + device-group
編制兩個Python腳本,名字為enable.py和configure.py,分別代表執(zhí)行enable或configure模式下的腳本文件。每個腳本都可以調用兩個參數,一個是命令集(command-set)要執(zhí)行的一組操作指令,另一個是設備組(device-group)即腳本要執(zhí)行的對象。我們還優(yōu)化了腳本,提供交互式的運行環(huán)境,用戶只需要鍵入腳本名稱,Python和Linux shell交互,自動詢問用戶需要執(zhí)行哪組命令,用戶進行選擇后腳本自動詢問需要執(zhí)行的目標設備,用戶再次進行選擇后Python按腳本順序執(zhí)行,并將結果輸出到Linux服務器。
為了配合兩個不同腳本的執(zhí)行,我們還制定了一些文件名稱約定,命令集本質上是txt文件,為了區(qū)分是enable還是configure模式,采用后綴名.enab和.conf來分別代表;Device-group必須采用Python字典數據結構,是JSON格式,可直接采用.json來代表。文件命名約定主要利于在Linux shell下與用戶交互時提供正確的輸出供用戶選擇。
腳本的執(zhí)行環(huán)境是一臺Linux 服務器,安裝PIP和Netmiko, 腳本中調用json, netmiko, sys, signal, os等模塊/函數,實現需要的功能。此外import getpass實現通過用戶的AD帳號進行認證來登錄目標設備,并在Python輸出中隱藏用戶密碼。腳本中利用for loop來實現對命令集的逐行執(zhí)行和設備集的逐個登錄。
以下是enable.py的源代碼:
- #!/usr/bin/env python
- from __future__ import absolute_import, division, print_function
- from getpass import getpass
- import json
- import netmiko
- #from netmiko import ConnectHandler
- #from netmiko.cisco import CiscoIosBase (device type: "cisco_ios", "cisco_xe")
- #from netmiko.cisco import CiscoIosBase (device type: "cisco_xe")
- import sys
- import signal
- import os
- signal.signal(signal.SIGPIPE, signal.SIG_DFL) # IOError: Broken pipe
- signal.signal(signal.SIGINT, signal.SIG_DFL) # KeyboardInterrupt: Ctrl-C
- def get_input(prompt=''):
- try:
- line = raw_input(prompt)
- except NameError:
- line = input(prompt)
- return line
- def get_credentials():
- """Prompt for and return a username and password."""
- username = get_input('Username(Please input your adm credentials): ')
- password = getpass()
- return username, password
- netmiko_exceptions = (netmiko.ssh_exception.NetMikoTimeoutException,
- netmiko.ssh_exception.NetMikoAuthenticationException)
- username, password = get_credentials()
- os.system('find *.enab')
- os.system('echo')
- os.system('echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"')
- commandfile = raw_input("Please select what command you want to run: \n")
- os.system('find *.json')
- os.system('echo')
- os.system('echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"')
- devicegroup = raw_input("Please select what device-group you want to apply to: \n")
- with open(commandfile) as cmd_file:
- commands = cmd_file.readlines()
- with open(devicegroup) as dev_file:
- devices = json.load(dev_file)
- for device in devices:
- device['username'] = username
- device['password'] = password
- try:
- print('~' * 80)
- print('Connecting to device:', device['ip'])
- connection = netmiko.ConnectHandler(**device)
- for command in commands:
- print(connection.send_command(command))
- """To keep 2 lines space between 2 devices"""
- print()
- print()
- connection.disconnect()
- except netmiko_exceptions as e:
- print('Failed to ', device['ip'], e)
Python腳本一旦制定就不用頻繁更新,唯一需要維護的是command-set和device-group信息,因為每次的任務是不同的,包括需要批量執(zhí)行的操作指令不同,每次需要對哪些設備進行操作也是特定于任務的。這就要求腳本的具體執(zhí)行者需要對自己的操作編寫單獨的命令集和設備組文件。
例如我們要通過enable.py調用一組命令對lab中的所有設備依次執(zhí)行,device-group的文件如下(Python字典文件,Json格式):
- [
- {
- "ip": "lab-wan-isr4431-1",
- "device_type": "cisco_xe"
- },
- {
- "ip": "lab-wan-isr4431-2",
- "device_type": "cisco_xe"
- },
- {
- "ip": "lab-wan-c3650-1",
- "device_type": "cisco_xe"
- },
- {
- "ip": "lab-wan-c3650-2",
- "device_type": "cisco_xe"
- },
- {
- "ip": "lab-lan-c3850ss-1",
- "device_type": "cisco_xe"
- }
- ]
假定要對上面的每臺設備依次執(zhí)行show clock命令,.enab的內容如下(txt格式):
- show clock
執(zhí)行結果將在執(zhí)行此腳本的Linux服務器上,以STD1 方式輸出如下:
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Connecting to device: lab-wan-isr4431-1
- 03:42:24.324 UTC Sat Apr 28 2018
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Connecting to device: lab-wan-isr4431-2
- 03:42:29.472 UTC Sat Apr 28 2018
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Connecting to device: lab-wan-c3650-1
- *03:40:15.780 UTC Sat Apr 28 2018
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Connecting to device: lab-wan-c3650-2
- *03:42:05.544 UTC Sat Apr 28 2018
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Connecting to device: lab-lan-c3850ss-1
- *03:42:45.277 UTC Sat Apr 28 2018
這里的例子中,command-set只有一條show clock命令,實際上可以由多條CLI命令進行任意組合,非常靈活。我在項目中已經預先定義了一些命令集和設備組,連同Python腳本一并Push到GitHub Repository。同時在自己的Laptop上安裝了Pycharm IDE工具和GNS3網絡設備仿真環(huán)境,以及GitHub Desktop客戶端。利用這些工具,用戶可以在本地編輯腳本和配套文件,在虛擬網絡環(huán)境中驗證,并實現所有文檔的版本管理。
對于設備組的編寫我們最初希望能通過API或腳本的方式從現有網管系統(tǒng)自動Retrieve, 經過研究個人覺得暫時還不可行。我公司現有RANCID/PI/Observium/IPAM等幾套系統(tǒng),首先是device-group的數據格式不一致,RANCID是TXT,PI是CVS, Observium是JSON,IPAM是專有格式。除了數據格式不同外,對Netmiko而言,最關鍵的信息是Device-type,這也是Netmiko支持跨平臺多廠家的最大優(yōu)勢所在,都是通過對設備類型的明確指定來指導SSH登錄設備后的操作細節(jié)。
前述的幾個系統(tǒng)要么沒有指定設備類型(例如PI默認就只是Cisco, IPAM對設備類型根本不關注,Observium系統(tǒng)不對設備進行控制無需SSH登錄因此也沒有設備類型信息),要么設備類型信息粒度粗(RANCID對思科設備只有Cisco一類,但實際上思科設備可細分為IOS-XE, NX-OS, IOS-XR和IOS)?;诖?,我們目前放棄了自動創(chuàng)建Device-group字典文件的想法。退一步講,即使我們通過腳本來自動創(chuàng)建一個json格式的device-group,我們仍然需要手工指定哪些設備歸屬到哪個組里面,人工參與程度并未降低,提高的效率有限。
四、其他需要考慮的問題
綜上所述,就是我們公司現在已經實現的網絡自動化。由于網絡新增站點不頻繁,一年新增一處,對這種新增網絡的部署,也暫時決定不采用Ansible/Jinca2/Task/Variable來實現,主要是不值得,我們有更簡單快捷的方式:拿一個現有站點的配置文件作為模板,對個性化的元素例如主機名、環(huán)回地址、SNMP location, BGP peer, OSPF area, Interface IP等進行修改,灌入設備,運抵現場,上電開通即可,不需要簡單問題復雜化。
另外要認識到,網絡自動化第一宗旨是提高效率,對全網只有有限數量的VPN網關,只設置在數據中心的LB,每個Site安全策略不具備共性的FW,沒有必要實行網絡自動化。
最后一點,我本人對網絡自動化還有些顧慮,就是潛在的風險。畢竟一個腳本是對一組設備執(zhí)行一系列操作,萬一命令集配置有誤,有可能導致全網癱瘓。目前還沒有很完善的回退機制,一旦發(fā)生將是災難性的結果。這也是為什么我在筆記本上安裝GNS3的原因,每次需要進行驗證,確保無誤后才能執(zhí)行。配套的管理流程也需要跟上,在Change工單上需要提交命令集和設備組的詳細信息,以備萬一需要回退,確定知道在哪些設備上回退哪些操作。
以上是結合我本人的工作實踐和項目研究總結的心得,網絡自動化是網絡行業(yè)的趨勢,網絡工程師無論喜歡與否,在大趨勢面前也只能順勢而為,否則就有被淘汰的危險。技術方案還在不斷進步,未來會有新的發(fā)展,即使是現有的手段,不同的公司也會有不同的推薦和實現,希望我的文章能起到拋磚引玉的作用,我也非常希望和同行業(yè)的專家交流,對文章中內容有不同觀點歡迎提出指正,相互學習,共同提高。
胡捷,在國內曾經任職中國網通(CNC)、Verizon、Juniper 和中國電信。參與過中國電信 CN2 項目技術方案編寫和城域網優(yōu)化改造項目,以及中國電信 IPv6 研究和現網試驗。2014 年 6 月至今在舊金山一家互聯網公司從事網絡工程師職業(yè)。
【51CTO原創(chuàng)稿件,合作站點轉載請注明原文作者和出處為51CTO.com】