Containerlab と vJunos で体験するクラウドネットワーク構築

Containerlab と Juniper の無償仮想イメージ vJunos を使用し、データセンターネットワーク(NW)の定番アーキテクチャ「Leaf-Spine 構成」をゼロから構築するハンズオン記事です。eBGP による Underlay 構成を皮切りに、EVPN/VXLAN によるテナント L2 拡張、ESI-LAG を用いた冗長化、VRF Route Leaking によるインターネット接続ゲートウェイ模擬まで、クラウド NW の中核技術をひと通り体験できます。ハードウェア不要・無償イメージのみで動く手順と全設定例を掲載しています。

はじめに

こんにちは。NTTドコモビジネスのクラウド、SDPFクラウド/サーバー(以降、SDPF クラウド)の内製開発に従事している堀岡勇杜と申します。 私が主に担当しているのは、ESI(Elastic Service Infrastructure)という名称の、クラウドのNWオーケストレータの開発です。ESI チームの業務内容については、こちらの記事で詳しく紹介しています。 ※ 本記事で出てくるEVPN Multihoming の関連用語であるESI(Ethernet Segment Identifier)とは全くの別物です。

突然ですが、データセンター NW の定番アーキテクチャである Leaf-Spine(CLOS) と、その上で動く EVPN/VXLAN は、クラウド NW の中核技術です。しかし実機やシミュレータがなければ、その挙動を肌で理解するのは大変難しいです。私自身も入社当時(2025年4月)はクラウド NW については完全な初学者だったのですが、この 1 年間で勉強させていただき、その全貌の一端が理解できるようになってきました。本記事を通じて、私が得た知見を共有できましたら幸いです。さまざまな用語が出てきますが、それらを全て解説するのは不可能であるため、気になる点は適宜調べながら進めていただければと思います。

用語解説

Leaf-Spine … サーバーを収容する「Leaf(葉)」スイッチと、Leaf 同士をつなぐ「Spine(背骨)」スイッチの 2 階層でネットワークを組む CLOS の定番設計。どのサーバー間も同じホップ数で通信でき、帯域を横に足しやすいのが特長です。SDPFクラウドでは、Spineのさらに上のSuper Spineが存在しており、3 階層の CLOS になっています。

EVPN/VXLAN … 物理的に離れたサーバー同士を「同じ LAN にいるかのように」つなぐ仮想ネットワーク技術です。EVPN が「誰がどこにいるか」の情報交換(制御プレーン)、VXLAN が実データのトンネル転送(データプレーン)を担います。

本記事では、OSS である Containerlab と Juniper Networks 社の vJunos(無償の仮想ルータ/スイッチイメージ)を使用し、典型的な Leaf-Spine 構成をゼロから組み立てます。最終的には以下を達成します。

  • eBGPによる Underlay の経路交換
  • iBGP + EVPN Type-2/3 による MAC/IP 学習(C-Plane = 制御プレーン)
  • VXLAN によるテナント(利用者)トラフィックのカプセル化(D-Plane = データプレーン)
  • ESI-LAG による EVPN Multihoming(サーバーの複数スイッチへの冗長接続)
  • Border Leaf + VRF Route Leaking(仮想ルーティングテーブル間の経路共有)によるインターネット接続ゲートウェイ模擬

「SDPFクラウドの SDN コントローラや NW オーケストレータが裏で何をしているのか」をハンズオンで体験し、クラウド NW の裏側を覗いていただける構成になっています。

⚠️ 本記事は学習用ラボ構成を前提としています

動作させることを優先しているため、本番設計とは異なる選択をしている箇所が多々あります(例: MTU デフォルトのまま、BGP 認証なし、など)


前提知識

本記事の主な対象読者は、BGP の基本概念(AS・ピアリング・経路広告)を理解している、データセンター NW の Overlay 技術を手を動かして学びたいインフラエンジニアや学生です。以下の知識があるとスムーズに進められます。

分野 期待するレベルの目安
Linux 操作 コマンドライン操作(ip, ping, tcpdump など)、Network Namespace の概念
TCP/IP 基礎 IP アドレス・サブネットマスク・ルーティングの仕組み、L2(Ethernet)と L3(IP)の違い
BGP 基礎 AS(Autonomous System)・ASN・eBGP / iBGP の区別、経路広告・ピアリングの概念
Docker 基礎 docker ps / docker pull などの基本操作、コンテナとイメージの違い

各セクションに設けている「用語解説」や「Q&A」は補足情報です。すでにご存知の方は読み飛ばしてください。


全体像

構築するトポロジ

最終的なゴールは、物理的に異なるラックに収容された HV1(ハイパーバイザー)上の VM1(仮想マシン)と BM1(ベアメタルサーバー)が同一の L2 ネットワーク上で通信でき、さらにそこからインターネットへ抜けられる状態を作ることです。これを実現するために、Underlay(物理 IP 転送の土台)→ Overlay(EVPN/VXLAN による L2 延伸)→ Internet GW(VRF Route Leaking による外部接続)の順に積み上げていきます。

主な登場人物は以下の通りです。

ノード 役割 ASN Loopback
spine1 Spine #1 64512 10.255.255.1
spine2 Spine #2 64513 10.255.255.2
leaf1-1 Underlay Leaf(HV=ハイパーバイザー収容) 65000 10.255.255.11
leaf2-1 / leaf2-2 Overlay Leaf(BM=ベアメタルサーバー収容、ESI-LAG ペア検証) 65000 10.255.255.21 / .22
leaf3-1 Border Leaf(Internet GW 収容) 65000 10.255.255.31
rr1 Route Reflector(経路情報を集めて他に配る中継役) 65000 10.255.255.101
hv1 ハイパーバイザー模擬(Linux + FRR、VTEP=VXLANトンネルの端点 を持つ) 65000 10.255.255.201
bm1 ベアメタルサーバー模擬(Linux)
inet-gw1 Internet Gateway 模擬(vJunos-router) 65002 198.51.100.1
isp1 外部 ISP 模擬 65001 192.0.2.1

用語解説

Underlay(アンダーレイ) … 物理スイッチ・ルータが実際に IP パケットを転送する「土台」のネットワーク層です。本記事では Leaf-Spine 間の P2P リンクと eBGP がこれにあたります。

Overlay(オーバーレイ) … Underlay の上に「論理的に重ねた」仮想ネットワーク層です。本記事では VXLAN がデータのカプセル化(D-Plane)、EVPN が経路情報の交換(C-Plane)を担い、テナントの L2 セグメントを物理的に離れたノード間へ延伸します。Underlay が「道路」なら Overlay は「宅配便」のようなイメージです。

ポイント

  • Spine ごとに ASN を分ける(64512 / 64513)。Leaf 側は multipath multiple-as で Spine 2 台への ECMP(Equal-Cost Multi-Path)を有効にしています。この設定により、障害発生時はベストパス再選定なしで残存パスに切り替わります。
  • Leaf は全て同じ ASN(65000) にして増設コストを下げています。詳細は以下を参照。
  • RR は Underlay にも参加しますが、直接データを転送せず Overlay の経路反射(他のノードの経路情報をまとめて再配布する役割)を担当します。
  • HV 側は FRR で EVPN ピアリングを代用し、RR と EVPN ピアを張ります(実際のクラウドでは SDN コントローラが HV 上の経路を収集し EVPN に変換します)。

