2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MシリーズMacでネットワーク検証環境を作る【OrbStack + containerlab】

2
Last updated at Posted at 2026-07-27

はじめに

ネットワークの勉強で「ルータを2台つないで経路を入れてみる」をやりたくても、実機を並べるのは手間もお金もかかります。containerlab なら、ルータとその配線を YAML に書いて deploy するだけで済みます。

ただし、Apple Silicon Mac(M シリーズ)でやろうとすると、つまずくところが2つあります。

1つめは、containerlab が Linux でしか動かないことです。macOS は Linux ではないので、Mac の中に小さな Linux を1つ用意して、その上で containerlab を動かします。

2つめは、ルータ役のソフトを詰めた「イメージ」が、Intel チップ向けにしか用意されていない場合が多いことです。Apple Silicon は Intel とは別系統のチップなので、Intel 向けのものを動かすと変換をはさんだ動作(Rosetta)になり、遅くなったり不具合が出たりします。今回使う FRR の公式イメージもこれに当たります。

この記事のゴールは、この2つを乗り越えて、ルータ役のコンテナ2台(r1, r2)をつなぎ、通信の道順を手で教える「静的ルーティング」を設定して、互いに ping が通る状態にすることです。ルータの経路表に、手で入れた道順が現れれば成功です。

r1# show ip route
S>* 192.168.2.0/24 [1/0] via 10.0.0.2, eth1, weight 1, 00:00:00

対象読者

  • Apple Silicon Mac でネットワーク検証環境を作りたい人
  • containerlab を触ってみたいが macOS での始め方が分からない人
  • Docker の基本操作(docker ps / docker exec)が分かる人

最終構成

1. containerlab とは

何をしてくれるツールなのか

containerlab は、コンテナ化されたネットワーク OS でラボのトポロジーを組むための CLI ツールです。公式ドキュメントは次のように説明しています。

a CLI for orchestrating and managing container-based networking labs. It starts the containers, builds a virtual wiring between them to create lab topologies of users choice and manages labs lifecycle.

出典:containerlab トップページ

やってくれることは3つです。コンテナを起動し、コンテナのあいだに仮想的な配線(virtual wiring)を張り、ラボの作成から破棄までを管理します。

背景にあるのは、ネットワーク OS のコンテナ化が進んだことです。

With the growing number of containerized Network Operating Systems grows the demand to run them in user-defined lab topologies.

出典:containerlab トップページ

Nokia SR Linux、Cisco XRd や Nexus 9000v、Juniper cRPD や vSRX、Arista、SONiC、VyOS、そして本記事で使う FRR など、幅広いネットワーク OS に対応しています。

なぜ docker compose ではダメなのか

コンテナを複数立ち上げるだけなら docker compose でもよさそうに思えますが、公式ドキュメントはこの点を明確に否定しています。

Container orchestration tools like docker-compose are not a good fit for this purpose, as they do not allow a user to easily create connections between the containers which define a topology.

出典:containerlab · Topology wiring

ネットワークのラボで欲しいのは、コンテナを並べることではなく、コンテナのあいだを結線することです。「r1 の eth1 と r2 の eth1 を1本のケーブルでつなぐ」という、実機ならLANケーブルを挿す作業に相当する部分がそれに当たります。docker compose は複数のコンテナを同じネットワークに参加させられますが、ノード間を任意の形につなぐようには作られていません。この部分を引き受けるのが containerlab です。

トポロジー定義ファイル

containerlab はラボの構成を トポロジー定義ファイル(*.clab.yml)から組み立てます。

Containerlab builds labs based on the topology information that users pass to it. This topology information is expressed as a code contained in the topology definition file.

出典:containerlab · Topology definition

書く内容は3つで、本記事で実際に書くのもこの3つだけです。

要素 役割 公式ドキュメントの説明(要約)
name ラボの名前 1つのトポロジーを他と区別する名前。同じホスト上に複数のラボを衝突なく展開できるようにするために使う
nodes 動かすノードの定義 どのラボ要素を、どんな設定・種類で動かすかを定義する
links ノード間の結線 ノード同士を相互接続する。簡易形式と拡張形式がある

出典:containerlab · Topology definition(name / nodes / links の各項)

ノードには kind を指定します。これはそのノードが何者かを表すもので、公式ドキュメントの定義はこうなっています。

Kinds define the behavior and the nature of a node, it says if the node is a specific containerized Network OS, virtualized router or something else.

出典:containerlab · Topology definition(Kinds)

Nokia SR Linux 専用の kind などが用意されている一方、FRR のような汎用の Linux コンテナには kind: linux を使います。本記事もこれを使います。

