CML2を触ってみた

動機

仕事でAWSやAzureをいじることがあるが、network周りわかってないなー、と思い、network本読んでも頭に入らない、ということでこういう時は手を動かすに限る。調べてみると実機の他にエミュレータがあるようだ。オープンソースのgns3とciscoのcml2があるが、gns3はiOSを別途入れる必要があるのと、自動化を見据えてやっていきたいので、cml2に着手した。CML2とはCisco Modeling Labs2のことでルータとかスイッチとかそういう機器をエミュレートしてくれるツール。

cml2のインストール

  • 私の環境ではinstallのあと、NATにする必要があった。(そうしないとcml2にprivate ip addressが割り当てられない)
  • メモリ16GBだと、大きいノード(IOS XRv 9000, CAT9000vなど)を動かせられないので、できるだけ大きなメモリを用意しよう。
  • cml2はおそらくintelしかサポートされていない。最近のMacはM1, M2..でARMで、自分のPCもそうなので、windows機に入れることに。vmwareに入れるがこの時にvt-xを有効にする(=Hyper-VやWSLを無効にする)必要がある。
    • cml2は2024/5時点で199ドル=3万円弱/年。円安がひびいてる
    • 2024/5時点ではvmware workstation proは個人利用に限り無償で利用可能である
    • メインはmac機なので、windowsのWSLが無効になっても支障はないが、問題は自動化を行う時にansibleやpyatsといったツールがwindows非対応ということだ。なので、自動化ということを考えた時はcml2をlinux OSに入れるか、windows機をサーバーと見立てるか(別機(Mac機))で操作するのどちらかになる。

ngrok

そこで、ngrokを使う。ngrokはwindowsにも対応しているので問題ない。ngrok config checkでconfigファイルのパスを知ることができる。以下のように修正する: 192.168.80.132はcml2を起動した時に得られるprivate ip address。sshは各種端末に入るのに必要。192.168.80.132:9090はsysadmin用の設定webappだが、これはどちらでも良い。

version: "2"
authtoken: ***

tunnels:
  ui:
    addr: https://192.168.80.132
    proto: http
  ctrl:
    addr: https://192.168.80.132:9090
    proto: http
  ssh:
    addr: 192.168.80.132:22
    proto: tcp

ngrok start --allで割り当てられるので、別機で入ることができる。結果は大体こんな感じ:

Web Interface                 http://127.0.0.1:4040
## port(12479)は都度変わる
Forwarding                    tcp://0.tcp.jp.ngrok.io:12479 -> 192.168.80.132:22

Forwarding                    https://*******.ngrok-free.app -> https://192.168.80.132:443
Forwarding                    https://*******.ngrok-free.app -> https://192.168.80.132:9090

これで別機であるMac機で操作できる準備は整った。

pythonなど環境整える

Mac機に"virl2_client[pyats]"と"pyats[full]"を入れる。

機器(ノード)のデプロイ

これはvirl2_clientを使った。(CML2 APIsのラッパー?) https://developer.cisco.com/docs/virl2-client/ のexamplesを見れば使い方がなんとなくわかるはずだ。start, stop, destroyの関数もある。個人的に使うだけならssl_verifyのオプションをfalseにすればよい。

client = ClientLibrary("https://*******.ngrok-free.app", "username", "password", ssl_verify=False)

機器へのログイン

あとは配置した機器へのログインだが、bashでもできる:

ssh admin@0.tcp.jp.ngrok.io -p 12479
# user, password入力
open /{lab_name}/{node_name}/0

ただ、pytasで自動化できる。

自動化

1: virl2_clientでノード作成自動化。起動もライブラリの関数でできる。起動はやや待つ。割とメモリを食うので、できるだけ軽いノードを使う(例: ubuntuよりserver(tinycorelinux)など)

2: virl2_clientのget_pyats_testbed関数でtestbedという構成管理configをexportできる。ファイルとして以下のように出力する:

pyats_testbed = lab.get_pyats_testbed(hostname="https://*******.ngrok-free.app:12479")

data = yaml.safe_load(pyats_testbed)
# user名、passwordを変更
data['devices']['terminal_server']['credentials']['default'] = {
  "username": cml.CML_USER, 'password': cml.PASSWORD
}
# その他、各々の機器に対して微調整(iosvl2はusername, password不要なので削除)
del data['devices']['iosvl2']['credentials']

with open(cml.CONFIG_YAML, "w") as f: 
    f.write(yaml.dump(data))

3: 端末に接続する

from genie import testbed
tb = testbed.load(cml.CONFIG_YAML)
conn = tb.devices[name]
conn.connect()
# connectできたかチェックする
conn.is_connected()

4: コマンド実行する

  • コマンド実行の関数はexecuteとconfigureがある。ライブラリの内部でモードを管理しているようで、手動でexecuteでconf tなどやるとエラーが出るので、特権モードの際はconfigureを使う。ただexecuteとconfigureが大量になると見苦しいので、ライブラリとして以下のようにまとめ、
  def execs(self, cmds: list[str | object]):
    print(f"#### device {self.name} ####")
    for cmd in cmds:
      if type(cmd) is str:
        self.conn.execute(cmd)
      elif isinstance(cmd, list):
        self.conn.configure(cmd)
      else:
        Exception(f"error execs @ ${cmd}")

などとして、利用する側は以下のようにすると便利かもしれない:

iosvl2_1.execs([
  [
    f"interface {ini.iosvl2_1.g0_0.name}",
    ...
  ],
  f"show interfaces brief",...
])
  • また、テストを行う際にwait untilをしたい場合がある。その場合は、show ...の結果にparseを使うと便利。dict形式でparseされた状態になる

参考) 他にも調べると、blitzとか生のコマンド叩かずに済むラッパライブラリなどあるようだが、学習用途なので、むしろ生のコマンドをできるだけ可視化する方が大事だと思っている

まだ少し使っただけだが、端末操作がかなり安定している。netmikoも少し使ったものの、端末関連のエラーで再現性のないエラーが出たりする(自分の使い方が悪いだけかも)ので、しばらくは使い続けられそう。

感想

堅いベストプラクティスはなさそうで、情報もそれほど豊富とは言えないため、ある程度手探りでコードを書く必要があるが、ハンズオンデモを行う際は複数の端末をあちこち切り替えてコマンド打つことになるので、いわゆるMakefile, ansible, terrafromのような宣言型のフレームワークよりはコードの相性が良い気がしている。現時点であまり情報はないが、とてもポテンシャルを感じるのでしばらくはネットワークの勉強と並行して、行うつもり。 また、gns3に対してもpyatsを併用して、安定した自動化処理を描くことができそうな気がしている。こちらはしばらく後かなぁ。


参考