Network Namespaceとは?
- ネットワーク的にシステムから独立した環境の作成が出来る
- IPに関する処理を1台のLinux内で複数に分割することが出来る
- Dockerのようなコンテナ型仮想技術を構成する要素の一つ
環境
仮想マシンとしてUbuntuをインストールして、ubuntu上で検証します
Network Namespaceを使ってみる
$ sudo ip netns add practice
$ ip netns list
practice
practice
という名前のNetwork Namespaceを作成します
ip netns list
では、作成されたNetwork Namespaceの確認をします
ネットワークインターフェイスと、ルーティングテーブルの確認
$ sudo ip netns exec practice ip address show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
先ほど作成したNetwork Namespace環境で$ ip address show
コマンドの実行しています
1つのネットワークインターフェース(1: lo)が表示されています
今度は、Network Namespaceを使用せずに実行してみます
$ ip address show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:d9:74:4e:9b:d3 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3
valid_lft 82340sec preferred_lft 82340sec
inet6 fe80::d9:74ff:fe4e:9bd3/64 scope link
valid_lft forever preferred_lft forever
表示される内容は変わり、こちらの環境ではネットワークインターフェース(2: enp0s3)が表示されました
今度はルーティングテーブルの確認をします
(Network Namespaceを使用しない場合)
ip route show
default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
10.0.2.2 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric 100
続いて、
(Network Namespace環境の場合)
$ sudo ip netns exec practice ip route show
Error: ipv4: FIB table does not exist.
Dump terminated
このエラーから、ルーティングテーブルが存在しないことが確認できます
Network Namespaceへルーティングエントリを登録していないためです
実際に繋いでみる
2つのNetwork Namespaceを繋いでみます。
仮想的なネットワーク環境が2つあるようにイメージします。そのネットワークを仮想的なLANケーブルで繋いでみます。
まずは、それぞれのネットワークを作成します
$ sudo ip netns add practice1
$ sudo ip netns add practice2
$ sudo ip netns list
practice2
practice1
作成したネットワーク同士を繋ぎます
$ sudo ip link add practice1-veth0 type veth peer name practice2-veth0
$ ip link show | grep veth
3: practice2-veth0@practice1-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
4: practice1-veth0@practice2-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
practice1-veth0
、practice2-veth0
は作成するネットワークインターフェイスの名前です。
ip link show | grep veth
から無事作成できていることが確認できます
しかし、現状は作成したvethインターフェイスはNetwork Namespaceで使用できないため使えるようにしていきます
そのためにシステム領域 → Network Namespace領域へ移す必要があります
$ sudo ip link set practice1-veth0 netns practice1
$ sudo ip link set practice2-veth0 netns practice2
これで、vethインターフェイスがNetwork Namespaceで使用できるようになりました
$ ip link show | grep veth
システム側ではもう確認できないことが分かります
Network Namespace側で確認してみます
$ sudo ip netns exec practice1 ip link show | grep veth
4: practice1-veth0@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
$ sudo ip netns exec practice2 ip link show | grep veth
3: practice2-veth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
これで、Network Namespace同士が仮想的なLANケーブルにつながりました。
しかし、これだけでは通信が出来ないので設定を行なっていきます
通信の設定
IPを使用して通信を行うためにvethインターフェイスにIPアドレスを付与します
$ sudo ip netns exec practice1 ip address add 192.0.2.1/24 dev practice1-veth0
$ sudo ip netns exec practice2 ip address add 192.0.2.2/24 dev practice2-veth0
これでIPアドレスの付与が出来ました
これで、通信ができる?
$ sudo ip netns exec practice1 ip link show practice1-veth0 | grep state
4: practice1-veth0@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
$ sudo ip netns exec practice2 ip link show practice2-veth0 | grep state
3: practice2-veth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
まだ出来ないみたいです。
ネットワークインタフェースがstate DOWN
になっています。
ネットワークインターフェースは初期状態ではDOWNになっていて通信が出来ないようです
ネットワークインターフェースのリンクをUP
へ変更し、通信ができるようにします
$ sudo ip netns exec practice1 ip link set practice1-veth0 up
$ sudo ip netns exec practice2 ip link set practice2-veth0 up
ここまで来れば、pingコマンドで疎通の確認をしてみます
$ sudo ip netns exec practice1 ping -c 3 192.0.2.2
PING 192.0.2.2 (192.0.2.2) 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=2.19 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.056 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.054 ms
--- 192.0.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2022ms
rtt min/avg/max/mdev = 0.054/0.765/2.185/1.004 ms
これで、TCP/IP環境が出来上がりました
practice1 → practice2 へpingで疎通確認を行なってみます
$ sudo ip netns exec practice1 ping -c 3 192.0.2.2 -I 192.0.2.1
PING 192.0.2.2 (192.0.2.2) from 192.0.2.1 : 56(84) bytes of data.
64 bytes from 192.0.2.2: icmp_seq=1 ttl=64 time=0.033 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.044 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.043 ms
--- 192.0.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 0.033/0.040/0.044/0.005 ms
-I
オプションの後の、192.0.2.1
が送信元のIPアドレスです。
返答がある事を確認できました
ルータは必要ないのか?
ここまでの構築では ルータを使用することなくIPを使ったネットワークが構築出来ました。
ルータ無しでなぜ通信が出来たのか?
それは、IPで構築されたネットワークのセグメントが関係しています
同じセグメントに属するIP同士はルータがなくても互いに通信を行うことが出来ます
セグメント・・・ネットワーク部とホスト部を識別するためにあります。
例えば、192.0.2.1/24
のIPアドレスの場合は192.0.2.0
がネットワークアドレスになります
ネットワーク部(192.0.2
)が同じIPアドレスは、同じセグメントに属しているということになります
先ほど構築したvethインターフェイスを例にとってみます。
/24
。つまり、先頭から24bitなので赤字の部分がネットワーク部になります。
両方に同じセグメントのIPが振られているのでルータがなくても通信が可能になります
実際にルータを入れてみる
ルータを使用したネットワークを作成します。
ルータがあるということは、セグメントが2つになります
構成図は以下です。
ルータを合わせたNetwork namespaceが1つ増えて3つになりました。
ここでは、セグメントを跨いだ通信をします。
つまり、間にルータがある状態でpractice1とpractice2の間をパケット通信してみます
実際にネットワークを作っていく
最初に作成したネットワークをまずは消しておきます
$ sudo ip list
practice1
practice2
listで確認してから先ほど作成したnetwork namespaceを全て削除します
$ sudo ip --all netns delete
ルータも含めた3つのnetwork namespace を作成します
$ sudo ip netns add practice1
$ sudo ip netns add practice2
$ sudo ip netns add router
$ sudo ip netns list
router
practice2
practice1
続いて、インターフェースを作成します
セグメント | practice | ルータ側 |
---|---|---|
1 | practice1-veth0 | gw-veth0 |
2 | practice2-veth0 | gw-veth1 |
$ sudo ip link add practice1-veth0 type veth peer name gw-veth0
$ sudo ip link add practice2-veth0 type veth peer name gw-veth1
それぞれのNetWork Namespace へインターフェースを所属させて、UPします
NetWork Namespace | インターフェース |
---|---|
practice1 | practice1-veth0 |
router | gw-veth0 & gw-veth1 |
practice2 | practice2-veth0 |
$ sudo ip link set practice1-veth0 netns practice1
$ sudo ip link set gw-veth0 netns router
$ sudo ip link set gw-veth1 netns router
$ sudo ip link set practice2-veth0 netns practice2
vagrant@ubuntu-focal:~$ sudo ip netns exec practice1 ip link set practice1-veth0 up
vagrant@ubuntu-focal:~$ sudo ip netns exec router ip link set gw-veth0 up
vagrant@ubuntu-focal:~$ sudo ip netns exec router ip link set gw-veth1 up
vagrant@ubuntu-focal:~$ sudo ip netns exec practice2 ip link set practice2-veth0 up
続いて、IPアドレスの設定を行います
Network Namespace | IPアドレス | インターフェース |
---|---|---|
practice1 | 192.0.2.1/24 | practice1-veth0 |
router | 192.0.2.254/24 | gw-veth0 |
router | 192.51.100.254/24 | gw-veth1 |
practice2 | 192.51.100.1/24 | practice2-veth0 |
practice1とrouter間の設定を行います。
それぞれのインターフェースに同セグメントのIPを当てます
$ sudo ip netns exec practice1 ip address add 192.0.2.1/24 dev practice1-veth0
$ sudo ip netns exec router ip address add 192.0.2.254/24 dev gw-veth0
$ sudo ip netns exec router ip address add 192.51.100.254/24 dev gw-veth1
$ sudo ip netns exec practice2 ip address add 192.51.100.1/24 dev practice2-veth0
ここまでできれば、practice1 - router 間の疎通確認を行います
$ sudo ip netns exec practice1 ping -c 3 192.0.2.254 -I 192.0.2.1
PING 192.0.2.254 (192.0.2.254) from 192.0.2.1 : 56(84) bytes of data.
64 bytes from 192.0.2.254: icmp_seq=1 ttl=64 time=2.78 ms
64 bytes from 192.0.2.254: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 192.0.2.254: icmp_seq=3 ttl=64 time=0.047 ms
--- 192.0.2.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.047/0.959/2.782/1.289 ms
practice2 - router 間も同様に
$ sudo ip netns exec practice2 ping -c 3 192.51.100.254 -I 192.51.100.1
PING 192.51.100.254 (192.51.100.254) from 192.51.100.1 : 56(84) bytes of data.
64 bytes from 192.51.100.254: icmp_seq=1 ttl=64 time=1.79 ms
64 bytes from 192.51.100.254: icmp_seq=2 ttl=64 time=0.047 ms
64 bytes from 192.51.100.254: icmp_seq=3 ttl=64 time=0.048 ms
--- 192.51.100.254 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2008ms
rtt min/avg/max/mdev = 0.047/0.627/1.786/0.819 ms
続いて、セグメントを超えた通信が可能か試してみます。
practice1 → practice2 へpingで疎通確認してみます
$ sudo ip netns exec practice1 ping -c 3 4/24 dev gw-veth1 192.51.100.1 -I 192.0.2.1
ping: 4/24: Temporary failure in name resolution
しかし、先ほどと同じ方法では疎通に失敗してしまいました。
Network Namespaceにルーティングの設定が必要になります
現状のNetwork Namespaceのルーティングを確認してみます
$ sudo ip netns exec practice1 ip route show
192.0.2.0/24 dev practice1-veth0 proto kernel scope link src 192.0.2.1
practice1にはルーティングエントリーが1つあります。
内容は、practice1-veth0というインターフェイスで192.0.2.0/24
宛に通信を行うとあるので、
practice1と、practice2は直接はつながっていません
どうすればいいのか?🤔
ルーティングテーブルに新たにルーティングエントリを追加する必要があります
ルーティングエントリとして、デフォルトルート(すべてのルートを表す) を追加します
practice1にデフォルトルートを追加します
$ sudo ip netns exec practice1 ip route add default via 192.0.2.254
$ sudo ip netns exec practice1 ip route show
default via 192.0.2.254 dev practice1-veth0
192.0.2.0/24 dev practice1-veth0 proto kernel scope link src 192.0.2.1
192.0.2.254はルータのipアドレスで、デフォルトルートをルータに向けました
practice2にも、同様にデフォルトルートとなるルーティングエントリを追加します
$ sudo ip netns exec practice2 ip route add default via 192.51.100.254
$ sudo ip netns exec practice2 ip route show
default via 192.51.100.254 dev practice2-veth0
192.51.100.0/24 dev practice2-veth0 proto kernel scope link src 192.51.100.1
ここまで来れば、再度、practice1 → practice2への疎通確認をしてみます
~$ sudo ip netns exec practice1 ping -c 3 198.51.100.1 -I 192.0.2.1
PING 198.51.100.1 (198.51.100.1) from 192.0.2.1 : 56(84) bytes of data.
--- 198.51.100.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2035ms
エラーは出ませんでしたが、100% packet loss
とあるように返答が無かったみたいです
ipフォワードの設定が必要になります
ここで、「IPフォワード」という技術が用意されています。この技術は、その名の通り、2つのNICの間でパケットを転送するという技術です。これにより、パケットが異なるネットワークの間を往き来できるようになります。
LinuxでIPフォワードを有効にするには、「/etc/sysctl.conf」ファイルに、「net.ipv4.ip_forward=1」という記述を行い(デフォルトではnet.ipv4.ip_forward=0)、ネットワークを再起動します。
https://linuc.org/study/knowledge/422/
$ sudo ip netns exec router sysctl net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
これでもう一度試してみます
$ sudo ip netns exec practice1 ping -c 3 198.51.100.1 -I 192.0.2.1
PING 198.51.100.1 (198.51.100.1) from 192.0.2.1 : 56(84) bytes of data.
From 192.0.2.254 icmp_seq=1 Destination Net Unreachable
From 192.0.2.254 icmp_seq=2 Destination Net Unreachable
From 192.0.2.254 icmp_seq=3 Destination Net Unreachable
--- 198.51.100.1 ping statistics ---
3 packets transmitted, 0 received, +3 errors, 100% packet loss, time 2031ms
今度は疎通が出来ました
おしまい
参考