つまりこの記事でやることは、突き詰めればルータ2台とその配線を YAML に書いて containerlab deploy するだけです。トポロジーの実体がテキストファイル1枚なので、コピーして書き換えれば別構成のラボをすぐ作れます。

2. なぜ macOS では Linux VM が必要なのか

Docker Desktop や OrbStack が入っていれば Linux コンテナは動くのだから containerlab もそのまま動きそうに見えますが、動きません。理由は、containerlab がコンテナを動かすだけのツールではなく、コンテナ間にネットワークを張るツールだからです。

containerlab 公式の macOS ガイド にこう書かれています。

We leverage some Linux kernel APIs (like netlink) either directly or via Docker to be available to setup links, namespaces, bind-mounts, etc.

Darwin (macOS kernel) is not Linux, and while it is POSIX compliant, it is not a drop-in replacement for Linux.

出典:containerlab · macOS

containerlab がやっている「コンテナ同士をケーブルでつなぐ」作業は、Linux カーネルにしかない機能を直接呼び出して実現しています。具体的には、コンテナごとに区切られた仮想的なネットワーク空間(netns)や、コンテナ同士をつなぐ仮想的なケーブル(veth)を作る機能です。これらは Linux 固有のものなので、問われるのはコンテナが Linux で動くかどうかではなく、containerlab 自身が Linux の上で動いているかどうかになります。

このことは配布物にも表れています。v0.77.0 のリリースページを見ると、deb / rpm / apk / tar.gz などのアセットが並びますが、すべて linux_amd64linux_arm64 向けで、macOS 向けのバイナリはありません。

そのため macOS では、Linux 環境を1つ用意してそこに containerlab を入れることになります。公式ガイドはその方法として、Linux VM を立てる方法と devcontainer で動かす方法を挙げています。本記事は前者を採ります。

3. なぜ OrbStack なのか

公式ガイドは macOS 用の選択肢として Docker Desktop、Rancher Desktop、Container Desktop、CoLima、OrbStack を挙げていますが、★が付いて推奨されているのは OrbStack だけです。

⭐ OrbStack - a great UX and performance. A choice of many and is recommended by Containerlab maintainer. Free for personal use.

出典:containerlab · macOS(Software)

個人利用は無料です。今回 OrbStack を選ぶ理由は2つあります。

1つは、Linux Machines 機能があることです。OrbStack は Docker ランタイムだけでなく、軽量な Linux VM を立てる機能を持っています。orb create ubuntu clab の1コマンドで Ubuntu VM が手に入り、その中に containerlab を入れられます。これが2章の要件を満たします。

もう1つは、macOS のホームディレクトリを共有してくれることです。OrbStack は macOS の /Users を VM 内に共有マウントするので、設定ファイルは Mac 側のエディタで編集し、deploy は VM 内で実行するという分担ができます。ルータの設定を何度も書き換える検証作業では、この分担が効きます。

共有まわりで最初に混乱するところです。VM 内の ~ は Mac のホームではありません。

  • VM 内の ~ = /home/<ユーザー名> … VM ネイティブのディスク。Mac からは見えない
  • VM 内の /Users/<ユーザー名> = Mac のホームと同じ場所

Mac と共有したいファイルは /Users/... 側に置きます。本記事もそちらに置きます。

4. OrbStack と Ubuntu VM を用意する

まず macOS 側で OrbStack を入れます(手順の詳細は公式のインストールガイドを参照)。

brew install orbstack
open -a OrbStack

clab という名前で Ubuntu VM を作ります。

orb create ubuntu clab   # VM を作成
orb list                 # 一覧を確認
orb -m clab              # VM に入る

orb list の出力例です。ヘッダー行は出ません。

clab  running  ubuntu  resolute  arm64  2.6 GB  192.168.139.160

左から順に「名前 / 状態 / ディストリ / バージョン / アーキテクチャ / ディスク使用量 / IP」です。5列目が arm64 になっていることを確認しておきます。Apple Silicon なので VM は ARM64 で、その上で動かすコンテナも ARM64 がネイティブになります。この点は7章で効いてきます。

orb -m clab で VM に入ると、Mac 側で cd していたディレクトリにそのまま着地します(固定のホームに入るのではありません)。たとえば Mac 側で ~/Documents にいる状態で orb -m clab すると、VM 内の pwd も /Users/<ユーザー名>/Documents になります。混乱を避けるため、本記事では VM 内では絶対パスで cd します。

以降、断りがなければ VM 内での作業です。

5. VM 内に Docker と containerlab を入れる

Docker

sudo apt update
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker

この直後に docker ps を叩くと、まず権限エラーになります。

