【Linux】 Network Namespace

# はじめに

知識のアウトプット用として書いておこうと思いました。
Dockerといったコンテナ型仮想化技術を構成する要素の1つが`Network Namespace`
コマンドライン操作を必要とするだけで、ネットワーク的にシステムから独立した仮想的なコンピュータを作成できる。

Ubuntu 18.04 LTS を起動させる。
ターミナルにて次のコマンドを入力する。
これは後続の作業に必要なパッケージをインストールするためのコマンド。
これにより必要なパッケージをインストールできる。

```ruby:ターミナル
$ sudo apt-get update
$ sudo apt-get -y install
```



### TCP/IPとは

>TCP(Transmission Control Protocol)
IP(Internet Protocol)

日常的に利用しているプロトコルの名称。

- 「運送会社がお客さんの荷物を目的地まで届ける」
- 「運送会社 => お客さんの手元まで届く流れ」

コンピュータの世界にも現実世界と同じように
荷物(データ)を届けるまでにちゃんと届くようにする仕組みがある



### IPアドレスとは

インターネットプロトコルというプロトコルで
通信するのに必要な識別子の一種、インターネット上の住所のようなもの



### ネットワークインターフェースとは

LANケーブルをネットワークインターフェースカード(NIC)や無線LANアダプタを
表している。ただ、それらをソフトウェアから扱う上で抽象化した概念のこと



### IPv4 / IPV6とは

> IPv4 / 6 (Internet Protocol version 4 / 6 )

今いる世界.現在には__2つのインターネットが全く別々に存在している__
プロトコルにIPv4 / IPv6をそれぞれ使用しているため両者には互換性がない

- IPv4であればIPv4アドレス<br>
- IPv6であればIPv6アドレスを使用するのが必要

IPv4は32bit(4bite)に対しIPv6は128bit(16byte)
普及に伴い新たに使えるものが少なくなってきているためIPv6へ移行が試みられている

### (補足)
IPアドレスを持ちネットワークにつながっている
ルータではないコンピュータのことを`ホスト(HOST)`という

ホストやルータといった区別をしないネットワークに繋がった
コンピュータの名称を`ノード(Node)`という


***
# 操作

#### $ ip address show
```ruby:ターミナル
$ ip address show
1:  lo:<LOOPBACK,UP,LOWER_UP> mtu XXXXX qdisc noqueue state UNKNOWN group default qlen XXXX
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 000.X.X.X/X scope host lo 
        valid_lft forever preferred_lft forever 
    inet6 ::X/XXX scope host
        valid_lft forever preferred_lft forever
2:  eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu XXXX qdisc fq_codel state UP group default qlen XXXX 
    link/ether XX:XX:Xx:XX:XX:XX brd ff:ff:ff:ff:ff:ff 
    inet 00.X.X.XX/XX brd XX.X.X.XXX scope global dynamic eth0 
        valid_lft XXXXXsec preferred_lft XXXXXsec 
    inet6 xxXX::XXX:Xxxx:xxXX:XXXX/XX scope link 
        valid_lft forever preferred_lft forever
```


`inet`の表示の後の部分がコンピュータの`IPアドレス`
`lo` や `eth0`は`ネットワークインターフェース`
`eth0`は差出人に相当するIPアドレス


IPアドレスは必要に応じてネットワークインターフェースに付与される、つまり

- ネットワークインターフェース `lo`には `000.X.X.X` というIPアドレス
- ネットワークインターフェース `eth0` には `00.X.X.XX` というIPアドレスが付与されている。

#### ループバックアドレス

`lo`の `000.X.X.X` というIPアドレスは`ループバックアドレス`という特殊なアドレスで
自分自身のアドレスを表している
動作確認など自分自身だけに関わる通信をしたいときに使うと便利

試しに　`($ ping -c 3 <自分のループバックアドレス>)`
コマンドを打つと同じように結果が帰ってくるのがわかる
***

#### $ sudo tcpdump
```ruby:ターミナル
$ sudo tcpdump -tn -I any icmp
Tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
Listening on any,  link-type LINUX_SLL (Linix cooked), capture size XXXXXX bytes

IP XX.X.X.XX > 8.8.8.8 : ICMP echo request, id XXXX, seq 1, lenght 64
IP 8.8.8.8 > XX.X.X.XX : ICMP echo reply, id XXXX, seq 1, lenght 64
IP XX.X.X.XX > 8.8.8.8 : ICMP echo request, id XXXX, seq 2, lenght 64
IP 8.8.8.8 > XX.X.X.XX : ICMP echo reply, id XXXX, seq 2, lenght 64
IP XX.X.X.XX > 8.8.8.8 : ICMP echo request, id XXXX, seq 3, lenght 64
IP 8.8.8.8 > XX.X.X.XX : ICMP echo reply, id XXXX, seq 3, lenght 64
```
 
コンピュータを流れる通信を覗き見できるコマンド
__パケットキャプチャ__、__スニッフィング__ともいう
`$ ping`を打った後`$sudo tcpdump`側のターミナルを見てみると
3回のやり取りrequest replyがあったのを確認できる
***

#### $ traceroute


```ruby:ターミナル
$ traceroute -n 8.8.8.8
Trace route to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1  XX.X.X.X 0.568ms  0.562ms  1.044ms
2  XXX.XX.X.X 4.495ms  4.499ms  4.703ms
3  XX.X.X.XX 11.304ms 11.319ms 11.305ms
4  XX.X.X.XX  12.111ms 11.811ms  12.097ms
……

```
パケットがどのような順路を通って目的地まで届くのかを確認するコマンド
通る順路とは通過する`Route`のこと
このコマンドはネットワークのトラブルシューティングによく使用される


