Categories: Cisco DevNet

CML2 を使用してデバイス構成を自動化する方法

この記事は、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つ目の方法で進める場合は、次の点に考慮する必要があります。

  1. ツールはそれぞれ、各デバイスとそれへの接続方法 (アドレス / 認証情報) を一覧表示したインベントリ / テストベッドファイルが必要です。1つ目の方法と同様、管理アドレスと認証情報は開始構成に後から追加できます (ネットワークデバイスのデフォルトの認証情報はシスコ / シスコのはずです)。管理アドレスを追加しない場合、CML に含まれているコンソール / ターミナルサーバ機能を使用できます。これにより、CML に SSH でアクセスすると、ターミナルサーバの場合と同じようにデバイスへの接続を開くことができます。
  2. pyATS にとってのメリットととして、CML2 は、コンソールサーバアプローチと同様に、接続情報を含むどのシミュレーションにもすぐに使える pyATS テストベッドファイルをダウンロードできる API を提供しています (これが GUI になるかどうかは今のところ不明)。これは非常に便利です。

CML2 で pyATS を使用する場合、どのラボに対してもテストベッドファイルを簡単にダウンロードできます。

それでは詳しく見ていきましょう。

私をご存知な人はお分かりでしょうが、私に Cisco Modeling Labs について語らせたら何日も続いてしまうので、このブログでは大学の論文風にならないよう、範囲を限定する必要があります。ですからここでは、皆さんが CML2 に関する基本的知識をお持ちと仮定して、ネットワーク自動化に向けて pyATS を活用することに深く焦点を当てます (何と言えばいいか、私は非常にオタクです)。もちろん、ネットワーク自動化に他のツールを使用したい場合は、ここからサンプルを拡張して、Ansible、Nornir、その他の優れたオプションを利用することもできます。

このブログでは、Cisco Modeling Labs Enterprise DevNet Sandbox を利用します。 このサンドボックスは、Cisco Modeling Labs を自分の用途で試してから購入したいという方に向け、デモアクセスを無料で提供しています。 このツールは 「エンタープライズ」 版ですが、ここで紹介するサンプルやテクニックはすべて 「パーソナル」 版でも実行できます。

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 を使用しています。“inside-host01”に対する構成のスニペットを見れば、ネットワークインターフェイス構成が適用されているのが分かります。

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 を使用した CML ネットワークの構成

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 です。これは CML2 向けの 「公式な」 Python ライブラリで、CML 開発チーム  (Hi Ralph!) によって構築、メンテナンスされています。 pip コマンドを使用してライブラリをインストールしたら、CML の 「Tools > Client Library」 の順に選択すると、ホストされているドキュメントを見つけることができます。virl2-client ライブラリは、Python スクリプトにインポートして、他のライブラリと同様に使用するものです。 ラボに pyATS テストベッドファイルをダウンロードするためのスニペットは次のとおりです。

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(または cmlutils) です。virlutils ライブラリは、VIRL 1.x 用のコマンドラインインターフェイスとして、数年前に誕生したもので、その利用のされ方は、仮想マシン環境での Vagrant に似ています。virlutils は、NetDevOps およびネットワーク自動化分野において VIRL または CML 1.x を使用して作業をしている人々の間で、「非公式ライブラリ」 でありながらも広く利用されるようになりました。Cisco Modeling Labs2 がリリースされたとき、このツールの価値が認識され、開発陣が引き続き CML2 へのサポートを追加してくれたことをうれしく思ったものです。(Thanks Joe!)  virlutils のインストールは pip コマンドで行います。

オリジナルの 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 を使用した CML ネットワークの構成

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 がデバイス固有のレンダリングをしてくれます。

ドキュメンテーションにアクセスすると、pyATS に含まれているモデルと、それぞれがサポートしているプラットフォームを確認できます。

最後に

長いブログになってしまいましたね。 ご紹介した情報に関心を持っていただき、使えるアイデアを思いつくきっかけとしてくださると幸いです。前述のとおり、関連トピックの深掘りに役立つリンクを貼っておきます。

今日のところは以上です。すぐに答えが知りたい緊急の質問がある方は、 Twitter (@hfpreston) に書き込んでいただくか、E メール (hapresto@cisco.com) をお寄せください。

新しくなった Developer video channel をご覧ください。

取り上げてほしいトピックのご提案は、Twitter まで。

 

Kazumasa Ikuta

シスコシステムズ合同会社 APJアーキテクチャー プリンシパルアーキテクト。2001 年入社。エリア担当 SE、通信事業者担当 SE、SDN応用技術室を経て、2021年よりアジア太平洋地域アーキテクチャーセントラルグループ所属、プリンシパルアーキテクト。主に企業向けのネットワーク運用管理全般および製品、SDNやネットワークプログラマビリティ関連、Cisco DevNetを担当。提案、構築、運用維持管理における技術サポート、本社開発部門と連携したアジア地域での製品や技術のロールアウトプラン策定と実行、対外的なプレゼンテーションなど、仕事を選ばず幅広く活動中。書籍:Ciscoネットワーク構築教科書[解説編](共著)Ciscoネットワーク構築教科書[設定編](共著)Cisco WAN 実践ケーススタディ(共著)