Namespace の学習

Linux の Namespace を学んだときの自分用ログ。実施しているきっかけは、Kubernetes のネットワーク周りをしっかり勉強しようと思ったのだけど、そのためには Docker のネットワークをしっかり学ぶ必要があり、Docker といえば Namespace だよね！ということで、壮大なヤクの毛狩りの結果、ちゃんと根本から勉強しようと腹をくくることにしました。

実際は超素晴らしい　[ip netnsコマンドの使い方（ネットワークの実験の幅が広がるなぁ～](https://qiita.com/hana_shin/items/ab078b5552f5df029030)を WSL2 で流して実験するだけなので、素晴らしい元記事を読んでいいねしてくださるとよいと思います。

基本的には、`ip` コマンドを使って、Namespace を使ったり、ネットワークを作ってみたりします。

# ip コマンド

私の Linux の知識が古すぎて `ifconfig` とばかり思っていましたが、現在では `ip` コマンドです。様々なことが出来るので見ていきましょう。

```bash
$ ip help
Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }
       ip [ -force ] -batch filename
where  OBJECT := { link | address | addrlabel | route | rule | neigh | ntable |
                   tunnel | tuntap | maddress | mroute | mrule | monitor | xfrm |
                   netns | l2tp | fou | macsec | tcp_metrics | token | netconf | ila |
                   vrf | sr | nexthop }
       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |
                    -h[uman-readable] | -iec | -j[son] | -p[retty] |
                    -f[amily] { inet | inet6 | mpls | bridge | link } |
                    -4 | -6 | -I | -D | -M | -B | -0 |
                    -l[oops] { maximum-addr-flush-attempts } | -br[ief] |
                    -o[neline] | -t[imestamp] | -ts[hort] | -b[atch] [filename] |
                    -rc[vbuf] [size] | -n[etns] name | -N[umeric] | -a[ll] |
                    -c[olor]}
```

#  環境
ただし、環境は、Windows 10 の WSL2 です。最近面倒なのでこの環境を使うことが多いですが、制限がないかちょっと心配。

```
$ cat /etc/os-release   # or lsb-release
NAME="Ubuntu"
VERSION="20.04 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```

# オプション一覧

`ip netns` がネットワーク関連のネームスペース関連のコマンドです。ネームスペースを指定することによって、プロセスや、ユーザーや、ネットワークを隔離して管理することができます。このネームスペースや、cgroupをうまく使っているのが Docker のようなコンテナ技術です。この記事がわかりやすかったです。[第2回　コンテナの仕組みとLinuxカーネルのコンテナ機能［1］名前空間とは？](https://gihyo.jp/admin/serial/01/linux_containers/0002?page=1) そして [第3回　Linuxカーネルのコンテナ機能［2］ ─cgroupとは？（その1）](https://gihyo.jp/admin/serial/01/linux_containers/0003?page=1)も cgroupの概要をつかむための良い記事でした。

```bash
$ ip netns help
Usage:  ip netns list
        ip netns add NAME
        ip netns attach NAME PID
        ip netns set NAME NETNSID
        ip [-all] netns delete [NAME]
        ip netns identify [PID]
        ip netns pids NAME
        ip [-all] netns exec [NAME] cmd ...
        ip netns monitor
        ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT]
NETNSID := auto | POSITIVE-INT
```

# ネームスペースの追加
WSL2 の環境では、sudo が必要でした。

```bash
$ sudo ip netns add test1
[sudo] password for ushio: 
$ sudo ip netns add test2
```

#  ネームスペースのリスト

```bash
$ ip netns list
test2
test1
```

# ネームスペースの削除

## すべてのネームスペースの削除

```bash
$ sudo ip -all netns del
```

## 個別の削除

```bash
$ sudo ip netns delete test1
```

# ネームスペース内でのプロセスの実行

ネームスペース内で`bash` を実行してみます。ネットワークのインターフェイスも母艦とは別のものになっています。

```bash
$ sudo ip netns exec test1 bash# ps
  PID TTY          TIME CMD
31284 pts/3    00:00:00 sudo
31285 pts/3    00:00:00 bash
# ip link
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
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
```

# プロセス関連のコマンド

ターミナル１で、bash を実行して、nc コマンドを実行してみます。nc はネットワークの調査で便利なコマンドで、下記のはポート11111でリッスンしています。`-l` は、リッスンするオプションであり、他の場合は、メッセージを送信します。`-k` は、コネクションがクローズした後も、次のコネクションを待ち受けます。

* [nc コマンド 使い方メモ](https://qiita.com/yasuhiroki/items/d470829ab2e30ee6203f)

```:ターミナル1
$ tty
/dev/pts/3
$ sudo ip netns exec test1 bash
# nc -kl 11111
```

違うターミナルからこのプロセスを見てみます。`tty` は現在使っているターミナルに割り当てられているデバイスファイルを表示しています。`ps -C nc` で、`nc` コマンドを実行しているプロセスを表示します。別のネームスペースで実行しているプロセスでも、`ps aux` 等であれば見ることが出来ます。

```:ターミナル2
$ tty
/dev/pts/5
$ ps -C nc
  PID TTY          TIME CMD
31343 pts/3    00:00:00 nc
```

ちなみにネームスペースから、aux コマンドを実行しても結果は同じです。この辺は docker と違いを感じます。

```:ターミナル2
$ sudo ip netns exec test1 bash
# ps
  PID TTY          TIME CMD
31416 pts/5    00:00:00 sudo
31417 pts/5    00:00:00 bash
31424 pts/5    00:00:00 ps
# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0    896   576 ?        Sl   Feb27   0:00 /init
root        11  0.0  0.0    896    88 ?        S    Feb27   0:00 /init
root     27172  0.3  2.5 9125368 156384 ?      Sl   Feb27   5:35 /usr/bin/dockerd -p /var/run/docker.pid
root     27194  0.3  0.9 2369808 56864 ?       Ssl  Feb27   5:37 containerd --config /var/run/docker/containerd/containerd.toml --log-level info
root     27677  0.0  0.0    904    88 ?        Ss   07:14   0:00 /init
root     27678  0.0  0.0    904    96 ?        S    07:14   0:00 /init
ushio    27679  0.0  0.0   2608   540 pts/1    Ss+  07:14   0:00 sh -c "$VSCODE_WSL_EXT_LOCATION/scripts/wslServer.sh" 622cb03f7e070a9670c94bae1a45d78d7181fbd4 stable .vscode-server 0  
ushio    27680  0.0  0.0   2608  1796 pts/1    S+   07:14   0:00 sh /mnt/c/Users/tsushi/.vscode/extensions/ms-vscode-remote.remote-wsl-0.53.4/scripts/wslServer.sh 622cb03f7e070a9670c94bae1a45d78d7181fbd4 stable .vs
ushio    27685  0.0  0.0   2608   596 pts/1    S+   07:14   0:00 sh /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/server.sh  --port=0 --use-host-proxy --enable-remote-auto-shutdown --print
ushio    27687  0.1  1.2 1022480 76736 pts/1   Rl+  07:14   0:23 /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/node /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/
ushio    27723  0.0  0.6 856768 40184 pts/1    Sl+  07:14   0:00 /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/node /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/
ushio    27777  0.0  1.3 943272 83604 pts/1    Sl+  07:14   0:08 /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/node /home/ushio/.vscode-server/bin/622cb03f7e070a9670c94bae1a45d78d7181fbd4/
ushio    27784  0.0  0.0  10128  5036 pts/3    Ss   07:14   0:00 /bin/bash
ushio    31210  0.0  0.0  10132  5328 pts/5    Ss   10:08   0:00 /bin/bash
root     31317  0.0  0.0  11008  4520 pts/3    S    10:14   0:00 sudo ip netns exec test1 bash
root     31318  0.0  0.0   8960  3908 pts/3    S    10:14   0:00 bash
root     31343  0.0  0.0   3252   764 pts/3    S+   10:20   0:00 nc -kl 11111
ushio    31346  0.0  0.0  10236  5308 pts/6    Ss   10:21   0:00 /bin/bash
ushio    31395  0.0  0.0   8788  3924 pts/6    S+   11:14   0:00 man nc
ushio    31405  0.0  0.0   7596  2232 pts/6    S+   11:14   0:00 pager
root     31416  0.0  0.0  11008  4592 pts/5    S    11:19   0:00 sudo ip netns exec test1 bash
root     31417  0.0  0.0   8960  4000 pts/5    S    11:19   0:00 bash
root     31425  0.0  0.0  10600  3256 pts/5    R+   11:19   0:00 ps aux
```

このプロセスIDがどのネームスペースに所属しているか見てみます。

```:ターミナル2
$ sudo ip netns identify 31343
test1
```

Bash の実行状況を観ます。tty のパートでわかるように、ターミナル１で動いているbash は２つあって、一つが、ネームスペースで実行したものです。

```:ターミナル2
$ ps -C bash -o comm,pid,lstart,tty
COMMAND           PID                  STARTED TT
bash            27784 Sun Feb 28 07:14:05 2021 pts/3
bash            31210 Sun Feb 28 10:08:49 2021 pts/5
bash            31318 Sun Feb 28 10:14:36 2021 pts/3
bash            31346 Sun Feb 28 10:21:08 2021 pts/6
```
それは次の比較でわかります。

```:ターミナル2
$ sudo ip netns identify 31318
test1
$ sudo ip netns identify 27784
```

# ホスト、ルーターの環境構築

実際やりたかったのはこのパートです。WSL2 で動くかな？もともと CKA のコースを受けていた時に、このコマンドの紹介があったのですが、その通りに WSL2 で動かなかったので気になってここでやっている感じです。まずは元のブログ通りの環境を作ってみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470/58a11088-068b-d342-026e-9ec1452a9fbc.png)

## ネームスペースの作成

```bash
$ sudo ip netns add host1
$ sudo ip netns add host2
$ sudo ip netns add router
$ sudo ip netns list
router
host2
host1
```

## インターフェイスの作成

仮想のネットワークインターフェイスを作成して、対向のネットワークインターフェイスを指定します。もちろん最初なので、DOWN したままです。

```bash
$ sudo ip link add name veth-h1 type veth peer name veth1-rt
$ sudo ip link add name veth-h2 type veth peer name veth2-rt
$ sudo ip link | grep veth
76: veth1-rt@veth-h1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
77: veth-h1@veth1-rt: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
78: veth2-rt@veth-h2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
79: veth-h2@veth2-rt: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
```

## ネームスペースをネットワークインターフェイスに割り当てる

`host`, `host2`, `router` にインターフェスを割り当てます。

```bash
$ sudo ip link set veth-h1 netns host1
$ sudo ip link set veth-h2 netns host2
$ sudo ip link set veth1-rt netns router
$ sudo ip link set veth2-rt netns router
```

## IP アドレスの割り当て

```bash
$ sudo ip netns exec host1 ip addr add 192.168.100.10/24 dev veth-h1
$ sudo ip netns exec host2 ip addr add 192.168.200.10/24 dev veth-h2
$ sudo ip netns exec router ip addr add 192.168.100.20/24 dev veth1-rt
$ sudo ip netns exec router ip addr add 192.168.200.20/24 dev veth2-rt
```

## インターフェイスの UP

```bash
$ sudo ip netns exec host1 ip link set veth-h1 up
$ sudo ip netns exec host2 ip link set veth-h2 up
$ sudo ip netns exec router ip link set veth1-rt up
$ sudo ip netns exec router ip link set veth2-rt up
```

確認すると、正しく設定されています。

```bash
$ sudo ip netns exec host1 ip a
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
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
77: veth-h1@if76: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether aa:9c:34:e9:11:2f brd ff:ff:ff:ff:ff:ff link-netns router
    inet 192.168.100.10/24 scope global veth-h1
       valid_lft forever preferred_lft forever
    inet6 fe80::a89c:34ff:fee9:112f/64 scope link 
       valid_lft forever preferred_lft forever
$ sudo ip netns exec host2 ip a
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
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
79: veth-h2@if78: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether e6:d6:9a:c7:0e:60 brd ff:ff:ff:ff:ff:ff link-netns router
    inet 192.168.200.10/24 scope global veth-h2
       valid_lft forever preferred_lft forever
    inet6 fe80::e4d6:9aff:fec7:e60/64 scope link 
       valid_lft forever preferred_lft forever
$ sudo ip netns exec router ip a
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
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/sit 0.0.0.0 brd 0.0.0.0
76: veth1-rt@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 2e:8d:45:ae:d7:b4 brd ff:ff:ff:ff:ff:ff link-netns host1
    inet 192.168.100.20/24 scope global veth1-rt
       valid_lft forever preferred_lft forever
    inet6 fe80::2c8d:45ff:feae:d7b4/64 scope link 
       valid_lft forever preferred_lft forever
78: veth2-rt@if79: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 9e:80:da:c0:3c:2f brd ff:ff:ff:ff:ff:ff link-netns host2
    inet 192.168.200.20/24 scope global veth2-rt
       valid_lft forever preferred_lft forever
    inet6 fe80::9c80:daff:fec0:3c2f/64 scope link 
       valid_lft forever preferred_lft forever
```

## ルーティングテーブルの設定

この手順が前に試したときに抜けていたと思います。`ip_forward` の設定をしないと、デフォルトでは、IPフォワードをしない設定になっています。

```bash
$ sudo ip netns exec host1 ip route add 192.168.200.0/24 via 192.168.100.20 dev veth-h1
$ sudo ip netns exec host2 ip route add 192.168.100.0/24 via 192.168.200.20 dev veth-h2
$ sudo ip netns exec router sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
```

### Ping 

きっちり動作しています。

```bash
$ sudo ip netns exec host1 ping  192.168.200.10
PING 192.168.200.10 (192.168.200.10) 56(84) bytes of data.
64 bytes from 192.168.200.10: icmp_seq=1 ttl=63 time=0.055 ms
64 bytes from 192.168.200.10: icmp_seq=2 ttl=63 time=0.065 ms
64 bytes from 192.168.200.10: icmp_seq=3 ttl=63 time=0.056 ms
64 bytes from 192.168.200.10: icmp_seq=4 ttl=63 time=0.057 ms
```

## ルーター機能の確認

[tcpdump]() を使ってルーター機能が正常に動いているか確認します。

```:ターミナル１
$ sudo ip netns exec router tcpdump -i veth1-rt icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1-rt, link-type EN10MB (Ethernet), capture size 262144 bytes
```

Ping を１回送ります。

```:ターミナル2
$sudo ip netns exec host1 ping -c 1 192.168.200.10
```

しっかりと、tcpdump で観察できます。

```:ターミナル１
$sudo ip netns exec router tcpdump -i veth1-rt icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1-rt, link-type EN10MB (Ethernet), capture size 262144 bytes
11:54:38.197299 IP 192.168.100.10 > 192.168.200.10: ICMP echo request, id 31512, seq 1, length 64
```

次に、iptable を使って確認します。router の IPテーブルに icmp をフォワードします。

```:ターミナル1
$ sudo ip netns exec router bash
# iptables -A FORWARD -p icmp
# iptables -nvL FORWARD
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0            icmp --  *      *       0.0.0.0/0            0.0.0.0/0      
```

１回Pingを送ると、値が変わります。

```:ターミナル2     
$ sudo ip netns exec host1 ping -c 1 192.168.200.10
```

```:ターミナル1
# iptables -nvL FORWARD
Chain FORWARD (policy ACCEPT 2 packets, 168 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    2   168            icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
```

同じブログの方が素晴らしいブログを書いてくれています。iptable や tpcdump についても学ばねばですが、先にもとにやってたことに戻ります。ネットワークはマジ奥深い。コントロール配下に置きたいところ。

* [tcpdumpの使い方](https://qiita.com/hana_shin/items/385182b05db96ef4e205)
* [iptablesの使い方](https://qiita.com/hana_shin/items/956dfaca4539ba257c16)