Linuxで動かしながら学ぶtcp/ipネットワーク入門 輪読
「Linuxで動かしながら学ぶtcp/ipネットワーク入門」をdocker ubuntuを使って、動かしながら読み進めた備忘録。
Goal
この回では、ubuntu内で仮想的なネームスペースを二つ作って、互いに通信できるところまでを目標にします。この回では同一セグメント内での二つのdeviceでPingできるがGoalです。
macに実行環境構築
環境はmac環境でdocker ubuntu 20.04を使用。
% docker run -it --privileged ubuntu:20.04 bash
docker内のnamespace作成には、--privideged
でdocker containerをsysctrl
権限付きで起動する必要があります。
参考
`docker run`せずに`docker pull`して、`docker container create --name learn-tcpip ubuntu:20.04`などとしてdownloadした\[repository:tag\](=image名?)を指定し、containerに好きな名前をつけるもよしです。dockerのimage名とは[repository:tag]のこと?
https://ja.stackoverflow.com/questions/32345/docker%E3%81%AE%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E5%90%8D%E3%81%A8%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E5%90%8D%E3%81%A3%E3%81%A6%E5%90%8C%E3%81%98%E3%82%82%E3%81%AE% docker create --name learn-tcpip ubuntu:20.04
f57fa4120e1e0dde140109a2cec6eed8f521b7f997cde5aa2fabbb440ff537a4
or
% docker container create --name learn-tcpip ubuntu:20.04
f57fa4120e1e0dde140109a2cec6eed8f521b7f997cde5aa2fabbb440ff537a4
containerを作成したら、停止中のcontainerリストを下記コマンドで表示して、containerを起動します。
% docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f57fa4120e1e ubuntu:20.04 "bash"
% docker container start f57fa4120e1e
f57fa4120e1e
docker containerの内部で実行していきます。
% docker container exec -it --privileged f57fa4120e1e bash
root@f57fa4120e1e:/#
interface接続までの流れ(物理的な接続)
Network Namespaceとは、独立したネットワークと思ってよく、ネットワークインターフェイスやルーティングテーブルを持ちます。
手順は下記。
- Namespaceを2つ作成, ns1, ns2とする
- Network interfaceを2つ作成、ns1-veth0、ns2-veth0とする
- interfaceをそれぞれnamespaceに接続する
一度daemonを切ると、namespaceは有効でないとエラーが表示されます。
このためnamespaceを削除して作り直します。
なお、今回使用したコマンドたちはこちらのリンク先にまとめてあります。dockerのcontainerが一旦停止するとnamespaceは無効化されますので、復旧などに。
daemonを再起動するとnamespaceは無効になるっぽい
root@f57fa4120e1e:/# ip netns list
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
Error: Peer netns reference is invalid.
helloworld
Error: Peer netns reference is invalid.
ns3
Error: Peer netns reference is invalid.
ns2
Error: Peer netns reference is invalid.
ns1
root@f57fa4120e1e:/# ip netns delete ns1
root@f57fa4120e1e:/# ip netns delete ns2
root@f57fa4120e1e:/# ip netns delete ns3
root@f57fa4120e1e:/# sudo ip netns add ns1
root@f57fa4120e1e:/# sudo ip netns add ns2
root@f57fa4120e1e:/# sudo ip netns add ns3
ns1-veth0
とns2-veth0
でvethのnetwork interfaceを作ります。
interfaceの実体はファイルである。すでにある場合はファイルが既にあるとエラーメッセージが出力されます。
root@f57fa4120e1e:/# sudo ip link add ns1-veth0 type veth peer name ns2-veth0
root@f57fa4120e1e:/# sudo ip link show | grep veth
4: ns2-veth0@ns1-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
6: ns1-veth0@ns2-veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
root@b
作成したinterfaceをnetwork namespaceの持ち物にします。
root@f57fa4120e1e:/# sudo ip link set ns1-veth0 netns ns1
root@f57fa4120e1e:/# sudo ip link set ns2-veth0 netns ns2
namespace内のinterfaceになるので、linkをshowしても何も表示されなくなります。
(スコープが区切られたみたいな感じ)
root@f57fa4120e1e:/# sudo ip link show | grep veth
root@f57fa4120e1e:/#
namespaceを指定して、ip linkを表示します。
root@f57fa4120e1e:/# sudo ip netns exec ns1 ip link show | grep veth
6: ns1-veth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
root@f57fa4120e1e:/# sudo ip netns exec ns2 ip link show | grep veth
4: ns2-veth0@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
作成済みのnamespace ns1, ns2に対して、ip linkが作成されています。
これでveth interfaceは仮想的なLANケーブルの役割を担います。なので、二つのnamespaceはこの仮想的なLANケーブルで繋がっています。
これはLANケーブルで二つのコンピュータが接続されているのと同じような感じです。
veth interfaceにip addressを付与すれば通信ができます。
ここまでで以下のように接続ができました。LANケーブルでコンピュータ同士が接続されたように、仮想ネットワークネームスペースがインターフェースを通じて接続されています。
これはLANケーブルでコンピュータを接続している状態です。ip addressを設定して通信ができるようになります。
interfaceにip addressを付与(論理的な設定)
各ネットワークスペースそれぞれでip addressを割り当てます。
root@f57fa4120e1e:/# sudo ip netns exec ns1 ip address add 192.0.2.1/24 dev ns1-veth0
root@f57fa4120e1e:/# sudo ip netns exec ns2 ip address add 192.0.2.2/24 dev ns2-veth0
interfaceの状態を確認します。
root@f57fa4120e1e:/# sudo ip netns exec ns1 ip link show ns1-veth0 | grep state
6: ns1-veth0@if4: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
root@f57fa4120e1e:/# sudo ip netns exec ns2 ip link show ns2-veth0 | grep state
4: ns2-veth0@if6: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
network interfaceのSTATE
の項目がDOWNになっています。明示的にUPにすることで通信ができます。
root@f57fa4120e1e:/# sudo ip netns exec ns1 ip link set ns1-veth0 up
root@f57fa4120e1e:/# sudo ip netns exec ns2 ip link set ns2-veth0 up
state UP
になりました。
root@f57fa4120e1e:/# sudo ip netns exec ns1 ip link show ns1-veth0 | grep state
6: ns1-veth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
root@f57fa4120e1e:/# sudo ip netns exec ns2 ip link show ns2-veth0 | grep state
4: ns2-veth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
root@f57fa4120e1e:/#
pingしてみむとす
ns1からns2のIPに向けてpingしてみむとす。
dockerにping install
docker imageにping
がないときは次のコマンドで入れましょう。
apt-get install iputils-ping net-tools
root@b27d3bad4e97:/# sudo ip netns exec ns1 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=0.724 ms
64 bytes from 192.0.2.2: icmp_seq=2 ttl=64 time=0.211 ms
64 bytes from 192.0.2.2: icmp_seq=3 ttl=64 time=0.147 ms
--- 192.0.2.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2084ms
rtt min/avg/max/mdev = 0.147/0.360/0.724/0.258 ms
ns1からns2にpingを送信して返ってくることが確認できました。
これでPingの疎通ができました。
┗(`・∀・´)ヨッシャ!
物理的な配線を論理的に設定することで通信することができるってことです。
論理構成されたネットワークはこのようになってます。
ここまででTCP/IPの実験環境の準備ができました。
ルータがいなくても通信できるのは、同じセグメント内同士だからです。
ルータは異なるセグメントと通信する為の機能です。
セグメントとは何か、ルータとは何かをよりよく理解するためにはIP Addressの設計をよく知ることが必要です。次のページではIP Addressについてみていきます。
IP Addressで理解するセグメント
先ほど、ip addressを付与した時のコマンドをもう一度見てみます。
root@f57fa4120e1e:/# sudo ip netns exec ns1 ip address add 192.0.2.1/24 dev ns1-veth0
root@f57fa4120e1e:/# sudo ip netns exec ns2 ip address add 192.0.2.2/24 dev ns2-veth0
1行目のコマンドでは、dev
でdevice名を指定し、ns1-veth0
としました。
また、ip addressは192.0.2.1/24
が値として割り当てられています。
2行目のコマンドについても同様です。まとめると次のような値の割り当てが行われています、
namespace name | device | ip address |
---|---|---|
ns1 | ns1-veth0 | 192.0.2.1/24 |
ns2 | ns2-veth0 | 192.0.2.2/24 |
ip addressは32bitの2進数表現を8bitで区切り、10進数に変換されたものです。
今回は、共通部分は192.0.2
です。これがセグメントを表します。/24
は32bitsのうち、何bitsをセグメントに割り当てるかを表します。ですから、この場合、残る8bitを10進数表現した1
及び2
が同一セグメント内におけるip addressを指します。
次の図のような構成でip addressを割り当てるコマンドだったのです。
今回は、ルータを使わず、同一セグメント内で通信できるネットワークを作りました。次はルータを使用して、異なるセグメント同士で通信できるネットワークを作ります。