動機
仕事で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を無効にする)必要がある。
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を併用して、安定した自動化処理を描くことができそうな気がしている。こちらはしばらく後かなぁ。