この記事は、DevNet の Network Programmability Evangelist である Hank Preston によるブログ「How can I automate device configurations using CML2? 」(2021/2/26)の抄訳です。
ネットワークオートメーションエンジニアの皆さん、こんにちは。数週間ぶりの投稿です。今回は Evan Fareed さんから良い質問が届いています。
私は、CML2 を使用してデバイスの初期設定をするにあたって、基本的なデバイス設定とインターフェイスの構成を自動化したいと思っています。お勧めの戦略や参考になるリソースはありますか?Postman、Ansible、Python スクリプト、pyATS、Hashicorp ツールのどれを使えばよいか分かりません。
Evan さんがぶつかった課題は、私たちの多くが直面していることではないでしょうか。私もそうです。Cisco Modeling Labs
E メールで Evan さんから質問をもらった私はすぐに、いくつかのアイデアと検討すべき助言を記した回答を返信しました。しかしながら、「何が」 できるかについての説明だけでなく、「どうすれば」 タスクを完遂できるかについて、詳細な記事にしたいと思いましたので、この投稿の後半では、この助言を具体化する技術的なあれこれを深掘りします。しかしまずは、質問に対するざっくりとした回答をご紹介します。
CML ネットワークトポロジーに関して基本構成を提供するために取り得る戦略または選択肢は2つ存在します。
1つ目の選択肢は、ラボ / シミュレーション定義の一部として、初期構成を含めることです。CML トポロジ内の各ノードには、基本 / 開始構成があります。CML には、各ノードタイプに対して最小限の基礎構成が初期設定されていますが、この初期設定は自由にカスタマイズ可能です。シミュレーションを一から開始する、またはノードをワイプしてリスタートするごとに、デバイスはその構成で起動します。
デバイスの初期構成は、Cisco Modeling Labs Simulation で提供できます。
2つ目の選択肢は、ごく最小限の構成 (または構成なし) でシミュレーションを開始し、自動ツールを使用して、その構成を保存または送信します。どのツール (Ansible、pyATS、Python など) を使用するかは、どのツールが好みか、または学びたいかで自由に選択してください。あなたが挙げたツールはそれぞれ、スキル向上に役立ちますので、どれを選んでも間違いはないでしょう。2つ目の方法の良いところは、単一の 「物理ネットワークトポロジ」 をもって、個々のラボセッションの要件に応じて、デバイスにさまざまな構成をデプロイできる点です。
2つ目の方法で進める場合は、次の点に考慮する必要があります。
CML2 で pyATS を使用する場合、どのラボに対してもテストベッドファイルを簡単にダウンロードできます。
私をご存知な人はお分かりでしょうが、私に Cisco Modeling Labs について語らせたら何日も続いてしまうので、このブログでは大学の論文風にならないよう、範囲を限定する必要があります。ですからここでは、皆さんが CML2 に関する基本的知識をお持ちと仮定して、ネットワーク自動化に向けて pyATS を活用することに深く焦点を当てます (何と言えばいいか、私は非常にオタクです)。もちろん、ネットワーク自動化に他のツールを使用したい場合は、ここからサンプルを拡張して、Ansible、Nornir、その他の優れたオプションを利用することもできます。
このブログでは、Cisco Modeling Labs Enterprise DevNet Sandbox
CML のライセンスや価格の詳細を知りたい方は、DevNet のページ (日本語版 CML ページ)をご覧ください。
このオプションは一番使いやすいですが、いくらか柔軟性に欠けるところがあります。
DevNet Sandbox を予約すると、ラボトポロジがすでに作成されていて、使用可能な状態であることが分かります。 このラボは 「マルチプラットフォーム ネットワーク」 と呼ばれるもので、いくつかのサンドボックスで使用されている一般的なトポロジです。これには、Nexus スイッチ、IOS XE ルータ、いくつかの Linux ホストで構成される基本的なネットワークが含まれています。 このトポロジを作成したのは私なのですが、今回ラボを構築するにあたってはこのオプションを使用しました。ノードの1つを選択して 「Edit Config」 タブをクリックすると、ノードに対して使用された基本構成が表示されます。
この Nexus 9000v スイッチの初期構成は、ラボ定義に含まれています。
上の図を見ると、この Nexus 9000v スイッチ (トポロジ内の 「dist-sw01」) に適用されている初期構成が分かります。 これは構成のほんの手始めですが、下にスクロールしていくと、VLAN、各種機能、インターフェイスなどに対する構成が分かります。
構成の上部にあるたくさんの 「echo」 コマンドについて不思議に思う方もいるかもしれません。 NX-OS デバイスの起動時の初期構成プロセスにおいて興味深い点は、スイッチに対してブートイメージを設定するコマンドが、スイッチ初期化プロセスによって 「無視される」 点です。 おそらく、スイッチでどのバージョンの NX-OX を実行していてもスタートアップ構成が機能するようにするためだと思われます。問題は、シミュレーションの Nexus 9000v がブートコマンドが構成されていない状態でクラッシュすると、恐ろしい 「loader >」 プロンプトが表示されてスタックすることです。 vCPU または vRAM のリソース共有が起こっている時、シミュレーション中の仮想ネットワークデバイスがクラッシュすることは珍しいことではありません。 私たちはこの問題を解決するため、EEM や Python スクリプトを活用して、スイッチの起動後にブートコマンドを構成するユニークな自動化ソリューションを作成しました。これは非常にうまく機能したため、CML 開発チームはこれを CML 自体に実装する気になってくれました。すばらしいですね!
「Update configuration from device (デバイスから構成を更新)」 というボタンに注目してください。 このノードの実行中に構成を変更した場合で、それらの変更を後で利用できるよう、トポロジに保存したい場合は、このボタンをクリックすることで、ラボ定義の構成と、デバイスで今実行中の構成とを置き換えることができます。
トポロジ内の各デバイスは、Linux ホストを含め、初期構成があります。 CML は、Linux ホストの基本構成の設定用として、業界標準の VM 初期化プロセス cloud-init
write_files:
- path: /etc/rc.local
owner: root:root
permissions: '0755'
content: |-
#!/bin/sh
ifconfig enp0s9 up 10.10.20.179 netmask 255.255.255.0
route add -net 0.0.0.0/0 gw 10.10.20.254 dev enp0s9
ifconfig enp0s2 up 172.16.101.11 netmask 255.255.255.0
route add -net 172.16.0.0/16 gw 172.16.101.1 dev enp0s2
route add -net 172.31.0.0/16 gw 172.16.101.1 dev enp0s2
exit 0
CML web GUI を通じてトポロジに取り組むのは簡単で楽しいものですが、ラボ定義をダウンロードしたり保存したりすることも、それはそれでメリットがあります。そのトポロジを友人とシェアすることも、異なる CML インターフェイスで同じトポロジを立ち上げることもできます。 また、“Lab as Code” アプローチを用いて、ラボを定義したりカスタマイズしたりすることも可能です。CML2 のラボ定義は、YAML で行います。これはネットワークオートメーションエンジニアやツールで広く利用されているデータ形式です。YAML ファイル内では、各デバイスの基本構成を簡単に見つけ、簡単に更新できます。ただし、YAML の形式は厳密に維持するよう注意してください。ホワイトスペースの管理が難しいかもしれません。
lab:
description: A sample network built with IOS XE, NX-OS, IOS XR, and ASA devices. Includes
Linux hosts.
notes: ''
timestamp: 1603303517.385979
title: Multi Platform Network
version: 0.0.3
nodes:
- id: n5
label: dist-rtr01
node_definition: csr1000v
x: -700
y: 100
configuration: |-
service timestamps debug datetime msec
service timestamps log datetime msec
! Call-home is enabled by Smart-Licensing.
service call-home
platform qfp utilization monitor load 80
no platform punt-keepalive disable-kernel-core
platform console serial
!
hostname dist-rtr01
pyATS は、私にとってお気に入りのネットワーク自動化用ツールの一つですが、愛用しているのは私だけではありません。たとえば Cisco Modeling Labs 2は、ネットワークシミュレーションの構築や管理のための一部のタスクで、pyATS を利用しています。pyATS を使用して何かをするには、管理されるネットワークを定義するテストベッドファイルが必要です。CML は、あなたが実行するあらゆるラボに対して、API を通じてこのテストベッドファイルを提供します。
将来のリリースでは、CML GUI から pyATS テストベッドをダウンロードできるようになることが期待されます。それまでは、「We ♥ API」 ですね。
CML 用 REST API ドキュメントは、Swagger/OpenAPI 仕様にて CML サーバ自体でホストされているので、開発者にとって非常に便利です。 これらを読むと、pyATS テストベッドに対する API リクエストは下記のとおりであることが分かります。
GET /labs/{lab_id}/pyats_testbed
lab_id (短い16進数の識別番号) が必要で、あとは GET リクエストを送信するだけです。もちろん、その前にまず認証を受け、認証ヘッダに含めるトークンを取得する必要があります。CML2 API は非常に便利で使いやすいものですが、私は通常、CML2 とプログラム的にやり取りする際にはこの方法を用いていません。 代わりに、2つの Python ライブラリの1つを使用しています。
1つ目は virl2-client
from virl2_client import ClientLibrary
# Create a client object for interacting with CML
client = ClientLibrary("https://10.10.20.161", "developer", "C1sco12345", ssl_verify=False)
# Find your lab. Method returns a list, this assumes the first lab returned is what you want
lab = client.find_labs_by_title("Multi Platform Network")[0]
# Retrieve the testbed for the lab
pyats_testbed = lab.get_pyats_testbed()
# Write the YAML testbed out to a file
with open("lab_testbed.yaml", "w") as f:
f.write(pyats_testbed)
2つ目のライブラリは virlutils
オリジナルの virlutils ライブラリの多くは、最高のネットワークオートメーションエンジニアの一人、Kevin Corbin 氏によって書かれ、保守されていました。彼とは光栄にも一緒に仕事をさせていただいたこともあります。私は、新しく興味深い課題に取り組むときはいつも彼のことを懐かしく思い出します。懐かしい Kevin、あなたはあまりに早く世を去ってしまいました。
virl2_client と異なり、virlutils はコマンドラインから使用することが想定されているため、Python コーディングは必要ありません。 このことは、ラボ用に pyATS テストベッドを取得する場合などに非常に便利です。 スニペットは次のようなものになります。
# First, you need to create the .virlrc file for your CML server
cat .virlrc
VIRL_HOST=10.10.20.161
VIRL_USERNAME=developer
VIRL_PASSWORD=C1sco12345
CML_VERIFY_CERT=False
# "Use" the desired lab
cml use "Multi Platform Network"
# Generate a testbed file for the lab
cml generate pyats --output testbed.yaml
Writing testbed.yaml
テストベッドファイルの生成にどのアプローチを用いようと、pyATS に飛びつく前にやるべきことがいくつかあります。それは統合された CML2 ターミナルサーバとネットワークデバイス自体に対する認証情報に関連します。 次に示すのは、生成されたテストベッドファイルの冒頭部分です。
testbed:
name: Multi Platform Network
tacacs:
login_prompt: 'login:'
password_prompt: 'Password:'
username: '%ENV{PYATS_USERNAME}'
passwords:
tacacs: '%ENV{PYATS_PASSWORD}'
enable: '%ENV{PYATS_AUTH_PASS}'
line: '%ENV{PYATS_PASSWORD}'
devices:
terminal_server:
os: linux
type: linux
connections:
cli:
protocol: ssh
ip: 10.10.20.161
username: change_me
password: change_me
tacacs やパスワードには“‘%ENV {PYATS_USERNAME}’”といった値を使用する点に注目してください。 デフォルトでは、テストベッドはデバイスの認証情報を環境変数として求めるよう設定されています。 おかげで、これらの認証情報の管理とセキュリティ保護に関して、任意の数のオプションを使用できます。 これは単純なシミュレーションですから、私のシミュレーションの認証情報ということで、“cisco”に置き換えましょう。
次に、“terminal_server”デバイス以下を見ると、CML サーバに対する認証情報として“change_me”と記載されています。 これらの認証情報は、環境変数を作成しても良いですし、単に CML に使用されているアカウントに変更しても結構です。ここでは、DevNet サンドボックスということで、“developer / C1sco12345”に置き換えます。
テストベッドファイルを離れる前に、デバイスをどのように接続するか確認しましょう。 こちらはトポロジからの、あるデバイスの定義です。
dist-rtr01:
os: iosxe
type: router
series: csr1000v
tacacs:
username: cisco
passwords:
tacacs: cisco
connections:
defaults:
class: unicon.Unicon
a:
protocol: telnet
proxy: terminal_server
command: open /ec3f5f/n5/0
connections 以下を見ると、テストベッドはプロキシとして 「ターミナルサーバ」(つまり CML サーバ自体) を使用して接続するよう設定されており、次にコマンド“open /ec3f5f/n5/0”が設定されているのが分かります。 これが機能するかをテストするには、CML サーバに telnet 接続して、このコマンドを実行します。CML サーバの“help”オプションや“tab”オプションを利用すれば、ターミナルサーバの機能が使いやすくなります。 こうしたデバイスへの接続方法は、CML トポロジから 「リアルワールド」 への外部 IP 接続を必要としないので、便利です。
テストベッドが完成したら、さっそく試してみましょう。
まず、テストベッドファイルのフォーマットが正しいか検証します。
pyats validate testbed testbed.yaml
この検証はエラーなしで終える必要がありますが、警告がいくつか表示されることもよくあります。こうした警告は、ネットワーク自動化ツールの世界が進化し続けていることに起因します。pyATS は CML または CML サンドボックスよりはるかに頻繁に更新されているため、生成されたテストベッドファイルが機能するにも拘らず、pyATS からの 「最新のテストベッドスキーマ」 を使用していないためにエラーが出る可能性があります。こうした警告は、CML アップデートがリリースされて、サンドボックスに適用したら、数が減るか、もしくは完全になくなるはずです。
/Users/hapresto/virtualenvs/std/bin/pyats:8: DeprecationWarning: 'tacacs.username' is deprecated in the testbed YAML. This key has been moved to 'credentials'.
sys.exit(main())
/Users/hapresto/virtualenvs/std/bin/pyats:8: DeprecationWarning: 'passwords.tacacs' is deprecated in the testbed YAML. Use 'credentials' instead.
sys.exit(main())
.
.
Warning Messages
----------------
- Device 'dist-rtr01' missing 'platform' definition
- Device 'dist-rtr02' missing 'platform' definition
- Device 'dist-sw01' missing 'platform' definition
- Device 'dist-sw02' missing 'platform' definition
- Device 'inside-host01' missing 'platform' definition
- Device 'inside-host02' missing 'platform' definition
- Device 'terminal_server' missing 'platform' definition
- Device 'terminal_server' has no interface definitions
テストベッドの検証を終えたら、実際にデバイスに接続して、詳細をいくつか取得してみましょう。このテストでは、引き続き pyats CLI を使用して、スイッチの1つに構成されている VLAN を見ていきます。
pyats parse --testbed-file testbed.yaml "show vlan" --device dist-sw01
想定される出力の一部を示すと次のようになります。
{
"vlans": {
"101": {
"interfaces": [
"Port-channel1",
"Ethernet1/1",
"Ethernet1/2",
"Ethernet1/11"
],
"mode": "ce",
"name": "prod",
"shutdown": false,
"state": "active",
"type": "enet",
"vlan_id": "101"
},
"102": {
"interfaces": [
"Port-channel1",
"Ethernet1/1",
"Ethernet1/2"
],
"mode": "ce",
"name": "dev",
"shutdown": false,
"state": "active",
"type": "enet",
"vlan_id": "102"
}
pyATS テストベッドの準備方法が分かったところで、ここからはそれを使用してシミュレーション内のネットワークデバイスの構成を更新する方法を見ていきましょう。このブログはすでに長くなりすぎているので (ついてきてくださって感謝です)、pyATS を使用したネットワーク構成についてはあまり追求しないことにします。 その件については、このブログの最後にお勧めの資料をリンクしておきますので参考にしてください。
pyATS ライブラリはネットワーク自動化のための堅牢なソリューションであり、開発者に数多くの選択肢を提供します。ネットワークの自動化に多くの人が用いているのは、Python を通じて CLI コマンドを送信するという方法です。pyATS はそれを非常に容易にしてくれます。CLI コマンドを使用してループバックインターフェイスを作成する方法の例を次に示します。
# import the base Genie object
from genie.conf import Genie
# Initialize a pyATS testbed object
testbed = Genie.init("testbed.yaml")
# Create a variable for our router and connect to it
dist_rtr01 = testbed.devices["dist-rtr01"]
dist_rtr01.connect(learn_hostname=True,log_stdout=False)
# Send configuration to router
dist_rtr01.configure('''
interface loopback 11
description Created with pyATS and CLI
ip address 10.255.255.1 255.255.255.255
''')
# Disconnect from the router
dist_rtr01.disconnect()
しかし、ネットワークの自動化は、単なる CLI を利用した別の作業方法を超えた何かを目指す必要があります。pyATS は、より Python らしい方法でネットワークをプログラムすることを可能にする、強力なオブジェクトのライブラリを含んでいます。次に示すのは、「インターフェイス」 オブジェクトを使用した類似の例です。
# import the base Genie object
from genie.conf import Genie
# import the Interface configuraiton object
from genie.conf.base import Interface
# Initialize a pyATS testbed object
testbed = Genie.init("testbed.yaml")
# Create a variable for our router and connect to it
dist_rtr01 = testbed.devices["dist-rtr01"]
dist_rtr01.connect(learn_hostname=True,log_stdout=False)
# Create an Interface object and configure the settings
new_loopback = Interface(device = dist_rtr01, name = "Loopback12")
new_loopback.ipv4 = "10.255.255.2"
new_loopback.ipv4.netmask = "255.255.255.255"
new_loopback.description = "Created with pyATS and Objects"
# Build the device specific configuration and apply to router
new_loopback.build_config()
# Disconnect from the router
dist_rtr01.disconnect()
オブジェクトを使用した構成の良い点は、モデルをサポートしているデバイスが、NX-OS であろうと、IOS、IOS-XR、またはその他のデバイスであろうと関係がないところです。構成のためのコードは同じで、“build_config ()”を実行すれば、pyATS がデバイス固有のレンダリングをしてくれます。
ドキュメンテーション
長いブログになってしまいましたね。 ご紹介した情報に関心を持っていただき、使えるアイデアを思いつくきっかけとしてくださると幸いです。前述のとおり、関連トピックの深掘りに役立つリンクを貼っておきます。
今日のところは以上です。すぐに答えが知りたい緊急の質問がある方は、 Twitter (@hfpreston) に書き込んでいただくか、E メール (hapresto@cisco.com) をお寄せください。
新しくなった Developer video channel
をご覧ください。 取り上げてほしいトピックのご提案は、Twitter
まで。