Network ネットワーク関連

Networkのnamespaceを試す場合は、ip netnsを使うほうが分かりやすいです。vethはL2の仮想ネットワークインタフェースで、2つのインタフェースのペアを作成してくれるものでnamespaceをまたがって通信できるようになります。

操作とコマンド実行例は以下のようになります。

操作 コマンド
名前空間の作成 ip netns add 名前空間名
名前空間の一覧 ip netns list
名前空間の削除 ip netns delete 名前空間名
名前空間内でコマンド実行 ip netns exec 名前空間名 コマンド
名前空間内のプロセスID ip netns pids 名前空間名
vethの作成 ip link add name NIC1つ目 type veth peer name NIC2つ目
NICに割り当てるIPの範囲 ip addr add 割り当てるIPの範囲 dev NIC名
NICを立ち上げる ip link set NIC名 up
デフォルトゲートウェイの指定 ip route add default via ゲートウェイIP dev 使用するNIC

ip以外の関連するコマンドとしては、以下があります。IPマスカレードを有効にする方法はiptablesでもかまいません。

操作 コマンド
IPフォワードの有効化 sysctl -w net.ipv4.ip_forward=1
IPマスカレードの有効化 /firewalld iptables --table nat --append POSTROUTING --source 有効化するIPの範囲 --jump MASQUERADE

testns1とtestns2の2つのnamespaceを作って動きを確認してみます。

# ip netns add testns1 # 名前空間の作成
# ip netns add testns2
# ip netns list # 名前空間の一覧
testns2
testns1

次に、vethを作ってnamespaceにひもづけます。m1とs1のペアを作ってs1をtestns1に、m2とs2のペアを作ってs2をtestns2にひもづけています。

# ip link add name m1 type veth peer name s1 # vethの作成
# ip link add name m2 type veth peer name s2
# ip -d link show s1
3: s1@m1:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:56:02:e4:d7:b9 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535
    veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
# ip -d link show m1
4: m1@s1:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether d2:32:b1:dc:bf:be brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535
    veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
# ip link set dev s1 netns testns1 # s1を名前空間testns1にひもづける
# ip link set dev s2 netns testns2 # s2を名前空間testns1にひもづける

m1とs1がnamespaceをまたいでつながったままになっていることを確認してみましょう。

# ip netns exec testns1 ip link
1: lo:  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
3: s1@if4:  mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 46:56:02:e4:d7:b9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
# ethtool -S m1
NIC statistics:
     peer_ifindex: 3
     rx_queue_0_xdp_packets: 0
     rx_queue_0_xdp_bytes: 0
     rx_queue_0_xdp_drops: 0

IPアドレスを割り当てていきます。

dev namespace ip address
m1 168.20.101/24
s1 testns1 192.168.20.102/24
m2 168.10.101/24
s2 testns2 192.168.10.102/24

ip netns exec testns1 ip addr add 192.168.20.102/24 dev s1
ip netns exec testns1 ip link set dev s1 up
ip netns exec testns1 ip link set dev lo up
ip netns exec testns1 ip addr show dev s1
ip addr add 192.168.20.101/24 dev m1
ip link set dev m1 up
ip addr show dev m1
ip netns exec testns1 ip route add default via 192.168.20.101 dev s1

ip netns exec testns2 ip addr add 192.168.10.102/24 dev s2
ip netns exec testns2 ip link set dev s2 up
ip netns exec testns2 ip link set dev lo up
ip netns exec testns2 ip addr show dev s2
ip addr add 192.168.10.101/24 dev m2
ip link set dev m2 up
ip addr show dev m2
ip netns exec testns2 ip route add default via 192.168.10.101 dev s2

作成したnamespace testns1からip netns exec testns1 ping 宛先を打って通信可能かを確認します。この段階では、testns1からtestns2のs2のIPには通信できないという結果になるはずです。


OK from testns1 ping to 192.168.20.101
OK from testns1 ping to 192.168.20.102
OK from testns1 ping to 192.168.10.101
NG from testns1 ping to 192.168.10.102
OK from host ping to 192.168.20.101
OK from host ping to 192.168.20.102
OK from host ping to 192.168.10.101
OK from host ping to 192.168.10.102

ホスト側にはtestns1とtestns2の双方の経路情報があります。

# ip route
default via 116.80.89.1 dev ens10 proto static
116.80.89.0/24 dev ens10 proto kernel scope link src 116.80.89.195
192.168.10.0/24 dev m2 proto kernel scope link src 192.168.10.101
192.168.20.0/24 dev m1 proto kernel scope link src 192.168.20.101

そのため、IPフォワードを有効にすると、testns1とtestns2の通信ができるようになります。sysctl -w net.ipv4.i_forward=1を実行してから再度、pingを打つと以下の結果になります。


OK from testns1 ping to 192.168.20.101
OK from testns1 ping to 192.168.20.102
OK from testns1 ping to 192.168.10.101
OK from testns1 ping to 192.168.10.102

インターネットに出るために、IPマスカレードを設定します。これでtestns1からインターネットに出ることができるようになります。

# iptables --table nat --append POSTROUTING --source 192.168.20.102/24 --jump MASQUERADE
# iptables --table nat --list
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  192.168.20.0/24      anywhere

# ip netns exec testns1 curl "http://142.251.42.131" # Googleから応答が返る
# ip netns exec testns2 curl "http://142.251.42.131" # Googleから応答が返らない

User ユーザー/グループ、権限

Userのnamespaceは、後発のnamespaceで利用できるようになり始めたという段階のものです。試してみる場合のお手軽な使い方は、unshare -U -rを指定する方法です。unshareの外からはunshareの実行ユーザーの操作のように見えるものが、unshareの中からはrootの操作に見えます。


mkdir /home/ubuntu/container
cd /home/ubuntu/container
unshare -U -r /bin/bash
id # uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
touch hoge
ll # -rw-rw-r-- 1 root root    0 Oct 17 07:23 hoge
exit
cd /home/ubuntu/container
ll # -rw-rw-r-- 1 ubuntu ubuntu    0 Oct 17 07:23 hoge

uidとgidを割り当てる場合は、/proc/unshareのPID/uid_mapと/proc/unshareのPID/gid_mapにプロセス内のマッピングルールを記載します。


(名前空間内の最初のID) (名前空間外の最初のID) (名前空間内で使用するIDの個数)

initのuid_mapとgid_mapは、以下のように定義されています。

# cat /proc/1/uid_map
         0          0 4294967295
# cat /proc/1/gid_map
         0          0 4294967295