iT邦幫忙

2022 iThome 鐵人賽

DAY 24
1

昨天我們在觀察 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,給大家備存參考一下。

這邊步驟比較多,我們先前情提要一下即將要進行的步驟:

  1. 建立兩個 net namespace: 既然 veth 是跨 namespace 溝通的,那我們就來建立兩個 network namespace。
  2. 建立一對 veth pair。
  3. 把這對 veth 分別放到一個 net namespace 中。
  4. 分別為這對 veth 介面設定一個 ip 且啟動起來。
  5. 測試看看連線。

  1. 現在就讓我們用 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
  1. 建立兩個 net namespace: 這邊用的指令是 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
  1. 建立一對 veth pair,名稱分別為 veth0 及 veth1,建立完成後用 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
  1. 把 veth0 放進 ns1 中,把 veth1 放進 ns2 中,可以觀察到,當這兩個虛擬設備分別放進去 net namespace 後,在 root namespace 這邊用 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
  1. 分別為這對 veth 介面設定一個 ip 且啟動起來,然後用 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

到這邊,是不是很像我們在昨天觀察到的情況呢:
https://ithelp.ithome.com.tw/upload/images/20221009/20151857IPdlCxZvaM.png

  1. 測試看看連線。

我們指定從 ns1ping 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

以上步驟我們做了以下的結構出來:
https://ithelp.ithome.com.tw/upload/images/20221010/20151857BjCaHHtyfF.png

如果想要刪掉上述實驗建立出來的設備,我這邊是發現,只需要刪掉 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 進行溝通的,很顯然我們距離終點還有點遠,這些就留給明天嚕~ (嗚嗚嗚,這樣明天才有東西可以寫!)


上一篇
Day 23: container 怎麼跟別人溝通呢?
下一篇
Day 25: 來過橋吧!
系列文
那些關於 docker 你知道與不知道的事32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言