これは何?
Dockerなどのコンテナ技術で使用されるNetwork Namespaceを使い、小さな仮想ネットワークを作る記事です。
ゴールは、異なるNetwork Namespace間でpingできるようにすることです。
Network Namespaceとは
Network NamespaceはLinuxのNamespace機能の一つで、ネットワーク関連のリソースを隔離する機能です。
Network Namespaceを使うことによって、ネットワーク的にシステムから独立した仮想的な空間を作ることができます。
Network namespaces provide isolation of the system resources associated with networking: network devices, IPv4 and IPv6 protocol stacks, IP routing tables, firewall rules, the /proc/net directory (which is a symbolic link to /proc/pid/net), the /sys/class/net directory, various files under /proc/sys/net, port numbers (sockets), and so on. In addition, network namespaces isolate the UNIX domain abstract socket namespace (see unix(7)).
ネットワーク的に独立した空間を作るため、ネットワーク関連の設定がホストマシンとNetwork Namespace内では異なります。
例えば、ホストマシンのRoute Tableと作成したNetwork Namespace内のRoute Tableを見ると、違う内容が表示されます。
$ ip route show
default via 10.32.0.1 dev eno1 proto dhcp src 10.32.1.33 metric 100
10.32.0.0/16 dev eno1 proto kernel scope link src 10.32.1.33 metric 100
$ sudo ip netns add ns
$ sudo ip netns exec ns bash
$ ip route show
Network Namespaceを作成した段階ではRoute Tableにエントリが存在しないため、特に何も表示されません。
実践
環境
$ cat /etc/issue
Ubuntu 24.04.1 LTS \n \l
Network Namespaceの作成
異なるNetwork Namespace間でpingが通るようにしたいので、まずは2つのNetwork Namespaceを作成します。
$ sudo ip netns add ns1
$ sudo ip netns add ns2
仮想Network Interfaceの作成
続いて、各Network Namespaceが通信するための仮想的なNetwork Interfaceを作成します。
この仮想的なNetwork Intefaceはveth(Virtual Ethernet Device)と呼ばれます。
vethを作成する際にはNetwork Interfaceを単体で作るのではなく、両端がNetwork Interfaceになっている仮想的なケーブルを作成し、それをNetwork Namespaceにアタッチします。
$ sudo ip link add veth1 type veth peer name veth2
veth1
, veth2
というNetwork Interfaceが追加されていることが確認できます。
$ sudo ip link show
# ...
4: veth2@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 36:e9:5b:30:7a:75 brd ff:ff:ff:ff:ff:ff
5: veth1@veth2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 02:f2:f1:f3:55:82 brd ff:ff:ff:ff:ff:ff
この時点ではホストマシンの領域にできてしまっているので、両端のNetwork Interfaceを各Network Namespaceにアタッチします。
$ sudo ip link set veth1 netns ns1
$ sudo ip link set veth2 netns ns2
ns1, ns2に入ってNetwork Interfaceがアタッチされているか確認します。
$ sudo ip netns exec ns1 bash
$ ip link show
# ...
5: veth1@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 02:f2:f1:f3:55:82 brd ff:ff:ff:ff:ff:ff link-netns ns2
$ sudo ip netns exec ns2 bash
$ ip link show
# ...
4: veth2@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 36:e9:5b:30:7a:75 brd ff:ff:ff:ff:ff:ff link-netns ns1
IPアドレスの割当
この時点で異なるNetwork Namespace同士がvethを通して繋がりましたが、pingを通すためにはIPアドレスの設定が必要になります。
各Network Namespaceでvethに対してIPアドレスを割り当てます。
$ sudo ip netns exec ns1 bash
$ ip address add 192.0.1.1/24 dev veth1
$ ip address show
# ...
5: veth1@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 02:f2:f1:f3:55:82 brd ff:ff:ff:ff:ff:ff link-netns ns2
inet 192.0.1.1/24 scope global veth1
valid_lft forever preferred_lft forever
$ sudo ip netns exec ns2 bash
$ ip address add 192.0.1.2/24 dev veth2
$ ip address show
# ...
4: veth2@if5: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
link/ether 36:e9:5b:30:7a:75 brd ff:ff:ff:ff:ff:ff link-netns ns1
inet 192.0.1.2/24 scope global veth2
valid_lft forever preferred_lft forever
Network Interfaceの状態をUPに変更する
最後にNetwork Interfaceの状態をUPにすることで通信できるようにします。
Route tableにエントリが追加されます。
$ sudo ip netns exec ns1 bash
$ ip link set veth1 up
$ ip route show
192.0.1.0/24 dev veth1 proto kernel scope link src 192.0.1.1 linkdown
$ sudo ip netns exec ns2 bash
$ ip link set veth2 up
$ ip route show
192.0.1.0/24 dev veth2 proto kernel scope link src 192.0.1.2
ping
$ sudo ip netns exec ns1 bash
$ ping -c 3 192.0.1.2
PING 192.0.1.2 (192.0.1.2) 56(84) bytes of data.
64 bytes from 192.0.1.2: icmp_seq=1 ttl=64 time=0.063 ms
64 bytes from 192.0.1.2: icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from 192.0.1.2: icmp_seq=3 ttl=64 time=0.058 ms
--- 192.0.1.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2059ms
rtt min/avg/max/mdev = 0.058/0.062/0.066/0.003 ms
参考