昨天我們在觀察 bridge 時,有注意到 container 中的網路介面與 host 中多出來的網路介面在名稱上似乎有關聯如下:
我們猜測的沒錯,他們的確有關聯,我們來看看文件:
The veth devices are virtual Ethernet devices. They can act as tunnels between network namespaces to create a bridge to a physical network device in another namespace, but can also be used as standalone network devices.
veth devices are always created in interconnected pairs.
根據文件,veth
是一種虛擬網路設備,會成對出現,會在兩個 namespace 之間扮演「橋樑」的角色,那他是怎麼建立出來的呢?又是怎麼彼此溝通的呢?就讓我們來實驗看看。
在剛剛 veth
的文件中有提到想要建立一對 veth 的話,可以用以下指令:
ip link add <p1-name> type veth peer name <p2-name>
我們昨天有看過 ip
的文件,也有用了 ip addr
來觀察過網路介面及其網路位址,實際上 ip
指令的功能還蠻多的,這邊有一份 Red Hat 提供的 ip COMMAND CHEAT SHEET,給大家備存參考一下。
這邊步驟比較多,我們先前情提要一下即將要進行的步驟:
ip
來實驗看看,在開始之前先觀察一下 host 的情況:可以看到目前就是只有 lo, ens5 跟 docker0。
ubuntu@ip-xxx:~$ ip link list
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: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 0e:24:0e:79:cc:2d brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:ea:22:dd:97 brd ff:ff:ff:ff:ff:ff
ip netns add [namespace name]
,建立後確認一下。ubuntu@ip-xxx:~$ sudo ip netns add ns1
ubuntu@ip-xxx:~$ sudo ip netns add ns2
# 確認一下目前的 netns 的情況:
ubuntu@ip-xxx:~$ sudo ip netns list
ns2
ns1
# 在 /var/run/netns 也可以看到
ubuntu@ip-xxx:~$ sudo ls -l /var/run/netns/
total 0
-r--r--r-- 1 root root 0 Oct 9 12:56 ns1
-r--r--r-- 1 root root 0 Oct 9 12:56 ns2
ip addr
確認一下:ubuntu@ip-xxx:~$ sudo ip link add veth0 type veth peer name veth1
# 這邊可以看到多了 272 與 273,名稱上也可以看出關聯:
ubuntu@ip-xxx:~$ sudo ip link list
1: lo: ...略
2: ens5: ...略
4: docker0: ...略
272: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether ce:da:2c:bd:74:9c brd ff:ff:ff:ff:ff:ff
273: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 16:48:87:27:10:eb brd ff:ff:ff:ff:ff:ff
ip addr
就看到不了。# 把 veth0 放進 ns1
ubuntu@ip-xxx:~$ sudo ip link set veth0 netns ns1
# 把 veth1 放進 ns2
ubuntu@ip-xxx:~$ sudo ip link set veth1 netns ns2
# 用 ip netns list 查看,也可以看到後面多了一個 id: 0 及 id: 1
ubuntu@ip-xxx:~$ sudo ip netns list
ns2 (id: 1)
ns1 (id: 0)
# 在原本的這個 namespace 看不到剛剛那兩個設備了
ubuntu@ip-xxx:~$ sudo ip link list
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: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 0e:24:0e:79:cc:2d brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:ea:22:dd:97 brd ff:ff:ff:ff:ff:ff
ip netns exec ns1 ip addr
觀察一下,根據文件,ip netns exec
的功用如下,也就是它可以讓我們指定要將 ip
指令在哪一個特定的 net namespace 執行。switches ip to the specified network namespace NETNS. Actually it just simplifies executing of:
ip netns exec NETNS ip [ OPTIONS ] OBJECT { COMMAND | help}
# 為 veth0 設定 ip 172.18.0.2 並且啟動起來
ubuntu@ip-xxx:~$ sudo ip netns exec ns1 ip addr add 172.18.0.2/24 dev veth0
ubuntu@ip-xxx:~$ sudo ip netns exec ns1 ip link set veth0 up
# 為 veth1 設定 ip 172.18.0.3 並且啟動起來
ubuntu@ip-xxx:~$ sudo ip netns exec ns2 ip addr add 172.18.0.3/24 dev veth1
ubuntu@ip-xxx:~$ sudo ip netns exec ns2 ip link set veth1 up
# 讓 ip addr 在 ns1 這個 namespace 執行,可以看到他有一個 273: veth0@if272
ubuntu@ip-xxx:~$ sudo ip netns exec ns1 ip addr
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
273: veth0@if272: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 16:48:87:27:10:eb brd ff:ff:ff:ff:ff:ff link-netns ns2
inet 172.18.0.2/24 scope global veth0
valid_lft forever preferred_lft forever
inet6 fe80::1448:87ff:fe27:10eb/64 scope link
valid_lft forever preferred_lft forever
# 同理,讓 ip addr 在 ns2 這個 namespace 執行,可以看到他有一個 272: veth0@if273
ubuntu@ip-xxx:~$ sudo ip netns exec ns2 ip addr
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
272: veth1@if273: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ce:da:2c:bd:74:9c brd ff:ff:ff:ff:ff:ff link-netns ns1
inet 172.18.0.3/24 scope global veth1
valid_lft forever preferred_lft forever
inet6 fe80::ccda:2cff:febd:749c/64 scope link
valid_lft forever preferred_lft forever
到這邊,是不是很像我們在昨天觀察到的情況呢:
我們指定從 ns1
去 ping
172.18.0.3,是可以 ping 得到的,但如果要從 host 去 ping 172.18.0.3 是 ping 不到的...
ubuntu@ip-xxx:~$ sudo ip netns exec ns1 ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.032 ms
64 bytes from 172.18.0.3: icmp_seq=3 ttl=64 time=0.037 ms
^C
--- 172.18.0.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2049ms
rtt min/avg/max/mdev = 0.032/0.038/0.047/0.006 ms
ubuntu@ip-xxx:~$ ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
^C
--- 172.18.0.3 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2038ms
以上步驟我們做了以下的結構出來:
如果想要刪掉上述實驗建立出來的設備,我這邊是發現,只需要刪掉 ns1 跟 ns2 即可:
ubuntu@ip-xxx:~$ sudo ip netns delete ns1
ubuntu@ip-xxx:~$ sudo ip netns delete ns2
如果是在建立了一對 veth 後,也只需要刪掉 veth pair 中的其中一個,另外一個也會隨之刪除。
到此,我們驗證了 veth 可以跨 namespace 溝通的能力,到這邊應該對 veth 比較有感覺一點了,而過程中也有注意到跟 docker bridge 的關聯,但還是沒回答到 docker0
是什麼,而且很顯然 host 是無法跟這兩個 net namespace 進行溝通的,很顯然我們距離終點還有點遠,這些就留給明天嚕~ (嗚嗚嗚,這樣明天才有東西可以寫!)