1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FRRoutingをDockerで試す~OSPF編~

Posted at

この記事は

下記の記事に触発されて、自分でも試したくなった
Docker上のFRRoutingでOSPFを動かしてみる

元記事ではcompose.ymlを使っていなかったが
また後で再現するときに楽なので、今回はcompose.ymlを作る

前提条件

  • Windows 11 Home の Docker Desktop環境で動作
  • Docker
    • Client Version: 25.0.3
    • Server: Docker Desktop 4.27.2 (137060)
      • Engine Version: 25.0.3
  • Docker Compose version v2.24.5-desktop.1

Docker Desktopは一定規模以上の企業で使う場合、有償となります

構成

  • 両端のネットワークにPCが1台ずつ存在する
  • 真ん中の19ネットワークにはルータしか存在しない
ネットワーク PC1 ルーター1 ルーター PC2
172.18.0.0/16 alpine1 (.10) frr1 (.250) - -
172.19.0.0/16 - frr1 (.250) frr2 (.251) -
172.20.0.0/16 - - frr2 (.250) alpine2 (.10)

docker compose コマンド復習

Docker Composeコマンド集

気づいたらdocker-composeが色々変わっていた件

Docker Compose Up

compose.ymlが置かれている階層(今回はworkdir)に移動し、docker compose upする
-dオプションをつけて、デタッチしつつ、ログを画面に流す

cd workdir
docker compose up -d && docker compose logs -f

alpineのデフォルトゲートウェイを変更する

alpine1コンテナの中で作業する

cd workdir
docker compose exec alpine1 bin/sh

alpine1のルーティングテーブルを確認すると
デフォルトゲートウェイが172.18.0.1となっている

 Destinationが「0.0.0.0」,Genmask「0.0.0.0」の設定行は,標準のパケット転送先を示しています。この設定は,他の設定に該当しないすべてのパケットに適用されます。この行で設定されているGatewayは,標準で使われるゲートウエイという意味で「デフォルト・ゲートウエイ」と呼ばれます。
https://xtech.nikkei.com/it/article/COLUMN/20080520/303086/

/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.18.0.1      0.0.0.0         UG    0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

既存のルートを削除し、新ルートを追加する

ルーターコンテナのIPアドレスである172.18.0.250に変更する

route del default gw 172.18.0.1
route add default gw 172.18.0.250

変更が反映されていることを確認する

/ # route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.18.0.250    0.0.0.0         UG    0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

alpine2についても同様の設定を行う

alpine1と通信する相手であるalpine2についても
同様の手順でデフォルトゲートウェイを変更する
ただし、所属するネットワークが違う点に注意する

docker compose exec alpine2 bin/sh

route del default gw 172.20.0.1
route add default gw 172.20.0.250

route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.20.0.250    0.0.0.0         UG    0      0        0 eth0
172.20.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

この状態ではまだPINGは通らない

/ # ping 172.20.0.10
PING 172.20.0.10 (172.20.0.10): 56 data bytes
^C
--- 172.20.0.10 ping statistics ---
13 packets transmitted, 0 packets received, 100% packet loss

FRRoutingコンテナ

続いて、FRRoutingコンテナの設定をしていく
aplineは単なる軽量Linuxなので、事前知識は不要だったが
FRRoutingについては中身を知らないと設定できないので
ひとつずつ調べて進める

VTYSHとは何か

自動翻訳によると、以下の定義だそうです

VTYSHはFRRデーモン用のシェルである。VTYSHは各デーモンで定義されたすべてのCLIコマンドを統合し、単一のシェルでユーザーに表示します。これにより、ユーザーは各デーモンにtelnetで接続して個々のシェルを使用する手間を省くことができます。統合は、デーモンからコマンドを抽出し、ビルド時にVTYSHに注入することで達成される。

何も設定しないままvtyshと入力すると、コンフィグファイルが無いとエラーが出る

/ # vtysh
% Can't open configuration file /etc/frr/vtysh.conf due to 'No such file or directory'.

コンフィグファイルの取り扱い

vtysh.conffrr.confは何が違うのだろう

FRRは/etc/frr/frr.confにある単一の設定ファイルを使用する。FRRがinitスクリプトやsystemdを使って起動されると、vtyshが起動され、設定ファイルを読み込み、適切な部分を興味のあるデーモンだけに送信する。実行中の設定更新は、同様にvtyshを使ってこの単一ファイルに永続化される。

この段階で、/etc/frr/にあるコンフィグファイルはstaticd.confzebra.confの2つだけ

/ # ls -la  /etc/frr/
total 16
drwxr-xr-x    1 frr      frr           4096 Mar 24 08:43 .
drwxr-xr-x    1 root     root          4096 Mar 24 08:43 ..
-rw-r--r--    1 frr      frr           3840 Nov  6  2022 daemons
-rw-------    1 frr      frr              0 Mar 24 08:43 staticd.conf
-rw-------    1 frr      frr              0 Mar 24 08:43 zebra.conf