Q. なぜ Leaf を全て同じ ASN にするのか?

RFC 7938 は「Leaf ごとに別 ASN」を推奨していますが、本構成では共通 ASN(65000)を採用しました。トレードオフは次の通り。

共通 ASN(本記事) 別 ASN(RFC 7938 推奨)
増設運用 ✅ Leaf テンプレ流用、Spine 側も peer-as 1 つ ❌ Leaf ごとに ASN 採番、Spine 側も増やすたび neighbor 別設定
AS-PATH ループ防止 as-override で無効化される ✅ そのまま効く
トラブルシュート ❌ AS-PATH に Leaf 識別子が出ない ✅ どの Leaf 経由か AS-PATH で分かる

進め方

  1. Containerlab で機器を起動
  2. Underlay(IP / eBGP)構築
  3. Overlay(iBGP EVPN / VXLAN / ESI-LAG)構築
  4. Border Leaf + Internet GW 構築

各セクションの末尾には「動作確認」と「完成状態チェックリスト」を載せています。


前提とする環境

以下を準備してください。

項目 内容
マシンの推奨スペック メモリ 32GB 以上(vJunos は 1 ノードあたり 4GB ほど使います)、ディスク空き容量 20GB 以上 (vJunos の qcow2 は 1 イメージ約 5GB、Docker ビルド後は合計 10GB 超になります)
ホスト OS Linux(Ubuntu 24.04 で検証)。Docker が動く環境ならOK
Docker v29.2.0 で検証
Containerlab v0.75.0 で検証。インストール手順
vJunos イメージ vJunos-switch-25.4R1.12, vJunos-router-25.4R1.12(手順は以下)
ゲスト OS 軽量 Linux nicolaka/netshoot(HV / BM 用)。コンテナ内の FRR は v10.6.1 で検証
エディタ VS Code + Containerlab 拡張があると便利

vJunos イメージの準備(vrnetlab でコンテナ化)

vJunos は Juniper が無償で公開している仮想ルータ/スイッチイメージです。ただし配布形式は qcow2(KVM 用)なので、Containerlab で使うには vrnetlab で Docker イメージに変換する必要があります。詳細はこちらを参照。

# 1. vrnetlab をクローン
git clone https://github.com/srl-labs/vrnetlab && cd vrnetlab/juniper

# 2. Juniper 公式サイトからダウンロードした qcow2 を vrnetlab 下に配置
# https://support.juniper.net/support/downloads で vjunos-switch (または vjunos-router) で検索
cp ~/Downloads/vJunos-router-25.4R1.12.qcow2 vjunosrouter/
cp ~/Downloads/vJunos-switch-25.4R1.12.qcow2 vjunosswitch/

# 3. Docker イメージをビルド(それぞれ数分かかる)
cd vjunos-switch && make && cd ..
cd vjunos-router && make && cd ..

# 4. ビルド結果を確認
docker images | grep vjunos
# vrnetlab/juniper_vjunos-switch   25.4R1.12   ...
# vrnetlab/juniper_vjunos-router   25.4R1.12   ...
# HV / BM 用イメージ
docker pull nicolaka/netshoot:v0.15

⚠️ vJunos のライセンスについて

vJunos は 評価・検証・学習用途で無償利用可能 です(商用サポートなし)。以下の点に注意してください。

  • 機能制限はほぼありませんが、commit 時に warning: requires 'bgp' license 等の警告が出ます。これはライセンスキーを投入していないだけで、BGP 自体は問題なく動作します(本記事の全手順はライセンスなしで完走できます)
  • 本番環境や商用目的での利用には正規ライセンスが必要です。詳しくは Juniper vJunos ページ を参照してください

1. 環境構築 — Containerlab で機器を起動

この章では、下図のように Spine / Leaf / RR / サーバー模擬など全 11 ノードを Containerlab で一括起動し、SSH でログインできる状態を目指します。

1.1 トポロジ定義(clos-network.clab.yml)

name: clos-network

topology:
  nodes:
    # --- SPINE ---
    spine1:
      kind: juniper_vjunosswitch
      image: vrnetlab/juniper_vjunos-switch:25.4R1.12
    spine2:
      kind: juniper_vjunosswitch
      image: vrnetlab/juniper_vjunos-switch:25.4R1.12

    # --- LEAF ---
    leaf1-1:
      kind: juniper_vjunosswitch
      image: vrnetlab/juniper_vjunos-switch:25.4R1.12
    leaf2-1:
      kind: juniper_vjunosswitch
      image: vrnetlab/juniper_vjunos-switch:25.4R1.12
    leaf2-2:
      kind: juniper_vjunosswitch
      image: vrnetlab/juniper_vjunos-switch:25.4R1.12
    leaf3-1:
      kind: juniper_vjunosswitch
      image: vrnetlab/juniper_vjunos-switch:25.4R1.12

    # --- Route Reflector ---
    rr1:
      kind: juniper_vjunosrouter
      image: vrnetlab/juniper_vjunos-router:25.4R1.12

    # --- HV / BM 模擬 ---
    hv1:
      kind: linux
      image: nicolaka/netshoot:v0.15
    bm1:
      kind: linux
      image: nicolaka/netshoot:v0.15

    # --- Internet Gateway / 外部 ISP 模擬 ---
    inet-gw1:
      kind: juniper_vjunosrouter
      image: vrnetlab/juniper_vjunos-router:25.4R1.12
    isp1:
      kind: juniper_vjunosrouter
      image: vrnetlab/juniper_vjunos-router:25.4R1.12

  links:
    # Spine <-> Leaf
    - endpoints: ["spine1:eth1", "leaf1-1:eth1"]
    - endpoints: ["spine1:eth2", "leaf2-1:eth1"]
    - endpoints: ["spine1:eth3", "leaf2-2:eth1"]
    - endpoints: ["spine1:eth4", "leaf3-1:eth1"]
    - endpoints: ["spine2:eth1", "leaf1-1:eth2"]
    - endpoints: ["spine2:eth2", "leaf2-1:eth2"]
    - endpoints: ["spine2:eth3", "leaf2-2:eth2"]
    - endpoints: ["spine2:eth4", "leaf3-1:eth2"]

    # Spine <-> RR
    - endpoints: ["spine1:eth10", "rr1:eth1"]
    - endpoints: ["spine2:eth10", "rr1:eth2"]

    # Server / GW
    - endpoints: ["leaf1-1:eth3", "hv1:eth1"]
    - endpoints: ["leaf2-1:eth3", "bm1:eth1"]
    - endpoints: ["leaf2-2:eth3", "bm1:eth2"]
    - endpoints: ["leaf3-1:eth3", "inet-gw1:eth1"]
    - endpoints: ["inet-gw1:eth2", "isp1:eth1"]

1.2 デプロイ