permission denied while trying to connect to the docker API at unix:///var/run/docker.sock

自分を docker グループに入れます。

sudo usermod -aG docker $USER

多くの Docker 導入手順は、この後に newgrp docker で現在のシェルにグループを反映させろと書いてあります。しかし OrbStack の Ubuntu VM は最小構成で、その newgrp が入っていません。

$ newgrp docker
newgrp: command not found

今のシェルにグループ追加を反映する手段がないので、VM を一度出て入り直し、ログインシェルを作り直します。

exit
orb -m clab
docker ps        # 通るようになる

containerlab

公式のインストールスクリプトを使います。

bash -c "$(curl -sL https://get.containerlab.dev)"
containerlab version

インストール中に「sudo usermod -aG clab_admins ... を実行してください」というメッセージが出ますが、標準の手順では自動で対応済みなので、そのまま進めてかまいません(理由は12章)。

6. 作業ディレクトリを用意する

Mac 側と共有される /Users 配下にラボ用のディレクトリを作ります。

# VM 内
mkdir -p /Users/$USER/clab/frr-lab      # イメージのビルド用
mkdir -p /Users/$USER/clab/static-lab   # 今回のラボ用

Mac 側から見ると ~/clab/frr-lab~/clab/static-lab に当たるので、設定ファイルは Mac のエディタで開けます。

7. FRR イメージを ARM64 ネイティブで用意する

公式 FRR イメージのアーキテクチャ

ルータには FRRouting(FRR) を使います。素直に考えれば公式イメージ frrouting/frr:latest を使いたくなりますし、Apple Silicon でも一見動きます。しかしアーキテクチャを確認するとこうなります。

docker pull frrouting/frr:latest
docker image inspect frrouting/frr:latest --format '{{.Architecture}}'
amd64

ARM64 の VM 上で amd64 イメージが動いているので、Rosetta によるエミュレーション動作です。一見動くので気付きにくいのですが、エミュレーションは実害を出します。筆者の場合、docker exec がハングする症状に悩まされ、原因の切り分けにかなり時間を使いました。

公式ガイドもネイティブを推しています。

You should strive to run the native images as much as possible, as it gives you the best performance and compatibility.

出典:containerlab · macOS(How Docker runs on Macs)

Rosetta も選択肢として挙げられてはいますが、ARM64 版が存在しない場合の代替という位置づけです。

If the image you're looking for is not available in ARM64, you can still try running the AMD64 version of the image under Rosetta emulation.

出典:containerlab · macOS(Running under Rosetta)

FRR 本体と Docker イメージの区別

ここで区別しておきたいのは、FRR というソフトウェアが amd64 専用なのではなく、frrouting/frr という Docker イメージに amd64 ビルドしか無いだけだという点です。FRR 自体は ARM64 で普通に動き、Ubuntu も arm64 版の frr パッケージを配布しています。

ということは、Ubuntu ベースで自分でイメージを焼けば ARM64 ネイティブになります。

frr-lab イメージをビルドする

cd /Users/$USER/clab/frr-lab