vtysh.confをつくる

vtysh.conf.sampleをGithubから拾ってくる
service integrated-vtysh-configの行だけ、行頭の!を取り外して有効化しておく

vi /etc/frr/vtysh.conf

!
! Sample configuration file for vtysh.
!
service integrated-vtysh-config
!hostname quagga-router
!username root nopassword
!

VTYSHでいろいろコマンド確認

VTYSHの中に入るには、単純にVTYSHと打てばよいらしい

/ # vtysh
Hello, this is FRRouting (version 8.4_git).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

現在の設定を確認する

show run
frr1# show run
Building configuration...

Current configuration:
!
frr version 8.4_git
frr defaults traditional
hostname frr1
domainname
service integrated-vtysh-config
!
end

その他の設定を確認しようとすると、「zebraが動いてないよ」と怒られる

show int brief
frr1# show int brief
zebra is not running
show ip route
frr1# show ip route
zebra is not running

zebra起動までのトラブルシューティング

たしかにdocker compose upした際のログを確認すると、zebraの起動に失敗している
これは後続のログのfrr.confが無いことが原因なのだろうか
ひとまずvtysh.confはつくって、サービスを統合するオプションも有効にしてあるので、コンテナを再起動してみる

frr1     | Failed to start zebra!
frr1     | /etc/frr/frr.conf does not exist; skipping config apply

・・・ダメでした
/etc/frr/frr.confを作ってみたけど、それもダメ

frr1     | 2024/03/24 15:18:05 WATCHFRR: [ZG9QC-QRCJZ] failed to mkdir "/var/tmp/frr/watchfrr.11": File exists
frr1     | 2024/03/24 15:18:05 WATCHFRR: [M1DC0-ZDNYJ] crashlog and per-thread log buffering unavailable!
frr1     | 2024/03/24 15:18:05 WATCHFRR: [T83RR-8SM5G] watchfrr 8.4_git starting: vty@0
frr1     | 2024/03/24 15:18:05 WATCHFRR: [ZCJ3S-SPH5S] zebra state -> down : initial connection attempt failed
frr1     | 2024/03/24 15:18:05 WATCHFRR: [ZCJ3S-SPH5S] staticd state -> down : initial connection attempt failed
frr1     | 2024/03/24 15:18:05 WATCHFRR: [YFT0P-5Q5YX] Forked background command [pid 12]: /usr/lib/frr/watchfrr.sh restart all
frr1     | /usr/lib/frr/frrcommon.sh: line 211: kill: (86) - No such process
frr1     | Cannot stop zebra: pid file not found
frr1     | 2024/03/24 15:18:05 ZEBRA: [ZG9QC-QRCJZ] failed to mkdir "/var/tmp/frr/zebra.21": File exists
frr1     | 2024/03/24 15:18:05 ZEBRA: [M1DC0-ZDNYJ] crashlog and per-thread log buffering unavailable!
frr1     | privs_init: initial cap_set_proc failed: Operation not permitted
frr1     | Wanted caps: cap_net_admin,cap_net_raw,cap_sys_admin=p
frr1     | Have   caps: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=p
frr1     | Failed to start zebra!
frr1     | 2024/03/24 15:18:06 STATIC: [ZG9QC-QRCJZ] failed to mkdir "/var/tmp/frr/staticd.24": File exists
frr1     | 2024/03/24 15:18:06 STATIC: [M1DC0-ZDNYJ] crashlog and per-thread log buffering unavailable!
frr1     | 2024/03/24 15:18:06 WATCHFRR: [QDG3Y-BY5TN] staticd state -> up : connect succeeded
frr1     | 2024/03/24 15:19:00 WATCHFRR: [K54RW-4APGS][EC 268435457] startup did not complete within timeout (1/2 daemons running)
frr1     | 2024/03/24 15:19:06 WATCHFRR: [YFT0P-5Q5YX] Forked background command [pid 34]: /usr/lib/frr/watchfrr.sh restart all
frr1     | 2024/03/24 15:19:06 WATCHFRR: [HD38Q-0HBRT][EC 268435457] staticd state -> down : read returned EOF
frr1     | Cannot stop zebra: pid file not found
frr1     | privs_init: initial cap_set_proc failed: Operation not permitted
frr1     | Wanted caps: cap_net_admin,cap_net_raw,cap_sys_admin=p
frr1     | Have   caps: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap=p
frr1     | Failed to start zebra!
frr1     | 2024/03/24 15:19:06 WATCHFRR: [QDG3Y-BY5TN] staticd state -> up : connect succeeded

staticdは動いているっぽいけど、zebraは起動しておらず