clab deploy -t clos-network.clab.yml

# トポロジを Web UI で確認(リモートサーバーの場合はポートフォワード)
clab graph -t clos-network.clab.yml

# 全部壊してやり直したくなった時は
clab destroy -t clos-network.clab.yml

ノードへの SSH は ssh admin@clab-clos-network-spine1(初期パスワードは admin@123)。なお、Linux コンテナ(hv1 / bm1)は docker exec -it clab-clos-network-hv1 bash のように直接シェルに入る方が確実です。 ContainerlabのVS Code拡張を入れておくと、コンテナをまとめて管理できて便利です。

Spine・Leaf・RR・Inet-GW・ISPにおいて、あらかじめ以下の手順で root パスワードを設定して commit しておきます。これは以降の設定をコミットする上で必須の操作です。admin ユーザーのパスワード変更ではないことに留意。

configure
set system root-authentication plain-text-password
commit

✅ 完成状態チェックリスト

  • clab deploy がエラーなく完了する
  • docker ps で全 11 ノードが Up になっている
  • ssh admin@clab-clos-network-spine1 でログインできる
  • clab graph の Web UI でトポロジが想定通り表示される

ここまでで、冒頭の図で示した全ノードが起動し、各機器へログインできる状態になりました。まだ NW 設定は入っていないので、次のセクションで Underlay から構築していきます。


2. Underlay の構築 — eBGP で Loopback 同士を疎通させる

この章では、下図のように各ノードに IP アドレスを振り、Spine-Leaf 間で eBGP を張ることで、全ノードの Loopback 同士が疎通できる状態を目指します。この「下地」が後の Overlay(EVPN/VXLAN)の土台になります。

2.1 IP アドレス設計

P2P リンク(機器同士を 1対1 でつなぐリンク)は /30(IP 2 個分)、Loopback は /32(IP 1 個)。Spine 側を .1、Leaf 側を .2 の規則で設計しています。

リンク Spine 側 Leaf 側
spine1 ↔ leaf1-1 10.1.11.1/30 10.1.11.2/30
spine1 ↔ leaf2-1 10.1.21.1/30 10.1.21.2/30
spine1 ↔ leaf2-2 10.1.22.1/30 10.1.22.2/30
spine1 ↔ leaf3-1 10.1.31.1/30 10.1.31.2/30
spine1 ↔ rr1 10.1.101.1/30 10.1.101.2/30
spine2 ↔ * 10.2.x.1/30 10.2.x.2/30(同様)
leaf1-1 ↔ hv1 10.11.201.1/30 10.11.201.2/30

2.2 各ノードの IP / Loopback 設定

代表として spine1, hv1 を掲載します。他のノードも同じパターン(IP のみ差し替え)。

spine1

configure
set routing-options router-id 10.255.255.1
set interfaces lo0 unit 0 family inet address 10.255.255.1/32

set interfaces ge-0/0/0 unit 0 family inet address 10.1.11.1/30
set interfaces ge-0/0/1 unit 0 family inet address 10.1.21.1/30
set interfaces ge-0/0/2 unit 0 family inet address 10.1.22.1/30
set interfaces ge-0/0/3 unit 0 family inet address 10.1.31.1/30
set interfaces ge-0/0/9 unit 0 family inet address 10.1.101.1/30
commit

spine2 / leaf1-1 / leaf2-1 / leaf2-2 / leaf3-1 / rr1 のコマンドを開く

spine2

configure
set routing-options router-id 10.255.255.2
set interfaces lo0 unit 0 family inet address 10.255.255.2/32

set interfaces ge-0/0/0 unit 0 family inet address 10.2.11.1/30
set interfaces ge-0/0/1 unit 0 family inet address 10.2.21.1/30
set interfaces ge-0/0/2 unit 0 family inet address 10.2.22.1/30
set interfaces ge-0/0/3 unit 0 family inet address 10.2.31.1/30
set interfaces ge-0/0/9 unit 0 family inet address 10.2.101.1/30
commit

leaf1-1

configure
set routing-options router-id 10.255.255.11
set interfaces lo0 unit 0 family inet address 10.255.255.11/32

set interfaces ge-0/0/0 unit 0 family inet address 10.1.11.2/30
set interfaces ge-0/0/1 unit 0 family inet address 10.2.11.2/30
set interfaces ge-0/0/2 unit 0 family inet address 10.11.201.1/30
commit

leaf2-1

configure
set routing-options router-id 10.255.255.21
set interfaces lo0 unit 0 family inet address 10.255.255.21/32

set interfaces ge-0/0/0 unit 0 family inet address 10.1.21.2/30
set interfaces ge-0/0/1 unit 0 family inet address 10.2.21.2/30
commit

leaf2-2

configure
set routing-options router-id 10.255.255.22
set interfaces lo0 unit 0 family inet address 10.255.255.22/32

set interfaces ge-0/0/0 unit 0 family inet address 10.1.22.2/30
set interfaces ge-0/0/1 unit 0 family inet address 10.2.22.2/30
commit

leaf3-1

configure
set routing-options router-id 10.255.255.31
set interfaces lo0 unit 0 family inet address 10.255.255.31/32

set interfaces ge-0/0/0 unit 0 family inet address 10.1.31.2/30
set interfaces ge-0/0/1 unit 0 family inet address 10.2.31.2/30
commit

rr1

configure
set routing-options router-id 10.255.255.101
set interfaces lo0 unit 0 family inet address 10.255.255.101/32

set interfaces ge-0/0/0 unit 0 family inet address 10.1.101.2/30
set interfaces ge-0/0/1 unit 0 family inet address 10.2.101.2/30
commit

hv1(Linux なので別物)

# FRR のインストール
apk add frr
sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons
/usr/lib/frr/frrinit.sh start

# IP 設定
ip addr add 10.255.255.201/32 dev lo
ip addr add 10.11.201.2/30 dev eth1
ip link set eth1 up
ip route del default
ip route add default via 10.11.201.1

⚠️ ip route del default を実行すると management NW 経由の SSH が切れます。以降 hv1 への操作は docker exec -it clab-clos-network-hv1 bash で入ってください。

直結リンクで ping が通れば OK です。

2.3 eBGP の設定

Underlay の目標は「全ノードの Loopback 同士を疎通させること」。これができれば、あとで Overlay (EVPN/VXLAN)がその「下地」の上に乗れます。Spine と Leaf で eBGP(異なる ASN 同士の BGP)を張り、Loopback 経路を広告します。

ポイント

  • Spine ごとに ASN を分けるspine1=64512, spine2=64513
  • Spine 側に as-override:Leaf 共通 ASN 方式の代償として、BGP の「AS-PATH(経路が通ってきた ASN の履歴)に同じ ASN があるとループとみなして破棄する」ルールを回避するため、Spine 側で AS-PATH 上の Leaf ASN を Spine 自身の ASN に書き換えます
  • Leaf 側に multipath multiple-as:spine1/spine2 の ASN が異なるため、両方を ECMP として使うために必須
  • ECMP 有効化load-balance per-packet という名前ですがこれは Junos のレガシーな仕様で、実態は 5-tuple(送信元/宛先 IP・ポート・プロトコル)のハッシュによるフロー単位の負荷分散です
  • 広告経路は Loopback のみfrom interface lo0.0 で Loopback に絞ることで、リンク IP が広告されず経路がスッキリします