cat <<'EOF' > Dockerfile
FROM ubuntu:24.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
    frr iputils-ping && \
    rm -rf /var/lib/apt/lists/*
CMD ["sleep", "infinity"]
EOF

docker build -t frr-lab:latest .

入れているのは2つだけです。frr が本体で、iputils-ping は疎通確認の ping 用です。ip コマンドを提供する iproute2frr の依存パッケージなので、明示しなくても入ります。

docker run --rm frr-lab:latest bash -c 'command -v ip; command -v ping'
/usr/sbin/ip
/usr/bin/ping

ARM64 になったことを確認します。

docker image inspect frr-lab:latest --format '{{.Architecture}}'
arm64

インストールされた FRR のバージョンも見ておきます。

docker run --rm frr-lab:latest dpkg -l frr | tail -1
ii  frr            8.4.4-1.1ubuntu6.7 arm64        FRRouting suite of internet protocols (BGP, OSPF, IS-IS, ...)

arm64 パッケージの FRR 8.4.4 が入りました。自前ビルドにしたことで、アーキテクチャ以外にも差が出ています。

frrouting/frr:latest frr-lab(自前ビルド)
アーキテクチャ amd64(Rosetta動作) arm64 ネイティブ
ベース Alpine Ubuntu
追加ツール 後から入れるには apk が要る Dockerfile に1語足すだけ
FRR の起動 entrypoint が自動起動 exec: で明示起動が必要

「追加ツール」の行は、たとえばパケットを見たくなったときに効きます。Dockerfile の frr iputils-ping の後ろに tcpdump を足して焼き直せば済みます。本記事は静的ルーティングしか扱わないので入れていません。

最後の行が運用上の差分になります。自前イメージは CMD ["sleep", "infinity"] で起きているだけなので、FRR は containerlab 側から明示的に起動する必要があります。次章の clab.yml に反映します。

なお、変わったのはイメージとその起動方法だけで、中身の FRR は同じソフトウェアです。設定ファイルや vtysh の使い方は公式イメージのときと同じまま流用できます。

8. FRR の仕組み(daemonsvtysh)

設定ファイルを書く前に、この後出てくる daemonsservice integrated-vtysh-config が何なのかを見ておきます。

FRR は複数デーモンの集合体

Cisco IOS は単一の OS ですが、FRR は機能ごとに別プロセス(デーモン)へ分かれています。Unix 流の設計です。

デーモン 役割
zebra 全体のとりまとめ役。カーネルのルーティングテーブルを実際に書き換える中核
staticd 静的ルート担当
ospfd OSPF を喋る担当
bgpd BGP を喋る担当

daemons ファイルの yesno は、このデーモンを起動するかどうかのスイッチです。今回は静的ルーティングだけなので zebrastaticdyesospfd などは no にします。

vtysh という統合CLI

プロセスが分かれていると、設定や確認のたびに各プロセスへ個別に話しかけることになり面倒です。そこで vtysh(VTY shell)という、全デーモンをまとめて操作する統合 CLI が用意されています。

docker exec -it clab-static-lab-r1 vtysh

これで出てくる r1# プロンプトが vtysh で、IOS 風の統合画面です。show ip route と打つと、vtysh が裏で適切なデーモンに問い合わせて結果を返します。操作する側はプロセス分割を意識せず、1つの CLI として触れます。

daemonsvtysh_enable=yes は、この vtysh を使えるようにするスイッチで、実質必須です。

設定ファイルを1個に集約する

FRR の設定ファイルの持ち方は2通りあります。

方式 実体
(A) 分割方式(デフォルト) zebra.conf / staticd.conf / ospfd.conf … とデーモンごとに分ける
(B) 統合方式(本記事で採用) frr.conf 1個に全デーモン分をまとめる

frr.conf の冒頭に書く service integrated-vtysh-config が、(B) でいくという宣言です。これがあるので staticd.conf などを個別に作らず、frr.conf 1個に interfaceip route もまとめて書けます。

9. ラボのファイルを作る

/Users/$USER/clab/static-lab の中に、次の構成を作ります。

static-lab/
├── router1/
│   ├── daemons
│   └── frr.conf
├── router2/
│   ├── daemons
│   └── frr.conf
└── static.clab.yml
cd /Users/$USER/clab/static-lab
mkdir -p router1 router2

router1router2 は、それぞれのコンテナの /etc/frr に bind mount します。

9.1 daemons(起動するデーモンの指定)

静的ルーティングなので zebrastaticd だけを yes にし、残りはすべて no にします。

cat <<'EOF' > router1/daemons
zebra=yes
bgpd=no
ospfd=no
ospf6d=no
ripd=no
ripngd=no
isisd=no
pimd=no
ldpd=no
nhrpd=no
eigrpd=no
babeld=no
sharpd=no
staticd=yes
pbrd=no
bfdd=no
fabricd=no

vtysh_enable=yes
zebra_options="  -A 127.0.0.1 -s 90000000"
staticd_options=" -A 127.0.0.1"
EOF

cp router1/daemons router2/daemons

2台とも同じ内容なのでコピーで済みます。

9.2 frr.conf(インターフェースと静的経路)

各ルータに、対向の LAN 向けの静的経路を1本入れます。今回は LAN の代わりにループバックアドレスを使います。

静的ルーティングを試すには、相手側にしか無いネットワークが要ります。r1 と r2 は 10.0.0.0/30 で直結しているので、この区間だけなら経路を教えなくても届いてしまうためです。そこで各ルータに、自分だけが持つネットワークを1つずつぶら下げます。

PC 役のコンテナを2台足しても同じことはできますが、ノードが増えるぶん構成が読みにくくなります。ループバックインターフェースに /24 を付ければ、frr.conf に2行足すだけで済みます。ループバックは物理リンクの状態に依存せず常に up なので、リンク障害の話と経路の話が混ざらない利点もあります。

このあと 192.168.2.1 へ ping しますが、これは r2 のループバックアドレスであって、その先に PC がいるわけではありません。

r1 には、192.168.2.0/2410.0.0.2(= r2)へ、と書きます。

cat <<'EOF' > router1/frr.conf
frr version 8.4.4
frr defaults traditional
hostname r1
no ipv6 forwarding
service integrated-vtysh-config
!
interface eth1
 ip address 10.0.0.1/30
!
interface lo
 ip address 192.168.1.1/24
!
ip route 192.168.2.0/24 10.0.0.2
!
end
EOF

r2 には、192.168.1.0/2410.0.0.1(= r1)へ、と書きます。

cat <<'EOF' > router2/frr.conf
frr version 8.4.4
frr defaults traditional
hostname r2
no ipv6 forwarding
service integrated-vtysh-config
!
interface eth1
 ip address 10.0.0.2/30
!
interface lo
 ip address 192.168.2.1/24
!
ip route 192.168.1.0/24 10.0.0.1
!
end
EOF

手動ルーティングの本体は ip route <宛先ネットワーク> <ネクストホップ> の1行です。「この宛先に行きたければ隣のこの IP に渡せ」を人間が直接教えています。

9.3 static.clab.yml(トポロジー定義)

1章で説明した name / nodes / links を実際に書きます。これがラボ全体の設計図になります。

cat <<'EOF' > static.clab.yml
name: static-lab

topology:
  nodes:
    r1:
      kind: linux
      image: frr-lab:latest
      binds:
        - router1:/etc/frr
      exec:
        - chown -R frr:frr /etc/frr
        - /usr/lib/frr/frrinit.sh start
    r2:
      kind: linux
      image: frr-lab:latest
      binds:
        - router2:/etc/frr
      exec:
        - chown -R frr:frr /etc/frr
        - /usr/lib/frr/frrinit.sh start

  links:
    - endpoints:
        - r1:eth1
        - r2:eth1
EOF

各キーの意味は次のとおりです。

キー 意味
name ラボ名。コンテナ名は clab-<name>-<node> になる(今回は clab-static-lab-r1)
kind: linux 汎用 Linux コンテナとして起動する。FRR はこれを使う
image 7章でビルドした ARM64 ネイティブの frr-lab:latest
binds ホスト側 router1 ディレクトリをコンテナの /etc/frr にマウント
exec FRR を明示的に起動する。自前イメージは自動起動しないので必須
links.endpoints r1 と r2 の eth1 の間に veth リンクを張る

exec の2行はそれぞれこういう意味です。

  • chown -R frr:frr /etc/frr … bind mount してきたホスト側のファイルは root 所有なので、FRR の実行ユーザーが読み書きできるように所有者を変える(統合方式では vtysh が frr.conf に書き戻すため書き込み権も要る)
  • /usr/lib/frr/frrinit.sh start … Ubuntu の frr パッケージ同梱の起動スクリプトで FRR を起動する

eth0 は containerlab が管理ネットワーク(172.20.20.x)用に自動で付けます。links で作られるのは eth1 以降のデータ用インターフェースです。

10. deploy して確認する

containerlab deploy -t static.clab.yml
17:41:18 INFO Containerlab started version=0.77.0
17:41:18 INFO Parsing & checking topology file=static.clab.yml
17:41:18 INFO Creating docker network name=clab IPv4 subnet=172.20.20.0/24 IPv6 subnet=3fff:172:20:20::/64 MTU=0
17:41:18 INFO Creating lab directory path=/Users/<user>/clab/static-lab/clab-static-lab
17:41:18 INFO unable to adjust Labdir file ACLs: operation not supported
17:41:18 INFO Creating container name=r2
17:41:18 INFO Creating container name=r1
17:41:19 INFO Created link: r1:eth1 ▪┄┄▪ r2:eth1
17:41:19 INFO Executed command node=r2 command="chown -R frr:frr /etc/frr" stdout=""
17:41:19 INFO Executed command node=r2 command="/usr/lib/frr/frrinit.sh start"
  stdout=
  │  * Starting watchfrr with command: '  /usr/lib/frr/watchfrr  -d  -F traditional   zebra staticd'
  │  * Started watchfrr

17:41:19 INFO Executed command node=r1 command="chown -R frr:frr /etc/frr" stdout=""
17:41:19 INFO Executed command node=r1 command="/usr/lib/frr/frrinit.sh start"
  stdout=
  │  * Starting watchfrr with command: '  /usr/lib/frr/watchfrr  -d  -F traditional   zebra staticd'
  │  * Started watchfrr

17:41:19 INFO Adding host entries path=/etc/hosts
17:41:19 INFO Adding SSH config for nodes path=/etc/ssh/ssh_config.d/clab-static-lab.conf
╭────────────────────┬────────────────┬─────────┬───────────────────╮
│        Name        │   Kind/Image   │  State  │   IPv4/6 Address  │
├────────────────────┼────────────────┼─────────┼───────────────────┤
│ clab-static-lab-r1 │ linux          │ running │ 172.20.20.3       │
│                    │ frr-lab:latest │         │ 3fff:172:20:20::3 │
├────────────────────┼────────────────┼─────────┼───────────────────┤
│ clab-static-lab-r2 │ linux          │ running │ 172.20.20.2       │
│                    │ frr-lab:latest │         │ 3fff:172:20:20::2 │
╰────────────────────┴────────────────┴─────────┴───────────────────╯

clab-static-lab-r1clab-static-lab-r2 が running になりました。表示されている 172.20.20.x は管理ネットワーク(eth0)の IP です。どちらのルータにどの番号が振られるかは起動順で変わるので、.2.3 が入れ替わることがあります。

ログの中では、exec: が実行されている行に注目できます。

17:41:19 INFO Executed command node=r1 command="chown -R frr:frr /etc/frr" stdout=""
17:41:19 INFO Executed command node=r1 command="/usr/lib/frr/frrinit.sh start"
  stdout=
  │  * Starting watchfrr with command: '  /usr/lib/frr/watchfrr  -d  -F traditional   zebra staticd'

起動対象が zebra staticd の2つだけになっているので、daemons の指定が効いていることがここで確認できます。

unable to adjust Labdir file ACLs: operation not supported という INFO ログが出ますが、エラーではありません。OrbStack VM のファイルシステムが ACL 操作に対応していないだけで、動作に影響はないので無視できます。

FRR が起動しているか

自前イメージは exec: で起動する方式なので、まずここを確認します。

docker exec clab-static-lab-r1 vtysh -c "show daemons"
% Can't open configuration file /etc/frr/vtysh.conf due to 'No such file or directory'.
 zebra watchfrr staticd

zebrastaticd、それに監視役の watchfrr が動いています。1行目の警告は無害です(後述)。

インターフェースの確認

docker exec clab-static-lab-r1 ip -br addr show eth1
docker exec clab-static-lab-r2 ip -br addr show eth1
eth1@if319       UP             10.0.0.1/30 fe80::a8c1:abff:fec0:2b04/64
eth1@if318       UP             10.0.0.2/30 fe80::a8c1:abff:fe28:9fbb/64

frr.conf に書いた IP が反映されています。

ルーティングテーブルの確認

docker exec clab-static-lab-r1 vtysh -c "show ip route"
Codes: K - kernel route, C - connected, S - static, R - RIP,
       O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
       T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,
       f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

K>* 0.0.0.0/0 [0/0] via 172.20.20.1, eth0, 00:00:00
C>* 10.0.0.0/30 is directly connected, eth1, 00:00:00
C>* 172.20.20.0/24 is directly connected, eth0, 00:00:00
C>* 192.168.1.0/24 is directly connected, lo, 00:00:00
S>* 192.168.2.0/24 [1/0] via 10.0.0.2, eth1, weight 1, 00:00:00

目的の S 経路が出ました。各行の読み方は次のとおりです。

意味
S>* 192.168.2.0/24 ... via 10.0.0.2, eth1 S = static。手動で設定した経路
C>* 10.0.0.0/30 ... eth1 C = connected(直結)。r1-r2 間のリンク
C>* 192.168.1.0/24 ... lo 自分の LAN(ループバックで代用)
C>* 172.20.20.0/24 ... eth0 containerlab の管理ネットワーク。自動で付く
K>* 0.0.0.0/0 ... via 172.20.20.1, eth0 K = kernel。管理ネットワーク経由のデフォルトルート。これも自動で付く

[1/0]1 はアドミニストレイティブディスタンスで、静的経路の既定値は 1 です。複数の経路情報源が競合したときにどちらを信じるかの優先度を表します。行頭の > は選ばれた経路、* は実際にカーネルの転送表に入っている経路を意味します。

eth0 の管理ネットワークと K>* のデフォルトルートは containerlab が自動で付けたもので、ラボの設計とは無関係です。ただし、この2行は11章の実験結果に効いてきます。

静的経路だけを絞って見ることもできます。

docker exec clab-static-lab-r1 vtysh -c "show ip route static"
S>* 192.168.2.0/24 [1/0] via 10.0.0.2, eth1, weight 1, 00:00:00

vtysh 起動時に % Can't open configuration file /etc/frr/vtysh.conf が出ることがありますが無視できます。これは vtysh という CLI ツール自身の設定ファイルで、ルーティング動作には無関係です。統合方式では宣言が frr.conf 側に集約されるため置いていません。気になる場合は各 routerN/ に空の vtysh.conf を置けば出なくなります。

疎通確認

r1 から r2 の LAN 側アドレスへ ping します。

docker exec clab-static-lab-r1 ping -c 3 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.061 ms
64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=0.134 ms
64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=0.130 ms

--- 192.168.2.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2051ms
rtt min/avg/max/mdev = 0.061/0.108/0.134/0.033 ms

r2 からも 192.168.1.1 へ ping して、双方向で通ることを確認します。

docker exec clab-static-lab-r2 ping -c 3 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=1.78 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.100 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.098 ms

--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2071ms
rtt min/avg/max/mdev = 0.098/0.658/1.776/0.790 ms

双方向とも 3/3 到達し、直結していないネットワーク同士が静的経路によって到達可能になりました。RTT が 0.1ms 前後で収まっているのは ARM64 ネイティブで動いているからです。

11. 静的経路を消したときの挙動

静的ルーティングの働きを確かめるために、入れた経路を消してみます。

docker exec clab-static-lab-r1 vtysh -c "conf t" -c "no ip route 192.168.2.0/24 10.0.0.2" -c "end"
docker exec clab-static-lab-r1 vtysh -c "show ip route"
(Codes の凡例は10章と同じなので省略)
K>* 0.0.0.0/0 [0/0] via 172.20.20.1, eth0, 00:00:05
C>* 10.0.0.0/30 is directly connected, eth1, 00:00:05
C>* 172.20.20.0/24 is directly connected, eth0, 00:00:05
C>* 192.168.1.0/24 is directly connected, lo, 00:00:05

S の行が消えました。この状態で ping します。

docker exec clab-static-lab-r1 ping -c 2 192.168.2.1
PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.

--- 192.168.2.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1056ms

物理的な結線は何も変えていないのに届かなくなりました。直結している 10.0.0.0/30 はそのまま残っているのに、その先の 192.168.2.0/24 へは行けません。直結以外の宛先は、手動で経路を教えないと届かないということです。

エラーにならない理由

ここで出ているのは Network is unreachable ではなく、無応答による 100% packet loss です。

原因は、10章で触れた管理ネットワーク経由のデフォルトルートです。

K>* 0.0.0.0/0 [0/0] via 172.20.20.1, eth0

このデフォルトルートが受け皿として残っているため、r1 は 192.168.2.1 宛の経路が無いとは判断しません。該当する経路が無いのでデフォルトルートに流そうと判断し、パケットを管理ネットワーク側(eth0)へ送り出します。そこに 192.168.2.1 は居ないので、パケットは誰にも届かず捨てられます。

デフォルトルートが無ければ、ルータは経路が無いと即断して Network is unreachable を返したはずです。つまりデフォルトルートの有無によって、経路ミスの症状が即座のエラーから無言のブラックホールへ変わります。設定ミスがエラーとして表に出ず「なぜか通信できない」という形でしか現れないぶん、実務ではこちらのほうが厄介です。

ルータが2台なら経路を手で書けますが、10台20台になると全ルータに全経路を書くことになり現実的ではなくなります。この経路の教え合いを自動化する仕組みが、OSPF や BGP といった動的ルーティングプロトコルです。静的ルーティングを一度手で書いておくと、動的ルーティングが何を自動化しているのかが具体的に分かります。

消した経路を戻す

いま消したのは、vtysh から触れる running config だけです。bind mount 元の router1/frr.conf には ip route の行が残ったままなので(vtysh で write していないため)、ラボを作り直せば元の状態に戻ります。

containerlab destroy -t static.clab.yml
containerlab deploy  -t static.clab.yml

vtysh での変更が再作成で消えるという性質は、この章のような一時的な実験には都合がよい一方、残したい変更をコンテナ内で行ってはいけない理由でもあります。設定を恒久的に変えるときはホスト側のファイルを編集します(12章)。

12. ハマりどころ

実際に踏んだものを並べます。

docker グループの反映方法

5章で書いたとおり、OrbStack の Ubuntu VM には newgrp が無いため、一般的な手順にある newgrp docker が使えません。sudo usermod -aG docker $USER の後は、exit してから orb -m clab で入り直すのが唯一の反映方法です。

FRR コンテナの restart

設定を変えたときに docker restart で済ませたくなりますが、これは避けます。理由は使っているイメージ側ではなく、containerlab の kind: linux 側にあります。公式ドキュメントにはこう書かれています。

Nodes of linux kind will have a on-failure restart policy when run with docker runtime. ... When restarted, the container will loose all non-eth0 interfaces.

出典:containerlab · linux kind(Using linux containers)

veth は containerlab がコンテナ起動後に netns へ差し込むものなので、Docker がコンテナを作り直すと eth1 以降が消えます。公式イメージでも自前ビルドでも同じです。

自前ビルドの frr-lab では、これに加えてもう1つ問題が起きます。frr-labCMD ["sleep", "infinity"] で、FRR は exec: によって deploy 時にしか起動されません。restart すると、インターフェースが消えたうえに FRR プロセスすら起動していない状態で戻ってきます。

設定変更は作り直しで反映します。

containerlab destroy -t static.clab.yml
containerlab deploy  -t static.clab.yml

containerlab tools veth create で手動復旧する道もありますが、ラボなら作り直すほうが早いでしょう。

設定変更の反映先

設定の変え方は2通りあり、目的で使い分けます。

やり方 反映範囲 使う場面
vtysh で running config を変える メモリ上だけ。再作成で消える 11章のような一時的な実験
ホスト側の router1/frr.conf を編集して destroy → deploy ファイルが正。作り直しても残る 恒久的に残したい変更

コンテナ内の /etc/frr/frr.conf を直接編集するのは、どちらでもない中途半端なやり方になります。ファイルを書き換えたつもりでも作り直したときに消えるので、残したい変更は必ず bind mount 元のホスト側ファイルを編集します。

Mac のエディタで ~/clab/static-lab/router1/frr.conf を開いて編集できるので、この運用はさほど苦になりません。

clab_admins グループのメッセージは無視してよい

containerlab の deploy / destroy は特権コマンドで、clab_admins というグループのメンバーだけが sudo なしで実行できます。インストール時に「sudo usermod -aG clab_admins <ユーザー名> を実行してください」というメッセージが出るので、手作業が要るように見えます。

しかし標準の手順(get.containerlab.dev)で入れた場合、この追加はパッケージのインストール処理がすでに済ませています(バージョン 0.63.0 以降。公式ドキュメント)。あのメッセージは追加の成否に関係なく必ず表示されるだけで、実際にはグループに入っています。groupsclab_admins が出れば追加済みです。

反映のタイミングは docker グループと同じで、ログインし直したときに効きます。docker グループのために VM へ入り直していれば、clab_admins も有効です。万一 deploy で権限エラーが出たときだけ、表示されたコマンドを実行して入り直します。

無視してよいメッセージ

メッセージ 出るタイミング 正体
unable to adjust Labdir file ACLs: operation not supported deploy OrbStack VM の FS が ACL 非対応なだけの INFO ログ
% Can't open configuration file /etc/frr/vtysh.conf vtysh 実行のたび毎回 vtysh 自身の設定ファイル。ルーティング動作には無関係

13. ラボの停止と削除

containerlab destroy -t static.clab.yml
17:41:34 INFO Parsing & checking topology file=static.clab.yml
17:41:34 INFO Destroying lab name=static-lab
17:41:34 INFO Removed container name=clab-static-lab-r1
17:41:34 INFO Removed container name=clab-static-lab-r2
17:41:34 INFO Removing host entries path=/etc/hosts
17:41:34 INFO Removing SSH config path=/etc/ssh/ssh_config.d/clab-static-lab.conf

VM 自体を止めたいときは Mac 側からこうします。

orb stop clab

まとめ

containerlab はコンテナを起動して仮想的な配線を張るツールで、ノード間を任意に結線できない docker compose の代わりになります。ただし netns や veth といった Linux 固有の機能を直接使うため、macOS では Linux VM が要ります。OrbStack の Linux Machines 機能がこれに合い、公式も OrbStack を推奨しています。/Users を VM に共有するので、Mac のエディタで設定を編集して VM で deploy できます。

Apple Silicon で気をつけるのは、公式 frrouting/frr イメージが amd64 のみで Rosetta 動作になる点です。一見動きますが docker exec のハングといった実害が出ます。Ubuntu ベースで自前ビルドすれば ARM64 ネイティブになり、tcpdump も同梱できます。ただし FRR が自動起動しなくなるので、clab.ymlexec: で明示起動が必要です。

静的ルーティングそのものは ip route <宛先> <ネクストホップ> の1行で、ルーティングテーブルでは直結が C、静的が S として現れます。直結以外は手動で経路を教えないと届かず、しかも経路が欠けたときに必ずエラーが出るとは限りません。デフォルトルートが受け皿にあると、無言のブラックホールになります。

次の一歩

同じ frr-lab イメージと同じ frr.conf の書き方のまま、daemonsospfd=yesrouter ospf の設定を足せば OSPF ラボになります。静的経路を手で書かなくても、ルータ同士が経路を教え合う様子を確認できます。

参考リンク

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?