/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /sbin/tini -- /usr/lib/frr/docker-start
    7 root      0:00 {docker-start} /bin/bash /usr/lib/frr/docker-start
   11 root      0:00 /usr/lib/frr/watchfrr zebra staticd
   27 root      0:00 bin/sh
   48 frr       0:00 /usr/lib/frr/staticd -d -F traditional -A 127.0.0.1
   51 root      0:00 ps

frr.confが空っぽなのはいかがなものか

vtysh.confでコンフィグファイルを統合するように設定したものの
肝心な統合先であるfrr.confが当初不在だったのはいかがなものか

service integrated-vtysh-config
vtysh will always write frr.conf.

今、frr.confは空っぽであるがそれでよいのか
zebraが起動しない問題は、frr.confとは無関係なのか?

解決

compose.ymlprivileged: trueを追記したら動きました
zebraを起動するには特権が必要だったという話
とくにfrr.confは関係なかった様子

Compose.ymlを編集した際は、buildオプションをつけないと反映されないので注意
docker compose up --build -d

よくよく見ると、先行記事にも書いてありました

frr1, frr2を作り、それぞれnet1とnet2、net2とnet3に接続します。
--privilegedをつけないと動かないようです。

OSPFを有効にする

vi /etc/frr/daemonsでデーモンを編集し、ospf=yesとする

/etc/frr # cat daemons
# This file tells the frr package which daemons to start.
#
# Sample configurations for these daemons can be found in
# /usr/share/doc/frr/examples/.
#
# ATTENTION:
#
# When activating a daemon for the first time, a config file, even if it is
# empty, has to be present *and* be owned by the user and group "frr", else
# the daemon will not be started by /etc/init.d/frr. The permissions should
# be u=rw,g=r,o=.
# When using "vtysh" such a config file is also needed. It should be owned by
# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
#
# The watchfrr, zebra and staticd daemons are always started.
#
bgpd=no
ospfd=yes
ospf6d=no
ripd=no
ripngd=no
isisd=no

docker compose restart frr1でコンテナを再起動し
docker compose exec frr1 bin/shで再度コンテナに入る

プロセスの一覧を確認すると、ospfdが動いていることがわかる

/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /sbin/tini -- /usr/lib/frr/docker-start
    7 root      0:00 {docker-start} /bin/bash /usr/lib/frr/docker-start
   12 root      0:00 /usr/lib/frr/watchfrr zebra ospfd staticd
   26 frr       0:00 /usr/lib/frr/zebra -d -F traditional -A 127.0.0.1 -s 90000000
   31 frr       0:00 /usr/lib/frr/ospfd -d -F traditional -A 127.0.0.1
   34 frr       0:00 /usr/lib/frr/staticd -d -F traditional -A 127.0.0.1
   38 root      0:00 bin/sh
   44 root      0:00 ps

OSPFの設定をする(VTYSH)

frr1でVTYSHを起動し、先ほど失敗したコマンドを確認する

まずはインターフェイスの要約
eth0とeth1にそれぞれ.250のIPアドレスが付与されていることがわかる

show int brief
frra1# show int brief
Interface       Status  VRF             Addresses
---------       ------  ---             ---------
eth0            up      default         172.18.0.250/16
eth1            up      default         172.19.0.250/16
lo              up      default

つづいてIPルーティングテーブルを表示する
2つのネットワークとダイレクトにつながっていることがわかる
またデフォルトゲートウェイ(0.0.0.0)は172.18.0.1向けということがわかる

frra1# 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.18.0.1, eth0, 00:03:35
C>* 172.18.0.0/16 is directly connected, eth0, 00:03:35
C>* 172.19.0.0/16 is directly connected, eth1, 00:03:35

設定を投入していく

まずはわけもわからず、先行文献に従って設定を投入してみる

/ # vtysh
frr1# conf t
frr1(config)# interface lo
frr1(config-if)# ip address 1.1.1.1/32
frr1(config-if)# exit
frr1(config)# router ospf
frr1(config-router)# router-info area 0.0.0.0
frr1(config-router)# network 172.18.0.0/16 area 0.0.0.0
frr1(config-router)# network 172.19.0.0/16 area 0.0.0.0
frr1(config-router)# end

設定を確認する

show run
frra1# show run
Building configuration...

Current configuration:
!
frr version 8.4_git
frr defaults traditional
hostname frra1
no ipv6 forwarding
domainname
service integrated-vtysh-config
!
interface lo
 ip address 1.1.1.1/32
exit
!
router ospf
 network 172.18.0.0/16 area 0.0.0.0
 network 172.19.0.0/16 area 0.0.0.0
 router-info area
exit
!
end

IPルートが反映されていることを確認する

