本文首發於我的公眾號 Linux雲端計算網路(id: cloud_dev),專注於乾貨分享,號內有 10T 書籍和視訊資源,後臺回覆「1024」即可領取,歡迎大家關注,二維碼文末可以掃。
上一篇文章我們詳細介紹了 macvlan 這種技術,macvlan 詳解,由於它高效易配置的特性,被用在了 Docker 的網路方案設計中,這篇文章就來說說這個。
01 macvlan 用於 Docker 網路
在 Docker 中,macvlan 是眾多 Docker 網路模型中的一種,並且是一種跨主機的網路模型,作為一種驅動(driver)啟用(-d 引數指定),Docker macvlan 只支援 bridge 模式。
下面我們做兩個實驗,分別驗證相同 macvlan 網路和不同 macvlan 網路的連通性。
1.1 相同 macvlan 網路之間的通訊
首先準備兩個主機節點的 Docker 環境,搭建如下拓撲圖示:
1 首先使用 docker network create
分別在兩臺主機上建立兩個 macvlan 網路:
root@ubuntu:~# docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=enp0s8 mac1
這條命令中,
-d
指定 Docker 網路 driver--subnet
指定 macvlan 網路所在的網路--gateway
指定閘道器-o parent
指定用來分配 macvlan 網路的物理網路卡
之後可以看到當前主機的網路環境,其中出現了 macvlan 網路:
root@ubuntu:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
128956db798a bridge bridge local
19fb1af129e6 host host local
2509b3717813 mac1 macvlan local
d5b0798e725e none null local
2 在 host1 執行容器 c1,並指定使用 macvlan 網路:
root@ubuntu:~# docker run -itd --name c1 --ip=172.16.10.2 --network mac1 busybox
這條命令中,
--ip
指定容器 c1 使用的 IP,這樣做的目的是防止自動分配,造成 IP 衝突--network
指定 macvlan 網路
同樣在 host2 中執行容器 c2:
root@ubuntu:~# docker run -itd --name c2 --ip=172.16.10.3 --network mac1 busybox
3 在 host1 c1 中 ping host2 c2:
root@ubuntu:~# docker exec c1 ping -c 2 172.16.10.3
PING 172.16.10.3 (172.16.10.3): 56 data bytes
64 bytes from 172.16.10.3: seq=0 ttl=64 time=0.641 ms
64 bytes from 172.16.10.3: seq=1 ttl=64 time=0.393 ms
--- 172.16.10.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.393/0.517/0.641 ms
注意:以上的實驗都需要物理網路卡 enp0s8 開啟混雜模式,不然會 ping 不通。
1.2 不同 macvlan 網路之間的通訊
接下來,我們來看看不同 macvlan 網路之間的連通性,搭建以下的拓撲環境:
由於 macvlan 網路會獨佔物理網路卡,也就是說一張物理網路卡只能建立一個 macvlan 網路,如果我們想建立多個 macvlan 網路就得用多張網路卡,但主機的物理網路卡是有限的,怎麼辦呢?
好在 macvlan 網路也是支援 VLAN 子介面的,所以,我們可以通過 VLAN 技術將一個網口劃分出多個子網口,這樣就可以基於子網口來建立 macvlan 網路了,下面是具體的建立過程。
1 首先分別在兩臺主機上將物理網口 enp0s8 建立出兩個 VLAN 子介面。
# 使用 vconfig 命令在 eth0 配置兩個 VLAN
root@ubuntu:~# vconfig add enp0s8 100
root@ubuntu:~# vconfig add enp0s8 200
# 設定 VLAN 的 REORDER_HDR 引數,預設就行了
root@ubuntu:~# vconfig set_flag enp0s8.100 1 1
root@ubuntu:~# vconfig set_flag enp0s8.200 1 1
# 啟用介面
root@ubuntu:~# ifconfig enp0s8.100 up
root@ubuntu:~# ifconfig enp0s8.200 up
2 分別在 host1 和 host2 上基於兩個 VLAN 子介面建立 2 個 macvlan 網路,mac10 和 mac20。
root@ubuntu:~# docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=enp0s8.100 mac10
root@ubuntu:~# docker network create -d macvlan --subnet=172.16.20.0/24 --gateway=172.16.20.1 -o parent=enp0s8.200 mac20
3 分別在 host1 和 host2 上執行容器,並指定不同的 macvlan 網路。
# host1
root@ubuntu:~# docker run -itd --name d1 --ip=172.16.10.10 --network mac10 busybox
root@ubuntu:~# docker run -itd --name d2 --ip=172.16.20.10 --network mac20 busybox
# host2
root@ubuntu:~# docker run -itd --name d3 --ip=172.16.10.11 --network mac10 busybox
root@ubuntu:~# docker run -itd --name d4 --ip=172.16.20.11 --network mac20 busybox
通過驗證,d1 和 d3,d2 和 d4 在同一 macvlan 網路下,互相可以 ping 通,d1 和 d2,d1 和 d4 在不同的 macvlan 網路下,互相 ping 不通。
這個原因也很明確,不同 macvlan 網路處於不同的網路,而且通過 VLAN 隔離,自然 ping 不了。
但這也只是在二層上通不了,通過三層的路由是可以通的,我們這就來驗證下。
重新找一臺主機 host3,通過開啟 ip_forward
把它改造成一臺路由器(至於為什麼可以這樣,可以參考我之前的一篇文章),用來打通兩個 macvlan 網路,大概的圖示如下所示:
1 首先對 host3 執行 sysctl -w net.ipv4.ip_forward=1
開啟路由開關。
2 然後建立兩個 VLAN 子介面,一個作為 macvlan 網路 mac10 的閘道器,一個作為 mac20 的閘道器。
[root@localhost ~]# vconfig add enp0s8 100
[root@localhost ~]# vconfig add enp0s8 200
[root@localhost ~]# vconfig set_flag enp0s8.100 1 1
[root@localhost ~]# vconfig set_flag enp0s8.200 1 1
# 對 vlan 子介面配置閘道器 IP 並啟用
[root@localhost ~]# ifconfig enp0s8.100 172.16.10.1 netmask 255.255.255.0 up
[root@localhost ~]# ifconfig enp0s8.200 172.16.20.1 netmask 255.255.255.0 up
3 這樣之後再從 d1 ping d2 和 d4,就可以 ping 通了。
root@ubuntu:~# docker exec d1 ping -c 2 172.16.20.10
PING 172.16.20.10 (172.16.20.10): 56 data bytes
64 bytes from 172.16.20.10: seq=0 ttl=63 time=0.661 ms
64 bytes from 172.16.20.10: seq=1 ttl=63 time=0.717 ms
--- 172.16.20.10 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.661/0.689/0.717 ms
root@ubuntu:~# docker exec d1 ping -c 2 172.16.20.11
PING 172.16.20.11 (172.16.20.11): 56 data bytes
64 bytes from 172.16.20.11: seq=0 ttl=63 time=0.548 ms
64 bytes from 172.16.20.11: seq=1 ttl=63 time=0.529 ms
--- 172.16.20.11 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.529/0.538/0.548 ms
PS:可能有些系統做了安全限制,可能 ping 不通,這時候可以新增以下 iptables 規則,目的是讓系統能夠轉發不通 VLAN 的資料包。
iptables -t nat -A POSTROUTING -o enp0s8.100 -j MASQUERADE
iptables -t nat -A POSTROUTING -oenp0s8.200 -j MASQUERADE
iptables -A FORWARD -i enp0s8.100 -o enp0s8.200 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i enp0s8.200 -o enp0s8.100 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i enp0s8.100 -o enp0s8.200 -j ACCEPT
iptables -A FORWARD -i enp0s8.200 -o enp0s8.100 -j ACCEPT
為什麼配置 VLAN 子介面,配上 IP 就可以通了,我們可以看下路由表就知道了。
首先看容器 d1 的路由:
root@ubuntu:~# docker exec d1 ip route
default via 172.16.10.1 dev eth0
172.16.10.0/24 dev eth0 scope link src 172.16.10.10
我們在建立容器的時候指定了閘道器 172.16.10.1
,所以資料包自然會被路由到 host3 的介面。再來看下 host3 的路由:
[root@localhost ~]# ip route
default via 192.168.108.1 dev enp0s3 proto dhcp metric 100
172.16.10.0/24 dev enp0s8.100 proto kernel scope link src 172.16.10.1
172.16.20.0/24 dev enp0s8.200 proto kernel scope link src 172.16.20.1
192.168.56.0/24 dev enp0s8 proto kernel scope link src 192.168.56.122 metric 101
192.168.108.0/24 dev enp0s3 proto kernel scope link src 192.168.108.2 metric 100
可以看到,去往 172.16.10.0/24
網段的資料包會從 enp0s8.100 出去,同理 172.16.20.0/24
網段也是,再加上 host3 的 ip_forward
開啟,這就打通了兩個 macvlan 網路之間的通路。
02 總結
macvlan 是一種網路卡虛擬化技術,能夠將一張網路卡虛擬出多張網路卡。
macvlan 的四種通訊模式,常用模式是 bridge。
在 Docker 中,macvlan 只支援 bridge 模式。
相同 macvlan 可以通訊,不同 macvlan 二層無法通訊,可以藉助三層路由完成通訊。
思考一下:
- macvlan bridge 和 bridge 的異同點
- 還有一種類似的技術,多張虛擬網路卡共享相同 MAC 地址,但有獨立的 IP 地址,這是什麼技術?
後臺回覆“加群”,帶你進入高手如雲交流群
我的公眾號 「Linux雲端計算網路」(id: cloud_dev) ,號內有 10T 書籍和視訊資源,後臺回覆 「1024」 即可領取,分享的內容包括但不限於 Linux、網路、雲端計算虛擬化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++程式設計技術等內容,歡迎大家關注。
參考:
https://www.cnblogs.com/CloudMan6/p/7400580.html
https://blog.csdn.net/dog250/article/details/45788279
https://www.hi-linux.com/posts/40904.html