commit 時に以下の警告が出ますが、無視して OK です(詳しくは「前提とする環境」のライセンス注記を参照)。

warning: requires 'bgp' license
commit complete

spine1

configure

# ECMP 有効化
set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

# 経路広告ポリシー(Loopback + BGP 経路)
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-BGP from protocol bgp
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-BGP then accept
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-DIRECT then accept

# BGP(ASN 64512)
set routing-options autonomous-system 64512
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY
set protocols bgp group UNDERLAY peer-as 65000
set protocols bgp group UNDERLAY as-override

# 各 Leaf / RR への neighbor
set protocols bgp group UNDERLAY neighbor 10.1.11.2
set protocols bgp group UNDERLAY neighbor 10.1.21.2
set protocols bgp group UNDERLAY neighbor 10.1.22.2
set protocols bgp group UNDERLAY neighbor 10.1.31.2
set protocols bgp group UNDERLAY neighbor 10.1.101.2

commit

spine2 のコマンドを開く

configure

set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-BGP from protocol bgp
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-BGP then accept
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALLOW-DIRECT then accept

# BGP(ASN 64513)
set routing-options autonomous-system 64513
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY
set protocols bgp group UNDERLAY peer-as 65000
set protocols bgp group UNDERLAY as-override

set protocols bgp group UNDERLAY neighbor 10.2.11.2
set protocols bgp group UNDERLAY neighbor 10.2.21.2
set protocols bgp group UNDERLAY neighbor 10.2.22.2
set protocols bgp group UNDERLAY neighbor 10.2.31.2
set protocols bgp group UNDERLAY neighbor 10.2.101.2

commit

leaf1-1

leaf1-1 は HV1(FRR)が直接 BGP を喋らないため、HV1 Loopback 宛の static route を広告に含めます。

configure

# ECMP
set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

# Loopback + static を広告
set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT then accept
set policy-options policy-statement EXPORT-UNDERLAY term ALL-STATIC from protocol static
set policy-options policy-statement EXPORT-UNDERLAY term ALL-STATIC then accept

# BGP(multiple-as は必須)
set routing-options autonomous-system 65000
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath multiple-as
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY

set protocols bgp group UNDERLAY neighbor 10.1.11.1 peer-as 64512
set protocols bgp group UNDERLAY neighbor 10.2.11.1 peer-as 64513

# HV1 Loopback への static route
set routing-options static route 10.255.255.201/32 next-hop 10.11.201.2

commit

leaf2-1 / leaf2-2 / leaf3-1 / rr1 のコマンドを開く

leaf2-1

configure

set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT then accept

set routing-options autonomous-system 65000
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath multiple-as
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY

set protocols bgp group UNDERLAY neighbor 10.1.21.1 peer-as 64512
set protocols bgp group UNDERLAY neighbor 10.2.21.1 peer-as 64513

commit

leaf2-2

configure

set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT then accept

set routing-options autonomous-system 65000
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath multiple-as
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY

set protocols bgp group UNDERLAY neighbor 10.1.22.1 peer-as 64512
set protocols bgp group UNDERLAY neighbor 10.2.22.1 peer-as 64513

commit

leaf3-1

configure

set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT then accept

set routing-options autonomous-system 65000
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath multiple-as
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY

set protocols bgp group UNDERLAY neighbor 10.1.31.1 peer-as 64512
set protocols bgp group UNDERLAY neighbor 10.2.31.1 peer-as 64513

commit

rr1

configure

set policy-options policy-statement PFE-LB term 1 then load-balance per-packet
set routing-options forwarding-table export PFE-LB

set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT from interface lo0.0
set policy-options policy-statement EXPORT-UNDERLAY term ALL-DIRECT then accept

set routing-options autonomous-system 65000
set protocols bgp group UNDERLAY type external
set protocols bgp group UNDERLAY multipath multiple-as
set protocols bgp group UNDERLAY export EXPORT-UNDERLAY

set protocols bgp group UNDERLAY neighbor 10.1.101.1 peer-as 64512
set protocols bgp group UNDERLAY neighbor 10.2.101.1 peer-as 64513

commit

2.4 動作確認

admin@spine1# run show bgp summary
...
Peer                     AS      InPkt     OutPkt   ...   State|#Active/Received/Accepted/Damped...
10.1.11.2             65000          6          8   ...   58 Establ
10.1.21.2             65000          5          7   ...   33 Establ
10.1.22.2             65000          4          7   ...   22 Establ
10.1.31.2             65000          4          7   ...   13 Establ
10.1.101.2            65000          4          7   ...    6 Establ

Spine から各 Leaf / RR とのピアが Establ(Established) になっていれば OK です。最終的に Border Leaf (leaf3-1) から HV1 の Loopback まで疎通できます。

admin@leaf3-1# run ping 10.255.255.201 source 10.255.255.31 count 3
64 bytes from 10.255.255.201: icmp_seq=0 ttl=62 time=3.254 ms
...
3 packets transmitted, 3 packets received, 0% packet loss

✅ 完成状態チェックリスト

  • Spine から見て、全 Leaf / RR の eBGP セッションが Establ
  • show route 10.255.255.0/24 で全ノードの Loopback が学習されている
  • 任意の Leaf から任意の Leaf の Loopback へ ping が通る
  • HV1 の Loopback (10.255.255.201/32) が leaf3-1 から見える

ここまでで Underlay が完成し、全ノードの Loopback 同士が IP で疎通できる「下地」が整いました。次のセクションで、この上に EVPN/VXLAN の Overlay を被せます。


3. Overlay の構築 — EVPN/VXLAN

ここからが核心です。Underlay の上に EVPN(C-Plane) + VXLAN(D-Plane) を被せ、テナントの L2 セグメントを複数 Leaf 間で拡張します。

Q. なぜ VLAN ではダメなのか?

データセンターでは複数のテナント(利用者)が同じ物理スイッチを共有します。テナント同士のトラフィックを分離する最も基本的な手段が VLAN(Virtual LAN)です。しかし VLAN には以下の限界があります。

課題 VLAN の限界 EVPN/VXLAN での解決
ID 数 最大 4,094 個 → 大規模クラウドでは枯渇する VNI は最大約 1,600 万個(VNIについては後述)
L2 の拡張 VLAN をラック間に伸ばすにはループ対策(STP)が必要になり、構成が複雑化する VXLAN で L3(IP Underlay)上にトンネルを張るため、STP 不要で任意のラック間へ L2 を延伸可能
MAC 学習のスケーラビリティ データプレーンのフラッディングで MAC を学習するため、規模拡大に伴い帯域を圧迫する EVPN が制御プレーンで MAC/IP を配布するため、不要なフラッディングを抑制できる