show ip route
frra1# 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.18.0.1, eth0, 00:09:18
C>* 1.1.1.1/32 is directly connected, lo, 00:01:41
O   172.18.0.0/16 [110/10] is directly connected, eth0, weight 1, 00:00:58
C>* 172.18.0.0/16 is directly connected, eth0, 00:09:18
O   172.19.0.0/16 [110/10] is directly connected, eth1, weight 1, 00:00:54
C>* 172.19.0.0/16 is directly connected, eth1, 00:09:18

設定を永続化させる

write mem
frra1# write mem
Note: this version of vtysh never writes vtysh.conf
Building Configuration...
Integrated configuration saved to /etc/frr/frr.conf
[OK]

frr.confに書き込まれているらしいので、確認してみる

frr.conf
/ # cat /etc/frr/frr.conf
frr version 8.4_git
frr defaults traditional
hostname frra1
no ipv6 forwarding
domainname
service integrated-vtysh-config
!
interface lo
 ip address 1.1.1.1/32
exit
!
router ospf
 network 172.18.0.0/16 area 0.0.0.0
 network 172.19.0.0/16 area 0.0.0.0
 router-info area
exit
!

frr2の設定

こちらも見よう見まねで設定
まずはdaemonsファイルを編集してOSPFを有効にする
ちなみに順序を間違えて先に設定を投入しようとすると、VTYSHのコンフィグで怒られる(ある意味親切ですね)

frr2(config)# route ospf
ospfd is not running

vtyshを起動して、以下のコマンドを打ち込む

frr2# conf t
frr2(config)# interface lo
frr2(config-if)# ip address 2.2.2.2/32
frr2(config-if)# exit
frr2(config)# router ospf
frr2(config-router)# router-info area 0.0.0.0
frr2(config-router)# network 172.19.0.0/16 area 0.0.0.0
frr2(config-router)# network 172.20.0.0/16 area 0.0.0.0
frr2(config-router)# end

こちらも永続化のためにwrite memしておく
exitでvtyshを抜けて、cat /etc/frr/frr.confで設定が保存されていることを確認する

/ # cat /etc/frr/frr.conf
frr version 8.4_git
frr defaults traditional
hostname frr2
no ipv6 forwarding
domainname
service integrated-vtysh-config
!
interface lo
 ip address 2.2.2.2/32
exit
!
router ospf
 network 172.19.0.0/16 area 0.0.0.0
 network 172.20.0.0/16 area 0.0.0.0
 router-info area
exit
!

OSPF neighborを確認する

frr1, frr2の両方の設定が完了した

frr1から見て、frr2がネイバー関係にあることがわかる

frr1# show ip ospf neighbor

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
2.2.2.2           1 Full/Backup     2m33s             35.709s 172.19.0.251    eth1:172.19.0.250                    0     0     0

逆もしかり

frr2# show ip ospf neighbor

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
1.1.1.1           1 Full/DR         5m18s             31.757s 172.19.0.250    eth0:172.19.0.251                    0     0     0

いざ、疎通確認!!

alpine1からalpine2に向かってトレースルート

/ # traceroute -n 172.20.0.10
traceroute to 172.20.0.10 (172.20.0.10), 30 hops max, 46 byte packets
 1  172.18.0.250  0.009 ms  0.011 ms  0.012 ms
 2  172.19.0.251  0.012 ms  0.014 ms  0.018 ms
 3  172.20.0.10  0.010 ms  0.011 ms  0.018 ms

逆方向

/ # traceroute -n 172.18.0.10
traceroute to 172.18.0.10 (172.18.0.10), 30 hops max, 46 byte packets
 1  172.20.0.250  0.009 ms  0.007 ms  0.008 ms
 2  172.19.0.250  0.016 ms  0.010 ms  0.010 ms
 3  172.18.0.10  0.015 ms  0.010 ms  0.008 ms

うまくいきました!

compose.yml

services:
  alpine1:
    image: alpine
    container_name: alpine1
    hostname: alpine1
    tty: true
    stdin_open: true
    privileged: true
    networks:
      net1:
        ipv4_address: 172.18.0.10
  alpine2:
    image: alpine
    container_name: alpine2
    hostname: alpine2
    tty: true
    stdin_open: true
    privileged: true
    networks:
      net3:
        ipv4_address: 172.20.0.10

  frr1:
    image: frrouting/frr
    container_name: frr1
    hostname: frr1
    privileged: true
    networks:
      net1:
        ipv4_address: 172.18.0.250
      net2:
        ipv4_address: 172.19.0.250
  frr2:
    image: frrouting/frr
    container_name: frr2
    hostname: frr2
    privileged: true
    networks:
      net2:
        ipv4_address: 172.19.0.251
      net3:
        ipv4_address: 172.20.0.250

networks:
  net1:
    ipam:
      config:
        - subnet: 172.18.0.0/16
  net2:
    ipam:
      config:
        - subnet: 172.19.0.0/16
  net3:
    ipam:
      config:
        - subnet: 172.20.0.0/16

参考

糸冬了!!

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?