概要
Linuxには名前空間(Namespace)というカーネルの機能が提供されています。
これは1つのプロセスが1つのリソースセットを参照し、別のプロセスが異なるリソースセットを参照するようにカーネルリソースを分割する機能です。
その中の1つであるネットワーク名前空間(Network Namespace)の機能を学んでみます。
環境
- Ubuntu 18.04
ip netnsを使ってみる
初期状態
デフォルトのUbuntuでは以下のように2つのNICが存在します。
- lo
- enp0s3
コマンドで確認します。
$ ip l 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff
図では以下のような状態です。
ネットワーク名前空間を作る
host1
というネットワーク名前空間を作ります。
ip netns add
で作ります。
$ sudo ip netns add host1 $ ip netns l host1
ここで作成された名前空間にはループバックインタフェースのみが存在します。
ネットワーク名前空間の中に入ってみる
ip netns exec
で中に入ることができます。
vagrant@ubuntu-bionic:~$ sudo ip netns exec host1 bash
root@ubuntu-bionic:~#
プロンプトが変わっていることが分かりますね。中のNICを確認すると、先ほどの図の通りループバックのlo
が存在します。
root@ubuntu-bionic:~# ip l 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
ただ初期状態ではDOWNしているのでifconfig
では見えません。
先ほどの図でlo
が点線だったのはそのためです。
root@ubuntu-bionic:~# ifconfig root@ubuntu-bionic:~#
ping
を打ってもunreachableが返ります。
root@ubuntu-bionic:~# ping 127.0.0.1 connect: Network is unreachable
なのでNICをUP状態にします。
root@ubuntu-bionic:~# ip link set lo up root@ubuntu-bionic:~# ping 127.0.0.1 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.018 ms
ping
も返るようになりました。
ホストLinuxと疎通させる
このままだと何も通信できないので、ホストLinuxと疎通できるようにします。
ホストLinux側で以下のようにip link add
でveth
を用意します。
$ sudo ip link add name veth1 type veth peer name host1-veth1 $ ip l 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff 3: host1-veth1@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether c6:fc:67:d3:45:bc brd ff:ff:ff:ff:ff:ff 4: veth1@host1-veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 76:40:af:6f:eb:67 brd ff:ff:ff:ff:ff:ff
name veth1
やpeer name host1-veth1
はオプションなので省略しても問題ありません。今回はveth1
やhost1-veth1
といった分かりやすい名前を付けたかったのでオプションで指定しています。
図で表すとこの状態です。
vethのピアをネットワーク名前空間へ
先ほど作ったvethのピアhost1-veth1
をhost1
へバインドします。
$ sudo ip link set host1-veth1 netns host1
$ ip l 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff 4: veth1@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 76:40:af:6f:eb:67 brd ff:ff:ff:ff:ff:ff link-netnsid 0
host1
に入って確認してみると、先ほどのNICが存在しています。
$ sudo ip netns exec host1 bash root@ubuntu-bionic:~# ip l 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 3: host1-veth1@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether c6:fc:67:d3:45:bc brd ff:ff:ff:ff:ff:ff link-netnsid 0
図で表すと以下の状態です。
IPアドレスを付与
互いに通信できるよう、
- 同一サブネットにする
- お互いのIPは重複しないようにする
の2点に注意してください。
今回はサブネットを10.0.0.0/24
として付与していきます。
ホストLinux
IPアドレス10.0.0.1
を付与。サブネットマスクは/24(255.255.255.0)
で。
$ sudo ip addr add 10.0.0.1/24 dev veth1
NICをUP。
$ sudo ip link set veth1 up $ ip a 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:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83214sec preferred_lft 83214sec inet6 fe80::b7:1fff:fe33:e924/64 scope link valid_lft forever preferred_lft forever 4: veth1@if3: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN group default qlen 1000 link/ether 76:40:af:6f:eb:67 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.0.0.1/24 scope global veth1 valid_lft forever preferred_lft forever
ネットワーク名前空間host1
IPアドレス10.0.0.2
を付与。サブネットマスクは/24(255.255.255.0)
で。
# ip addr add 10.0.0.2/24 dev host1-veth1
NICをUP。
# ip link set host1-veth1 up # ip a 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 3: host1-veth1@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether c6:fc:67:d3:45:bc brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.0.0.2/24 scope global host1-veth1 valid_lft forever preferred_lft forever inet6 fe80::c4fc:67ff:fed3:45bc/64 scope link valid_lft forever preferred_lft forever
図で表すと以下です。
動作確認
ホストLinuxからhost1
へのping
10.0.0.1
から10.0.0.2
です。
vagrant@ubuntu-bionic:~$ ping 10.0.0.2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.020 ms
疎通できてますね。
host1
からホストLinuxへのping
10.0.0.2
から10.0.0.1
です。
root@ubuntu-bionic:~# ping 10.0.0.1 PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. 64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms
こちらも疎通できてますね。
その他
ネットワーク名前空間はホストLinuxを再起動すると消えてなくなります。
なので再起動しても同じような環境を用意したい場合、ブート時に名前空間を作成するスクリプトを用意する必要があります。
まとめ
ip netns
コマンドを使ってネットワーク名前空間について検証してみました。
これに加えてbridgeやiptablesを用いたNATなどを駆使するとdockerと同じような状態を構築することが可能です。