信頼できる唯一の情報源(SSoT)としてのNetBox導入:DCIM・IPAMの一元管理とネットワーク自動化

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

クイックスタート(5分)

スプレッドシートや分散したWikiページによるネットワーク管理は、運用上の悪夢を招きます。サブネット割り当ての不整合が生じ、インターフェースの説明文は陳腐化し、定期メンテナンスは当て推量になってしまいます。NetBoxは、データセンターインフラ管理(DCIM)およびIPアドレス管理(IPAM)における信頼できる唯一の情報源(SSoT: Single Source of Truth)として機能し、こうした混乱を解消します。

ローカル環境またはUbuntuのステージングVM(2 vCPU、4 GB RAM)にインスタンスを立ち上げるには、公式のDocker Composeプロジェクトを使用します。

# 1. 公式のNetBox Dockerリポジトリをクローン
git clone -b release https://github.com/netbox-community/netbox-docker.git
cd netbox-docker

# 2. 環境設定の上書きファイルを作成
touch docker-compose.override.yml

# 3. イメージをプルしてバックグラウンドでサービスを起動
docker compose pull
docker compose up -d

PostgreSQLとRedisが初期データベースマイグレーションを実行するまで、およそ60〜90秒待ちます。docker compose psでスタックの状態を確認してください。すべてのコンテナがhealthy(正常)と表示されたら、管理者アカウントを作成します。

docker compose exec netbox /opt/netbox/netbox/manage.py createsuperuser \
  --username admin \
  --email [email protected]

ブラウザでhttp://<your-server-ip>:8000にアクセスします。新しく作成したスーパーユーザーアカウントでサインインし、ダッシュボードを表示します。

ディープダイブ:DCIMとIPAMのモデリング

自動化スクリプトを作成する前に、NetBoxの基本的な設計原則を理解しておく必要があります。NetBoxは運用テレメトリ(稼働状態の実測値)ではなく、意図した状態(Intended State)をモデル化します。つまり、ネットワークトポロジーがどうあるべきかを定義するものであり、リンクのリアルタイムメトリクスやCPU使用率の急上昇、BGPネイバーのフラップ回数などを監視するツールではありません。

1. DCIMの基本階層

NetBoxは厳格なリレーショナルモデルを採用しています。外部キー参照のエラーを防ぐため、インフラデータは必ず以下の順序でボトムアップに構築してください。

  • 組織(Organization):物理的な拠点をリージョン(Region)、サイトグループ(Site Group)、サイト(Site)にグループ化します(例:Region: US-East → Site: us-east-dc1)。
  • ラック(Racks):標準サーバーキャビネットを定義します(例:標準19インチマウント対応の42U Rack-A01)。
  • デバイスタイプ(Device Types):正確なインターフェース番号を含むハードウェアプロファイルを定義します(例:1Gポート×48、10G SFP+アップリンク×4を備えたCisco Catalyst 9300-48P)。
  • デバイス(Devices):Rack-A01のラックユニットU24にマウントされた特定の個別機器(例:sw-leaf-01)をインスタンス化します。

2. IPAMのマッピング

NetBoxでは、IPアドレスは独立したスプレッドシートに記述されるのではなく、デバイスインターフェースに直接紐付けられます。これにより、クリーンなL2/L3トポロジーマッピングが徹底されます。

  • RIRと集約(RIRs & Aggregates):最上位のCIDRブロックを割り当てます(例:10.0.0.0/8や172.16.0.0/12などのRFC 1918プライベートIP割り当て)。
  • VRF:マルチテナントネットワークや専用のアウトオブバンド管理ファブリックを運用する際に、ルーティングテーブルを分離します。
  • プレフィックス(Prefixes):特定のVLANにマップされた機能ごとのサブネットを切り出します(例:VLAN 100 - OOBMにマッピングされた10.20.100.0/24)。
  • IPアドレス(IP Addresses):CIDRマスク付きの静的インターフェースIPを割り当てます(例:sw-leaf-01のGigabitEthernet1/0/1に10.20.100.11/24を割り当て)。

Python APIによるコンフィグ生成の自動化

SSoTの真のメリットは、パイプラインがAPIから直接「意図した状態」を取得できる点にあります。手動でのコピー&ペーストや、保守が困難な静的Jinja変数はもう不要です。

APIトークンの生成

Web UIの右上にあるユーザープロファイルをクリックし、API Tokens → Add a Tokenの順に進みます。サービスアカウントの場合は有効期限を空のままにし、40文字の16進数トークンをコピーして環境変数にエクスポートします。

export NETBOX_URL="http://127.0.0.1:8000"
export NETBOX_TOKEN="0123456789abcdef0123456789abcdef01234567"