#### Route
ネットワーク機器
それぞれの行に表示されているIPアドレスはパケットが通過した
ルータの持っているIPアドレス

>インターネットにはたくさんのルータがありパケットを
バケツリレーして成り立っていることがわかる

***

### ルーティングテーブルとは
TCP/IP の世界では次にパケットを渡すべき相手を`ルーティングテーブル`という概念で管理している
ルーティングテーブルはコマンドで確認ができる

#### $ ip route show 
```ruby:ターミナル
$ ip route show 
Default via XX.X.X.X dev eth0 proto dhcp src XX.X.X.XX metric XXX
XX.X.X.X/XX dev eth0 proto kernel scope link src XX.X.X.XX
XX.X.X.X dev eth0 proto dhcp scope link src XX.X.X.XX metric XXX

```
まずルーティングテーブルは複数の`ルーティングエントリ`から構成されている
それぞれの行がルーティングエントリ
それぞれのルーティングエントリの先頭には宛先となるIPアドレスが書かれている
宛先`default`は特殊な宛先であり、他のどのが宛先にも該当しない時に使用される

3行目のXX.X.X.X/XXは複数のIPアドレスをまとめた表現方法
このようにルーティングテーブルは　宛先となるIPアドレスを
必ずしも1つずつ書くわけではない

***
#### $ ping

```ruby:ターミナル
$ ping -c 3 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56 (84) bytesofdata.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=63 time=9.06 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=63 time=8.88 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=63 time=10.3 ms

8.8.8.8 pingstatistics
3 packets transmitted, 3 received, 0% packet loss, time 2004ms 
rtt min/avg/max/mdev = 8.883/9.445/10.386/0.678ms

```
TPC/IPのネットワークで__疎通__を確認するのに使用される。
`-c 3`というオプションをつけたことによって応答を要求するメッセージを3回送っている。よって3回の返答が戻ってくる。

>
”3 packets transmitted, 3 received, 0%”
こちらの出した要求に対して応答が無事に届いているのが確認できる。







# 本題のNetwork Namespace
改めてNetwork NamespaceはDockerなどのコンテナ型仮想化技術を構成する要素の一つ

```ruby:ターミナル
$ sudo ip netns add helloworld

$ ip netns list
hello world
```
#### $ ip netns add
>新たにNamespaceを作成できる

#### $ ip netns list
>lsのように確認ができる

#### $ sudo ip netns exec [Namaspace名]
>このコマンドで実行できる



```ruby:ターミナル
$ sudo ip netns add ns1
$ sudo ip netns add ns2
```
作り方が分かったので2つ作成
これで`ns1`と`ns2`のネットワークが作成できたが、お互いにまだ独立している状態
両者を繋ぐには "__veth__" (Virtual Ethernet Device)という仮想的な
ネットワークインターフェースを使用する、vethを作るには `$ip link add`サブコマンドを使用する
<br>

```ruby:ターミナル
$ sudo ip link add ns1-veth0 type peer name ns2-veth0
```
#### $ip link add
>ネットワークインターフェース作成コマンド

これによってvethのネットワークインターフェースが作成された
ns1-veth0とns2-veth0は作成するネットワークインターフェースの名前

```ruby:ターミナル
$ ip link show | grep veth
3 : ns2-veth0@ns1-veth0 : <BROADCAST, MULTICAST, M-DOWN> mtu XXXX qdisc noop
state DOWN mode DEFAULT group default qlen XXXX
4 : ns1-veth0@ns2-veth0 : <BROADCAST, MULTICAST, M-DOWN> mtu XXXX qdisc noop
state DOWN mode DEFAULT group default qlen XXXX
```
grepコマンドによってvethという文字列が含まれるものだけを絞り確認する
現実世界で言えばLANケーブルで繋がった2枚のネットワークインターフェースが作成されている
ただ、まだこれは作成しただけでシステムの領域に所属しているため
Network Namespaceで使用できるようにする
<br>

```ruby:ターミナル
$ sudo ip link set ns1-veth0 netns ns1
$ sudo ip link set ns2-veth0 netns ns2

```
設定したいネットワークインファーフェースの名前の後ろに netns とNamespace名を指定する


<img width="665" alt="namaspace3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581998/eaaa1487-f8dc-0059-1f3f-765417a0238a.png">

このような感じになっている
ただ、まだこの段階ではPC同士をケーブルで繋いでいるのとほぼ同じなので
現実のPCのように設定をしなければ通信ができない

IPを使用して通信する場合はIPアドレスが必要になる
よってvethインターフェースにIPアドレスを付与しなければならない
<br>

```ruby:ターミナル
$ sudo ip netns exec ns1 ip address add XXX.X.X.1/XX dev ns1-veth0
$ sudo ip netns exec ns2 ip address add XXX.X.X.2/XX dev ns1-veth0
```
#### $ ip address add
IPアドレスを設置するには `$ ip address add`

ns1-veth0にはXXX.X.X.1というIPアドレス
ns2-veth0にはXXX.X.X2というIPアドレスが付与される
さらに、UPとDOWNという2つの概念があり
初期の状態はDOWNなので使用するときはUPに設定する
<br>


```ruby:ターミナル
$ sudo ip netns exec ns1 ip link set ns1-veth0 up
$ sudo ip netns exec ns2 ip link set ns2-veth0 up
```
繋がったか確認


```ruby:ターミナル
$ sudo ip netns exec ns1 ping -c 3 XXX.X.X.2
```

<img width="787" alt="namespace1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581998/baaba69b-004c-e436-6f4c-172c38fa8d1e.png">

このようになっている




# 終わりに
同じネットワーク内ですが、ひとまずvethインターフェースで繋げる関連の理解をしました。
まだまだ複雑化していくので段階に分けてQiita書いていきます。