つまり VLAN は「1 台のスイッチ内 or 隣接スイッチ間」の L2 分離VXLAN は「DC 全体規模」の L2 分離 と役割が違います。本記事で構築するのは後者です。

テナントごとに L3(ルーティング)も分離 したい場合は VRF(Virtual Routing and Forwarding)を使います。VRF はスイッチ / ルータの中に「テナント専用の経路表」を作る技術で、テナント A とテナント B が同じ 192.168.1.0/24 を使っていてもルーティングが混ざりません。本記事のセクション 4 で VRF を使った外部接続を構築します。

3.1 アーキテクチャの整理

各ノードが Overlay において担う役割を整理します。

役割 C-Plane D-Plane
Spine (単なる中継) (単なる IP 転送)
RR (rr1) iBGP RR、EVPN 経路反射
Underlay Leaf (leaf1-1) 参加しない 参加しない
Overlay Leaf (leaf2-1/2-2/3-1) iBGP/EVPN ピア VTEP(VXLAN トンネルの出入口)
HV1 (FRR) iBGP/EVPN ピア VTEP

Q. なぜ leaf1-1 は EVPN に参加しないのか?

HV1 が VTEP を持つので、leaf1-1 は単なる IP ルータとして VXLAN パケットを Underlay 越しに転送するだけで済みます。実環境でも同様で、HV 上のソフトウェア VTEP(Contrail vRouter 等)が VTEP の役割を担います。本記事ではそれを FRR で代用しています。

3.2 C-Plane: iBGP EVPN ピア

leaf2-1

configure
# RR との iBGP(Overlay)
set protocols bgp group OVERLAY type internal
set protocols bgp group OVERLAY local-address 10.255.255.21
set protocols bgp group OVERLAY neighbor 10.255.255.101
set protocols bgp group OVERLAY family evpn signaling

# EVPN/VXLAN 基本設定
set switch-options vtep-source-interface lo0.0
set switch-options route-distinguisher 10.255.255.21:1
set protocols evpn encapsulation vxlan
# IRB(L3 ゲートウェイ)を使わない宣言。Type-2 ルートに default-gateway コミュニティを付けない
set protocols evpn default-gateway no-gateway-community
set protocols evpn extended-vni-list all

# RT を明示指定。FRR の advertise-all-vni は AS:VNI 形式(65000:10010)で RT を生成するため、
# Junos 側も同じ値を使う(Junos の vrf-target auto は AS:(VNI+0x10000000) と計算式が異なり互換性がない)
set switch-options vrf-target target:65000:10010
commit

leaf2-2 / leaf3-1 のコマンドを開く

leaf2-2

configure
set protocols bgp group OVERLAY type internal
set protocols bgp group OVERLAY local-address 10.255.255.22
set protocols bgp group OVERLAY neighbor 10.255.255.101
set protocols bgp group OVERLAY family evpn signaling

set switch-options vtep-source-interface lo0.0
set switch-options route-distinguisher 10.255.255.22:1
set protocols evpn encapsulation vxlan
set protocols evpn default-gateway no-gateway-community
set protocols evpn extended-vni-list all
set switch-options vrf-target target:65000:10010
commit

leaf3-1

configure
set protocols bgp group OVERLAY type internal
set protocols bgp group OVERLAY local-address 10.255.255.31
set protocols bgp group OVERLAY neighbor 10.255.255.101
set protocols bgp group OVERLAY family evpn signaling

set switch-options vtep-source-interface lo0.0
set switch-options route-distinguisher 10.255.255.31:1
set protocols evpn encapsulation vxlan
set protocols evpn default-gateway no-gateway-community
set protocols evpn extended-vni-list all
set switch-options vrf-target target:65000:10010
commit

rr1

configure
set protocols bgp group OVERLAY type internal
set protocols bgp group OVERLAY cluster 10.255.255.101
set protocols bgp group OVERLAY local-address 10.255.255.101
set protocols bgp group OVERLAY neighbor 10.255.255.21
set protocols bgp group OVERLAY neighbor 10.255.255.22
set protocols bgp group OVERLAY neighbor 10.255.255.31
set protocols bgp group OVERLAY neighbor 10.255.255.201
set protocols bgp group OVERLAY family evpn signaling
commit

hv1(FRR)

vtysh
configure terminal

router bgp 65000
 bgp router-id 10.255.255.201
 no bgp ebgp-requires-policy

 neighbor 10.255.255.101 remote-as 65000
 neighbor 10.255.255.101 update-source 10.255.255.201

 address-family l2vpn evpn
  neighbor 10.255.255.101 activate
 exit-address-family
exit
end
write
exit

確認

admin@rr1# run show bgp summary group OVERLAY
...
10.255.255.21         65000   ...   Establ   bgp.evpn.0: 0/0/0/0
10.255.255.22         65000   ...   Establ   bgp.evpn.0: 0/0/0/0
10.255.255.31         65000   ...   Establ   bgp.evpn.0: 0/0/0/0
10.255.255.201        65000   ...   Establ   bgp.evpn.0: 0/0/0/0

全ピアが Establ(Established) になれば完成です。まだ VNI を作っていないので EVPN 経路は 0 件です。


3.3 D-Plane: VXLAN セグメントを作る

VNI 10010(VLAN 10)を用意し、VM1(HV1 上、192.168.10.10)BM1(leaf2-1 配下、192.168.10.101) が同じ L2(同一サブネット、つまり「同じ LAN」)で通信できるようにします。

Q. VNI とは?

VXLAN Network Identifier の略。VLAN ID の「拡張版」のようなもので、最大約 1,600 万のセグメントを作れます(VLAN は 4,094 まで)。

⚠️ 本番では MTU 設計が必須

VXLAN は外側に IP(20) + UDP(8) + VXLAN(8) + Inner Ethernet(14) = 50 バイトのオーバーヘッド が乗ります。テナントが MTU 1500 で通信したいなら、Underlay の物理 MTU を 9000(Jumbo Frame) にするのが定番です。

hv1:Linux Kernel + FRR

# VM 模擬の Network Namespace 作成
ip netns add vm1
ip link add veth-host type veth peer name veth-vm
ip link set veth-vm netns vm1
ip netns exec vm1 ip link set dev veth-vm address 02:00:00:00:01:10
ip netns exec vm1 ip addr add 192.168.10.10/24 dev veth-vm
ip netns exec vm1 ip link set veth-vm up
ip netns exec vm1 ip link set lo up

# VTEP(VXLAN I/F)作成
ip link add vxlan10 type vxlan id 10010 local 10.255.255.201 dstport 4789 nolearning

# Bridge 経由で VM 側と VXLAN を接続
ip link add br10 type bridge
ip link set veth-host master br10
ip link set vxlan10 master br10
ip link set vxlan10 up
ip link set veth-host up
ip link set br10 up
vtysh
configure terminal
router bgp 65000
 address-family l2vpn evpn
  advertise-all-vni
 exit-address-family
end
write
exit

leaf2-1

configure
set vlans v10 vlan-id 10
set vlans v10 vxlan vni 10010
set vlans v10 vxlan ingress-node-replication

# BM1 接続ポート
set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members v10
commit

Q. ingress-node-replication とは?

SDPF クラウドでは、お客さまに自由な L2 ネットワークを構成していただけるよう、Overlay ネットワークになるべく制限を与えない形でサービスを提供します。そのため、BUM(Broadcast / Unknown unicast / Multicast)トラフィックも通す必要があります。ingress-node-replication は、この BUM パケットをフラッドする際の方式を指定する設定です。これを有効にすると、Type-3(IM)ルートで学習した各リモート VTEP に対して ユニキャストで複製送信します。

bm1

ip link set eth1 up
ip link add link eth1 name eth1.10 type vlan id 10
ip link set eth1.10 up
ip addr add 192.168.10.101/24 dev eth1.10

動作確認

VM1 ↔ BM1 で ping が通り、HV1 で tcpdump を取ると UDP/4789 の VXLAN にカプセル化 されているのが分かります。

# BM1で実行
~ # ping 192.168.10.10
64 bytes from 192.168.10.10: icmp_seq=1 ttl=64 time=3.35 ms
...

# HV1で実行
~ # tcpdump -i eth1 -n -vv udp port 4789
tcpdump: listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
... IP (tos 0x0, ttl 253, id 21304, offset 0, flags [none], proto UDP (17), length 134)
    10.255.255.21.55534 > 10.255.255.201.4789: [no cksum] VXLAN, flags [I] (0x08), vni 10010
IP (tos 0x0, ttl 64, id 44875, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.10.101 > 192.168.10.10: ICMP echo request, id 102, seq 8, length 64
... IP (tos 0x0, ttl 64, id 21000, offset 0, flags [none], proto UDP (17), length 134)
    10.255.255.201.49139 > 10.255.255.21.4789: [udp sum ok] VXLAN, flags [I] (0x08), vni 10010
IP (tos 0x0, ttl 64, id 6907, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.10.10 > 192.168.10.101: ICMP echo reply, id 102, seq 8, length 64

leaf2-1 側でも EVPN Type-2(MAC/IP)と Type-3(IM)の経路がリモート VTEP 宛に学習されています。

admin@leaf2-1# run show route table bgp.evpn.0

bgp.evpn.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

2:10.255.255.21:1::10010::aa:c1:ab:0a:18:4a/304 MAC/IP
                   *[EVPN/170] 00:01:12
                       Indirect
2:10.255.255.201:2::0::02:00:00:00:01:10/304 MAC/IP
                   *[BGP/170] 00:03:21, localpref 100, from 10.255.255.101
                      AS path: I, validation-state: unverified
                       to 10.1.21.1 via ge-0/0/0.0
                    >  to 10.2.21.1 via ge-0/0/1.0
2:10.255.255.21:1::10010::aa:c1:ab:0a:18:4a::192.168.10.101/304 MAC/IP
                   *[EVPN/170] 00:01:05
                       Indirect
3:10.255.255.21:1::10010::10.255.255.21/248 IM
                   *[EVPN/170] 00:03:09
                       Indirect
3:10.255.255.201:2::0::10.255.255.201/248 IM
                   *[BGP/170] 00:03:10, localpref 100, from 10.255.255.101
                      AS path: I, validation-state: unverified
                    >  to 10.1.21.1 via ge-0/0/0.0
                       to 10.2.21.1 via ge-0/0/1.0

確認のポイントを整理します。

  • [EVPN/170] Indirect のエントリ(RD 10.255.255.21:1)は leaf2-1 自身がローカルで生成した EVPN 経路(自分のポートに接続された BM1 の MAC/IP、および自分が属する VNI の IM ルート)。
  • [BGP/170] from 10.255.255.101 のエントリ(RD 10.255.255.201:2)は RR(rr1)経由で受け取ったリモート VTEP(HV1)からの経路。to 10.1.21.1 / to 10.2.21.1 の 2 経路が並んでいるのは、spine1・spine2 の両方を経由した ECMP が有効になっているためです。
  • EVPN の経路情報は BGP によって制御プレーン上でやり取りされ、実際のパケット転送は VXLAN(UDP/4789)がデータプレーンとして担います。tcpdump で確認した通り、vni 10010 のカプセル化で転送されていることが確認できます。

3.4 EVPN Multihoming(ESI-LAG)で BM の接続を冗長化

セクション 3.3 で VXLAN の疎通は確認できましたが、このままでは BM1 が leaf2-1 の 1 本だけでぶら下がっている状態です。クラウドサービスでは物理故障の単一障害点を排除することが基本要件であり、リンクやスイッチの障害でサーバーが孤立しないよう、複数 Leaf へ冗長接続します。

ここからは BM1 を leaf2-1 / leaf2-2 の両方に接続して冗長化します。BM1 のネットワーク設定をいったん削除して bond に組み直すため、一時的に BM1 ↔ VM1 間の通信が途絶えます。

EVPN Type-1 / Type-4 を活かす ESI-LAG(All-Active) で構成します。

EVPN Multihoming の商用導入事例として、SDPF クラウド開発メンバーが JANOG48 で発表した EVPN Anycast Gateway を商用導入した話 も大変参考になります。

Q. ESI-LAG とは?

通常の LAG(Link Aggregation)は 1 台のスイッチへの束ねですが、ESI-LAG は 複数台のスイッチをまたいで LAG を組める技術です。サーバーから見ると 1 台のスイッチにつないでいるように見えます。

方針

  • 2 台の Leaf で 同じ ESI同じ LACP System ID を設定 → BM1 から見ると単一の LAG 相手に見える
  • BM1 側は Linux bond(mode=802.3ad)

leaf2-1(既存設定の置き換え)

configure
delete interfaces ge-0/0/2 unit 0
set chassis aggregated-devices ethernet device-count 1
set interfaces ge-0/0/2 ether-options 802.3ad ae0

set interfaces ae0 unit 0 family ethernet-switching interface-mode trunk
set interfaces ae0 unit 0 family ethernet-switching vlan members v10

# ESI(leaf2-1/2-2 で完全一致させる)
set interfaces ae0 esi 00:00:00:00:00:00:00:00:00:01
set interfaces ae0 esi all-active

set interfaces ae0 aggregated-ether-options lacp active
set interfaces ae0 aggregated-ether-options lacp periodic fast
set interfaces ae0 aggregated-ether-options lacp system-id 00:00:00:00:00:01
commit

leaf2-2(新規)

leaf2-1 と完全に同じ ESI / LACP System ID を投入します。VLAN/VNI/RT もここで作成。

configure
set vlans v10 vlan-id 10
set vlans v10 vxlan vni 10010
set vlans v10 vxlan ingress-node-replication

set chassis aggregated-devices ethernet device-count 1
set interfaces ge-0/0/2 ether-options 802.3ad ae0

set interfaces ae0 unit 0 family ethernet-switching interface-mode trunk
set interfaces ae0 unit 0 family ethernet-switching vlan members v10

set interfaces ae0 esi 00:00:00:00:00:00:00:00:00:01
set interfaces ae0 esi all-active

set interfaces ae0 aggregated-ether-options lacp active
set interfaces ae0 aggregated-ether-options lacp periodic fast
set interfaces ae0 aggregated-ether-options lacp system-id 00:00:00:00:00:01
commit

bm1(Linux Bond)

ip addr flush dev eth1.10
ip link del eth1.10

ip link add bond0 type bond mode 802.3ad miimon 100 lacp_rate 1 xmit_hash_policy layer3+4

ip link set eth1 down
ip link set eth2 down
ip link set eth1 master bond0
ip link set eth2 master bond0
ip link set bond0 up
ip link set eth1 up
ip link set eth2 up

ip link add link bond0 name bond0.10 type vlan id 10
ip link set bond0.10 up
ip addr add 192.168.10.101/24 dev bond0.10

切断試験

BM1 から VM1 に ping を流したまま、leaf2-1 → leaf2-2 の順にリンクを落とすと、片方が生きている間は ping が継続することを確認できます。

# leaf2-1 で接続断 → ping 継続
configure
set interfaces ge-0/0/2 disable
commit

# leaf2-2 でも接続断 → ping 停止
configure
set interfaces ge-0/0/2 disable
commit

# leaf2-1 を復活 → ping 復活
configure
delete interfaces ge-0/0/2 disable
commit

# leaf2-2 で実行
configure
delete interfaces ge-0/0/2 disable
commit

HV1 から見ると、BM1 の bond0 MAC が leaf2-1 / leaf2-2 の両方から同じ ESI で広告されています。

~ # vtysh -c "show bgp l2vpn evpn"
Route Distinguisher: 10.255.255.21:1
*>i [2]:[10010]:[48]:[xx:xx:xx:xx:xx:xx]   ← bond0 の MAC
    10.255.255.21    ESI:00:00:00:00:00:00:00:00:00:01  RT:65000:10010
Route Distinguisher: 10.255.255.22:1
*>i [2]:[10010]:[48]:[xx:xx:xx:xx:xx:xx]
    10.255.255.22    ESI:00:00:00:00:00:00:00:00:00:01  RT:65000:10010

💡 bond0 の MAC はカーネルが自動付与します(通常 eth1 の MAC を継承)。実際の値は ip link show bond0 で確認してください。

ESI が両ノードで一致しているため、HV1 はこの 2 経路を Aliasing(ECMP 的にロードバランス)して扱います。つまり、「leaf2-1 および leaf2-2 のいずれを経由しても、BM1 に届く」状態が完成しています。これが ESI-LAG の本質です。

✅ 完成状態チェックリスト(Overlay全体)

  • RR の OVERLAY グループで全 Leaf / HV1 が Establ
  • HV1 で show evpn vni に VNI 10010 が表示される
  • BM1 → VM1(VXLAN 経由)の ping が通る
  • HV1 の tcpdump -i eth1 udp port 4789 で VXLAN ヘッダ(vni 10010)が見える
  • leaf2-1/2-2 のどちらかのリンクを落としても BM1 → VM1 の通信が継続する
  • show bgp l2vpn evpn で BM1 の MAC が leaf2-1/2-2 の両方から同じ ESI で広告されている

ここまでで、EVPN/VXLAN によるテナント L2 拡張と ESI-LAG による冗長接続が完成しました。VM1(HV1 上)と BM1 が物理的に離れていても同一 L2 で通信でき、かつ片方のリンクが落ちても通信が継続する状態です。


4. Border Leaf と Internet Gateway

最後に、テナント網(VRF = 仮想ルーティングテーブル、「テナント専用の経路表」と考えてOK)と外部網(Global = インターネット側)を接続します。

  • leaf3-1 を VTEP 化して Overlay の VLAN10 を Internet GW まで延伸
  • inet-gw1 で VRF-User と Global を Route Leaking
  • inet-gw1 ↔ isp1 で eBGP、isp1 から default route を受け取る

以下の内容を構成します。

4.1 leaf3-1(Border Leaf として VTEP 化)

configure
set vlans v10 vlan-id 10
set vlans v10 vxlan vni 10010
set vlans v10 vxlan ingress-node-replication

# inet-gw1 接続ポート
set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members v10
commit

4.2 inet-gw1: 共通の下準備(I/F + ASN)

configure
set routing-options router-id 198.51.100.1
set routing-options autonomous-system 65002

# I/F
set interfaces ge-0/0/0 vlan-tagging
set interfaces ge-0/0/0 unit 10 vlan-id 10
set interfaces ge-0/0/0 unit 10 family inet address 192.168.10.1/24
set interfaces ge-0/0/1 unit 0 family inet address 203.0.113.2/30
set interfaces lo0 unit 0 family inet address 198.51.100.1/32
commit

ge-0/0/0.10 がテナント側(leaf3-1 経由で BM1 と同セグ)、ge-0/0/1.0 が インターネット側(外部)です。

4.3 inet-gw1: VRF と Route Leaking

ユーザーの VRF(VRF-User)と Global テーブル(inet.0 = Junos の通常の経路表)を分離しつつ、必要な経路だけ相互にリーク(漏らす)します。これが「Route Leaking」で、「テナント内部の経路をインターネット側に教える(またはその逆)」ことで、テナント内のサーバーがインターネットと通信できるようになります。

configure

# Route Leaking ポリシー(双方向)
# Global -> VRF: default route のみ VRF に流す
set policy-options policy-statement LEAK-GLOBAL-TO-VRF term ALLOW-DEFAULT from instance master
set policy-options policy-statement LEAK-GLOBAL-TO-VRF term ALLOW-DEFAULT from route-filter 0.0.0.0/0 exact
set policy-options policy-statement LEAK-GLOBAL-TO-VRF term ALLOW-DEFAULT then accept
set policy-options policy-statement LEAK-GLOBAL-TO-VRF term DENY-REST then reject
# VRF -> Global: BM1 の Global IP(/32)のみ Global へ流す
set policy-options policy-statement LEAK-VRF-TO-GLOBAL term ALLOW-BM1 from instance VRF-User
set policy-options policy-statement LEAK-VRF-TO-GLOBAL term ALLOW-BM1 from route-filter 198.51.100.41/32 exact
set policy-options policy-statement LEAK-VRF-TO-GLOBAL term ALLOW-BM1 then accept
set policy-options policy-statement LEAK-VRF-TO-GLOBAL term DENY-REST then reject

# VRF 本体
set routing-instances VRF-User instance-type virtual-router
set routing-instances VRF-User interface ge-0/0/0.10
set routing-instances VRF-User routing-options instance-import LEAK-GLOBAL-TO-VRF
# BM1 の Global IP への static
set routing-instances VRF-User routing-options static route 198.51.100.41/32 next-hop 192.168.10.101

# Global 側にも VRF からの経路を取り込む
set routing-options instance-import LEAK-VRF-TO-GLOBAL
commit

4.4 inet-gw1: 外部 ISP との eBGP

最後に、上で Global にリークした経路を eBGP で 外部 ISP へ広告します。

configure
# 外部 ISP へ広告するポリシー(static のみ → 198.51.100.41/32 が乗る)
set policy-options policy-statement ADVERTISE-TO-ISP term 1 from protocol static
set policy-options policy-statement ADVERTISE-TO-ISP term 1 then accept

set protocols bgp group TO-ISP type external
set protocols bgp group TO-ISP peer-as 65001
set protocols bgp group TO-ISP neighbor 203.0.113.1
set protocols bgp group TO-ISP export ADVERTISE-TO-ISP
commit

4.5 isp1 (外部 ISP 模擬)

configure
set routing-options router-id 192.0.2.1
set routing-options autonomous-system 65001

set interfaces ge-0/0/0 unit 0 family inet address 203.0.113.1/30
set interfaces lo0 unit 0 family inet address 192.0.2.1/32

set protocols bgp group TO-GW type external
set protocols bgp group TO-GW peer-as 65002
set protocols bgp group TO-GW neighbor 203.0.113.2

set policy-options policy-statement SEND-DEFAULT term 1 from protocol static
set policy-options policy-statement SEND-DEFAULT term 1 from route-filter 0.0.0.0/0 exact
set policy-options policy-statement SEND-DEFAULT term 1 then accept
set protocols bgp group TO-GW export SEND-DEFAULT

set routing-options static route 0.0.0.0/0 discard
commit

4.6 bm1 (Global IP 付与とデフォルトゲートウェイ)

ip addr add 198.51.100.41/32 dev bond0.10
ip route replace default via 192.168.10.1

Q. なぜ /32 で付与するのか

BM1 が「自分は 198.51.100.41 である」とさえ名乗れれば十分です。戻りパケットのルーティングは inet-gw1 の VRF 内に 198.51.100.41/32 next-hop 192.168.10.101 の static route があるため、ISP → inet-gw1 → (VRF) → leaf3-1 → VXLAN → leaf2-1/2-2 → BM1 と正しく転送されます。

4.7 動作確認

inet-gw1 で Global の inet.0 にも 198.51.100.41/32 が現れます(= VRF からのリーク成功)。

admin@inet-gw1# run show route 198.51.100.41
inet.0:        198.51.100.41/32  *[Static/5]  > to 192.168.10.101 via ge-0/0/0.10
VRF-User.inet.0: 198.51.100.41/32  *[Static/5]  > to 192.168.10.101 via ge-0/0/0.10

そして BM1 → 外部 ISP(192.0.2.1)への ping、および逆方向の 外部 ISP → BM1(198.51.100.41)への ping がともに通れば、End-to-End の経路が完成です。

~ # ping -c 3 -I 198.51.100.41 192.0.2.1
64 bytes from 192.0.2.1: icmp_seq=1 ttl=63 time=5.87 ms
...
3 packets transmitted, 3 received, 0% packet loss

admin@isp1# run ping 198.51.100.41 count 3
64 bytes from 198.51.100.41: icmp_seq=0 ttl=63 time=6.070 ms
...
3 packets transmitted, 3 packets received, 0% packet loss

✅ 完成状態チェックリスト(Border GW)

  • inet-gw1 の inet.0VRF-User.inet.0 の両方に 198.51.100.41/32 が存在
  • inet-gw1 ↔ isp1 の eBGP が Establ、isp1 から default route を受信
  • BM1 → 192.0.2.1 (外部 ISP) の ping が通る(-I 198.51.100.41 で source 指定)
  • 外部 ISP → 198.51.100.41 (BM1) の ping が通る

ここまでで、テナント内の BM1 が VRF Route Leaking を経由して外部 ISP と双方向に通信できる End-to-End の経路が完成しました。本記事で目標としていた全構成の構築が完了です。


全体の完成確認

全セクションを通して構築した結果、冒頭で掲げたゴール — 物理的に離れた HV1 上の VM と BM1 が同一 L2 で通信でき、さらにインターネットへ抜けられる — が達成できています。完成した NW で実現できていることを整理します。

通信パス 経由するレイヤ
VM1(HV1)↔ BM1 HV1 (VTEP) → VXLAN → Underlay (Spine経由) → leaf2-1/2-2 (VTEP) → BM1
BM1 → インターネット BM1 → leaf2-1/2-2 → VXLAN → leaf3-1 → inet-gw1 (VRF Route Leaking) → isp1
インターネット → BM1 isp1 → inet-gw1 (Global→VRF) → leaf3-1 → VXLAN → leaf2-1/2-2 → BM1
  • Underlay:eBGP + ECMP により、どちらの Spine を経由しても全ノードの Loopback が到達可能
  • Overlay:EVPN/VXLAN により、異なるラックの VM1 と BM1 が同一 L2(VNI 10010)で通信
  • 冗長化:ESI-LAG により、leaf2-1 または leaf2-2 のどちらか一方が故障しても BM1 の通信が継続
  • 外部接続:VRF Route Leaking により、テナント内部の経路とインターネット側の経路を相互にリークし、BM1 が外部と双方向に通信可能

これらが組み合わさることで、クラウド NW の基本構成 — マルチテナント対応の L2 延伸・物理冗長・外部接続 — が 1 つのラボ上で再現できています。


おまけ: ハマったら見るところ(Troubleshooting)

手順通りやってもうまくいかないとき、上から順に切り分けると早いです。

症状 確認ポイント
BGP が Active から進まない 直結 ping → Loopback 間 ping → peer-as の値 → ポリシーで自分の経路を絞ってないか
Underlay は OK だが Overlay iBGP が Active Loopback 間の ping、local-address が自分の Loopback になっているか
EVPN ピアは張れたが経路が来ない 両端の RT が一致しているか、extended-vni-list の VNI 範囲
ESI-LAG で片側だけしか流れない 2 台の esilacp system-id完全に一致しているか

Junos 側で何が起きているか覗くコマンド

run show bgp summary
run show route table bgp.evpn.0
run show route advertising-protocol bgp <neighbor>
run show route receive-protocol bgp <neighbor>
run show ethernet-switching vxlan-tunnel-end-point remote
run show evpn database

FRR 側

vtysh -c "show bgp l2vpn evpn summary"
vtysh -c "show evpn vni"
vtysh -c "show evpn mac vni all"

まとめ

Containerlab + vJunos でクラウド NW の王道構成を一通り体験しました。しかし、本記事はあくまで学習用であり、実際の運用では次のような事項も検討が必要です。

  • IRB / Anycast Gateway(各 Leaf に同じ GW IP を持たせる分散 L3 ルーティング)
  • MTU 設計(Underlay 9000 / テナント 1500)
  • BGP 認証(MD5)
  • マルチテナント運用(VNI 数千規模の管理)
  • セキュリティポリシー(マイクロセグメンテーション、ACL)
  • 監視連携

本記事を通じてクラウド NW を少しでも知っていただき、「面白い!」と思っていただけましたら幸いです。

クラウド NW 開発に興味を持っていただけた学生の方は、ぜひインターンのポスト「【B19】エンタープライズ向け大規模クラウド/ネットワークサービスを支えるコントローラ開発」や「【B25】エンタープライズ向け大規模クラウドサービスを支える仮想ネットワークソフトウェア開発」にご応募ください。