Pythonを使用したインベントリの抽出とコンフィグ生成

pynetboxを使用してRESTエンドポイントをクエリし、Jinja2を使ってマルチベンダー対応またはCisco IOS向けのコンフィグを生成します。

import os
import ipaddress
import pynetbox
from jinja2 import Template

NETBOX_URL = os.getenv("NETBOX_URL", "http://127.0.0.1:8000")
NETBOX_TOKEN = os.getenv("NETBOX_TOKEN")

nb = pynetbox.api(NETBOX_URL, token=NETBOX_TOKEN)

# スイッチポート設定用のJinja2テンプレート
interface_template = Template("""
! {{ device.name }} 用の自動生成設定
hostname {{ device.name }}
!
{% for iface in interfaces %}
interface {{ iface.name }}
 description {{ iface.description or 'Unused Port' }}
 {% if iface.ip %}
 ip address {{ iface.ip.ip }} {{ iface.ip.netmask }}
 {% else %}
 no ip address
 {% endif %}
 {% if iface.enabled %}no shutdown{% else %}shutdown{% endif %}
!
{% endfor %}
""")

def build_config(device_name: str):
    device = nb.dcim.devices.get(name=device_name)
    if not device:
        raise ValueError(f"デバイス '{device_name}' がNetBoxのインベントリに見つかりません。")

    # 対象デバイスのすべての物理および論理インターフェースを取得
    interfaces = list(nb.dcim.interfaces.filter(device_id=device.id))

    for iface in interfaces:
        # このインターフェースにバインドされているプライマリIPv4/IPv6アドレスを取得
        ip_records = list(nb.ipam.ip_addresses.filter(interface_id=iface.id))
        if ip_records:
            # CIDR表記(例: 10.20.100.11/24)をIPとドット付きネットマスクにパース
            parsed_ip = ipaddress.ip_interface(ip_records[0].address)
            iface.ip = parsed_ip
        else:
            iface.ip = None

    rendered = interface_template.render(device=device, interfaces=interfaces)
    print(rendered)

if __name__ == "__main__":
    # 使用例:エッジスイッチのコンフィグを生成
    build_config("sw-leaf-01")

スクリプトを実行すると、2秒足らずでクリーンですぐにデプロイ可能なCisco CLIスニペットが出力されます。エンジニアがNetBox上でインターフェースの説明やIP割り当てを更新するだけで、人為的なタイポのリスクなしに50台のスイッチに一貫した変更を生成できます。

Ansibleのダイナミックインベントリ連携

静的なhosts.iniファイルを維持・管理する必要はありません。公式のNetBoxコレクションを使用することで、インベントリ、ロール、プラットフォームタグをAnsible Playbookに動的に同期できます。

ansible-galaxy collection install netbox.netbox

netbox_inventory.ymlという名前でダイナミックインベントリプラグイン設定ファイルを作成します。

plugin: netbox.netbox.nb_inventory
api_endpoint: http://127.0.0.1:8000
token: 0123456789abcdef0123456789abcdef01234567
validate_certs: false
config_context: true
group_by:
  - site
  - device_roles
query_filters:
  - status: active

Ansibleがホストグループを正しく構築しているか確認します。

ansible-inventory -i netbox_inventory.yml --graph

Day-2運用のための実践的Tips

  • プラットフォーム変数をConfig Contextsに保存する:デバイスのモデリングをシンプルに保ちます。BGP AS番号(例:65001)、NTPサーバー(10.0.0.123)、Syslog転送先などのグローバルおよびサイトレベルの変数は、NetBoxのConfig Contexts内に定義します。
  • WebhookでGitOpsパイプラインをトリガーする:インターフェースやデバイスが更新されるたびにGitHub ActionsやGitLab CI RunnerへHTTP POSTペイロードを送信するようにNetBox Webhookを設定します。これにより、即座にドライランによる差分チェック(diff check)を開始できます。
  • 厳格なSSoT規律を徹底する:本番環境のスイッチに対するアドホックなCLI変更を禁止します。エンジニアが問題を一時的に修正するためにNetBoxをバイパスした場合、次回の自動デプロイでその修正が上書きされてしまいます。
  • 日次データベーススナップショットを自動化する:PostgreSQLにはネットワークのすべての真実(truth)が保持されています。毎日UTC 02:00にデータベースをダンプし、圧縮アーカイブをオフサイトに保存するcronジョブを設定してください。
# PostgreSQLの日次自動バックアップ
docker compose exec -T postgres pg_dump -U netbox netbox | gzip > /var/backups/netbox_$(date +%F_%H%M%S).sql.gz
Share: