はじめに
こんにちは、SREの井上です。今回は、Oisix ra daichi Inc.(以後はORD)で機器管理をGoogleスプレッドシートからNetBoxへ移行し、NW機器のコンフィグを自動取得した社内事例を紹介いたします。
ORDでは、美味しい野菜を多くのお客様へお届けするために多数の拠点を置いています。多拠点をつなぐORDのネットワークは、本社が位置する大崎や物流拠点の海老名ステーション、もともと別ブランドだった「らでぃっしゅぼーや」「大地を守る会」のネットワークが相互接続されて構成されています。オンプレミス環境は、約600台以上のNW機器によって支えられており、ORDのNWチームによって管理されています。
この管理対象となるネットワークが年々拡大する一方で、機器情報の管理や運用効率化をすすめていくことが課題となっていました。
運用管理の課題
ORDのネットワークを構成するルータ、スイッチ、Firewall(FW)、Access Point(AP)などの機器は、数多くの物理/論理リソースの管理が必要です。例えば、スイッチ1台を管理すると次のような項目が考えられます。
- ホスト名
- 設置拠点
- 機種情報
- IPアドレス/サブネットマスク
- ネットワークコンフィグ
- シリアル番号
- OSバージョン
- 保守情報
このような機器情報は、企業独自のアプリケーションやExcelなどのいわゆる台帳をもとに情報を記録しているかと思います。ORDでも同様に、次のような3つのGoogleスプレッドシートを元に台帳管理をしていました。
- サーバ管理表
- NW機器管理表
- IP管理表(セグメント一覧、IPアドレスの使用状況)
しかし、Googleスプレッドシートの管理は、ちょっとした情報を整理するには優れている反面、正確に管理するのは困難です。ORDの運用を例に取ると、次のような課題がありました。
- NW機器管理表に記載されているIPアドレスが、IP管理表に反映されていない。
- フォーマットが異なっていて、検索性が低い。
- 誰がいつシートを更新したのかを確認することが難しい。
- 表記揺れがあり、フィルターが機能しない。
このような課題もあり、GoogleスプレッドシートからNetBoxへの移行を検討しました。
NetBoxへの移行
NetBoxとは
NetBoxは、Apache License. Version 2.0 として無料で利用可能なオープンソースソフトウェア(OSS)です*1。IPアドレス管理(IPAM)やデータセンタインフラストラクチャ管理(DCIM)の機能を持っており、次の情報を管理可能です*2。
- IPアドレス管理(IPAM) - ネットワークアドレス、IPアドレス、VRF、VLAN
- ラック - マウントしている位置
- デバイス - デバイスの種類
- ケーブル接続 - デバイス間のネットワーク、コンソール、電源接続
- 仮想化 - 仮想マシン
- データ回線 - プロバイダー情報
NetBoxは、REST APIの対応もしているため、まとまったデータを1度に登録・変更・削除が可能です。また、Dockerコンテナへの対応もしているため、環境設定から機器情報の登録設定まで全てInfrastructure as Code(IaC)として管理できる点が大きな魅力となっています。
今すぐ機能を試してみたい方は、コミュニティがデモサイトを用意していますのでこちらをご確認ください。
NetBoxへの移行準備
さて、GoogleスプレッドシートからNetBoxへ移行するというのは、言うは易く行うは難しです。移行までに実施したことを順を追って説明します。
- Googleスプレッドシートのフォーマットを正規化してCSVとして扱う。
- devicetype-libraryを活用する。
- Ansibleを使用して、CSVファイルをインポートする。
Googleスプレッドシートのフォーマットを正規化してCSVとして扱う
先に述べた3つのGoogleスプレッドシートは、シートごとにフォーマットが異なっていたため、そのまま扱うには難しい状態となっていました。そのため、まずは各シートを扱いやすいCSV形式へ出力できるようにチームメンバと次のルールに則うように手作業で修正をしました。
- 同じような意味を持つcolumn(サーバー用途と備考など)は1つにまとめる。
- NULL状態のセルは、作成しない。
- 色付けによって識別させているcolumnは、新たにcolumnを作成する。
- 左上のセル「A1」からcolumnが始まる状態にする。
- 表記揺れを修正する。
- 結合されているセルを元に戻す。
どれも泥臭い作業ですが、NetBoxへ移行しても登録されている情報に誤りなどがあれば、移行の意味がありません。 長年積もったものを棚卸しするには重要な工程です。全ての情報を整理できたわけではありませんが、他部署の方にも協力いただき信頼性の高い情報へ修正しました。
devicetype-libraryを活用する
NetBoxには、NW機器を登録する前にDevice Typesと呼ばれるデバイスの物理情報(ラックの高さと深さなど)やその個々のコンポーネント(コンソール、電源、ネットワークインターフェイスなど)をあらかじめ定義する機能があります。例えば、48個のイーサネットインターフェイスを備えたJuniper EX4300-48Tのデバイスタイプを定義し、「switch1」、「switch2」などの名前でNW機器を登録すると、デバイスの物理情報を自動的に継承することができます。これにより、機器ごとに統一された情報を登録することができます。
しかし、ORDで管理している何台もの機器を全てDevice Typesに定義するのは手間がかかります。そのため、Device Typesの登録はdevicetype-libraryというOSSを活用しました*3。devicetype-libraryは、NW機器やサーバの情報がYAMLで表現されメーカーごとのDevice Typesが定義されています。このYAMLをNetBoxにインポートすることでメーカ名や機器名の表記揺れが発生しませんし、メンテナンスはコミュニティが対応してくれます。
利用当初は、全てのNW機器の情報がdevicetype-libraryに管理されていたわけではありませんでした。そのため、未定義のNW機器に関してはdevicetype-libraryへPull Request(PR)を出して微力ながらOSSへコントリビュートして対応をしました。こちらが、コントリビューションガイド*4を参考にして出したPRです。YAMLに合わせて機器情報を記載するのみなので、プログラムの修正などに比べるとコントリビュートの難易度が低いとかと思います。OSS活動に興味があるけど気軽なところから始めてみたいという方がいればぜひ、この機会にPRを出してみるのはいかがでしょうか?
Ansibleを使用して、CSVファイルをインポートする
Googleスプレッドシートのフォーマットが整えば、CSVとして出力してNetBoxへインポートするだけです。CSVファイルのインポートは、Ansibleを活用しました。NetBoxのAnsible Collectionsは、netbox-communityによって管理されています*5。Ansible Galaxyを使用することで、NetBoxの操作に必要なプラグインやモジュールをインストールすることができます。Ansible Galaxyによってインストールされるモジュールは、NetBoxの操作に必要な、CRUD(Create, Read, Update, Delete)の機能が一通り揃っています。Ansible Playbookで操作を行うためには、NetBoxのAPIキーとアクセス先のURLのみを使用するだけです。NetBoxのGUI上の画面で登録する時に必要なパラメータをサンプルコード*6にそってPlaybookに書き起こすだけなので、あまり苦労せずに設定することができました。
Ansibleを活用したNetwork機器の自動化
NetBoxとAnsibleとの連携は、データのインポートだけではありません。NetBox上で管理されている機器をAnsibleのダイナミックインベントリとして活用することができます。Ansibleの実行時に、メーカー名、SiteやRoleなど特定の機器に対して柔軟に実行することが可能です。また、NetBoxに管理している情報をホスト変数として活用できるため、機器に応じたパラメータ設定も可能となっています。
ORDでは、Aruba、Cisco IOS、Fortinetなど複数のNW機器が存在することから、ansible_network_os
の情報をNetBoxから取得することで、NW機器のOSを意識しないPlaybookの構成を意識しています。ダイナミックインベントリの例を次に示します。
--- # netbox_inventory.yml file in YAML format # Example command line: ansible-inventory -v --list -i netbox_inventory.yml # https://docs.ansible.com/ansible/latest/collections/netbox/netbox/nb_inventory_inventory.html plugin: netbox.netbox.nb_inventory api_endpoint: https://xxxxxxxxx/ token: xxxxxxxxx group_by: - manufacturers - sites - device_roles compose: ansible_network_os: custom_fields.ansible_network_os
NW機器のコンフィグを取得する例をもとに説明すると、大まかにディレクトリ構成は次のようになっています。
. ├── get-config.yml └── roles └── get_config └── tasks ├── arubanetworks.aoscx.aoscx.yml ├── cisco.ios.ios.yml ├── main.yml └── unsupported_platform.yml
get-config.ymlは、role(get_config)を呼び出すシンプルなPlaybookとなっています。
--- - name: get network config hosts: all gather_facts: false roles: - role: get_config when: - ansible_network_os is defined - ansible_network_os | length > 0 - primary_ip4 is defined
role内main.ymlでは、with_first_found
*7を使用してansible_network_os
ごとのPlaybookを実行する構成となっています。該当するNW機器が存在しない場合には、エラー処理用のPlaybook(unsupported_platform.yml)を実行することで対処をしています。
このような構成をとることで、ネットワーク機器ごとに異なるモジュールやansible_network_osを抽象化してPlaybookを実行することができます。
--- - name: load supported platform file or fail include_tasks: "{{ item }}" with_first_found: - "{{ role_path }}/tasks/{{ ansible_network_os }}.yml" - "{{ role_path }}/tasks/unsupported_platform.yml"
Cisco IOSの機器に対するPlaybook(cisco.ios.ios.yml)を例に挙げると、ios_commandモジュールを使用して実行結果を表示させるようにしています。
--- - name: run show running-config on remote devices (ios) connection: network_cli cisco.ios.ios_command: commands: - show running-config register: result_sh_run ignore_errors: true - name: print show running-config (ios) debug: msg: "{{ result_sh_run.stdout_lines }}"
このようなPlaybookの構成にのっとり、show running-config
などのコマンドをAWX*8から定期実行し、コンフィグ情報はすべてGitHub上に管理をしています。機器のOSバージョンや設定情報をNW機器へログインしなくとも確認することができるため、どのような設定がされているかをすぐに調査することができる仕組みとなっています。
まとめ
ORDで活用しているNetBoxとAnsibleの紹介でした。 まだまだNW自動化としては、コンフィグの取得といった基本的なことしか出来ていません。今後、NW機器へのコンフィグ設定やNetBoxに登録された情報をどのように活用していくかを検討していきたいと思います。
*3:netbox-community/devicetype-library
*4:devicetype-library/CONTRIBUTING.md at master · netbox-community/devicetype-library
*5:NetBox modules for Ansible using Ansible Collections
*6:netbox.netbox.netbox_device module – Create, update or delete devices within NetBox — Ansible Documentation
*7:ansible.builtin.first_found lookup – return first file found from list — Ansible Documentation