解決Docker Container MACVLAN 無法透過DHCP獲得IP的兩個方法

Docker Container無疑是近10年來LINUX宇宙最偉大的“發明”之一,今天不懂Docker不能算入門了IT。Docker Container有好幾種網路方式,其中MACVLAN模式小U認爲是最好玩的,透過MACVLAN可以讓只有一個網卡的設備虛擬出多個“網口”,取得多個IP。但,只要玩過DOCKER MACVLAN的朋友都會發現一個問題:DOCKER MACVLAN NETWORK是不具備DHCP自動抓取IP的功能。本文分享兩個解決方法,又是一篇只有20分鐘寫的文章,請見諒。

Docker Container 的網路模式和他們的IP地址

Docker 容器有多種網路模式,每種模式都有其特定的用途和優點。以下是幾種常見的 Docker 網路模式簡單介紹:

1. Bridge 網路模式

Bridge 網路模式是 Docker 的預設網路模式。在這種模式下,Docker 會在宿主機上創建一個虛擬網橋(類似於軟體交換機),並將所有的容器連接到這個網橋上。每個容器都會被分配一個獨立的、宿主機內部虛擬內網的 IP 地址,並且這些容器之間可以通過內部 IP 地址進行通信。

2. Host 網路模式

在 Host 網路模式下,容器直接使用宿主機的網路堆棧,這意味著容器不會被分配獨立的網絡名稱空間。容器與宿主機共享相同的 IP 地址和網路接口。不會有單獨的IP地址

3. Macvlan 網路模式

Macvlan 網路模式允許容器有自己的虛擬 MAC 地址,並且每個容器看起來像是一個獨立的、擁有獨立網口的物理設備,並獲得和宿主機同級的真實內網IP地址。這使得容器可以直接與宿主機網路上的其他設備通信,無需經過宿主機的網路堆棧。

4. Overlay 網路模式

Overlay 網路模式通常用於 Docker Swarm 或 Kubernetes 等集群環境中。這種模式允許在不同宿主機上的容器之間建立一個虛擬的 L2 網絡,使其可以跨主機通信。

Docker Macvlan 模式無法DHCP的問題

運行在Docker Macvlan 模式的容器,需要全手動的設定IP地址,無法DHCP。通常是怎麼做的?首先,先要根據宿主機所在的真實網域,創建一個相同的MACVLAN網路,例如最常見的家用路由器 192.168.1.1 的內網:

docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 macvlan_net

然後再手動指派 Docker Container 的IP地址,例如指定爲 192.168.1.100:

docker run -it --rm \
  --network macvlan_net \
  --ip 192.168.1.100 \
  your_image

這就相當於全靜態的IP配置。對於我們熟悉的人來說,問題不大,但是如果要把一個裝配了 DOCKER MACVLAN 容器的機器交給任意一戶人家、任意的路由器網路使用,那問題就大了。這種全靜態的IP配置,適應性是零,使用者必須符合以下全部要求,機器才能正常使用:

  • 路由器的內網網域是 192.168.1.XXX
  • 路由器的子網MASK 是 /24 或 255.255.255.0
  • 192.168.1.100沒有被其他設備佔用

這顯然是不可能的。所以,小U以下提供兩種自適應的方法。

MACVLAN IP的解決方法方法一 (不完美)

方法一就是 Ups-Gemini 雙子VPN 1.0 系統採用的方法。這種方法是利用啓動script rc.local,自動抓取宿主機的IP信息(宿主機是能DHCP獲得IP地址的),然後反向分析出網域,再自我分配一個IP地址:

# rc.local
subnet=$(ip route | awk '/default/ {print $3}' | cut -d"." -f1-3)".0/24"
gateway=$(ip route | awk '/default/ {print $3}')
docker network create -d macvlan --subnet=$subnet --gateway=$gateway -o parent=eth0 mac_bridge
docker-compose -f /path/to/docker-compose.yaml up --force-recreate 

# docker-compose.yaml
networks:
  mac_bridge:
    external: true

聰明的你可以看出,這個邏輯有幾個潛在問題:

  1. 開機延遲內,宿主機必須要獲得IP地址。也就是說,如果開機時候沒有插網線,MACVLAN就建立不起來。
  2. 開機後宿主機更換路由器,網域更變了MACVLAN不會跟着變。必須重啓。
  3. IP網域的MASK必須是 /24 或 255.255.255.0。不過這點問題不大,我所接觸過的家用路由器產品,都是這個MASK,如果修改過的,都是高人,協助客製化修改並不困難。
  4. 如果偵測到的網域是 123.123.123.0/24,那麼指派MACVLAN的IP就是 123.123.123.2,相當數量的路由器的默認DHCP是從 2~254,這就需要客戶自行修改DHCP範圍。但有的客戶不知道DHCP是什麼,有的客戶的路由器沒有管理權限。這導致不時會出現IP衝突(雖然概率比較低)

MACVLAN IP DHCP完美解決方法

經過大約幾個月的摸索,小U發現可以利用另一種虛擬技術:Linux Container來解決這個問題。 Linux Container同樣具有和Docker相似的網路選項,但Linux Container的Macvlan是能夠自動抓取IP,而且MAC地址是persist不變的,也就說不僅僅能自動抓取到IP,而且DHCP得到的地址會相對穩定,這實在是太好用了!

小U接觸到Linux Container已經是發展過 LXC – LXD – INCUS 幾個階段,如果你也是新接觸,建議直接從INCUS開始。這兩篇文章是帶我入門的,是我找到最全面最清晰的教學(雖然有些舊,自己腦補更新):

使用 INCUS Linux Container的首先難點是安裝,他的安裝沒有Docker簡單,不過只要是Linux Kernel 和 Distribution 都支援,不要太舊,都難度不大。

INCUS Linux Container 的使用更偏向 Docker Compose,很多設定都有一個設定檔可以好像 nano / vi 去修改,不像 Docker,一旦啓動了,有些參數就不能改,要遷移到一個新的container。總體來說INCUS的設定更爲先進,更偏向與虛擬機的設定邏輯。

想比起Dockerhub 數之不盡的鏡像,INCUS Linux Container 的鏡像基本都是Linux的系統本身(出乎意料竟然有OpenWRT)。如果要使用 Docker鏡像,就要先INCUS出一個Debian/Ubuntu/Arch,然後在裡面裝Docker,那麼就完美把Docker MACVLAN 無法DHCP的問題完美解決了!

不過你就會問,這樣“套娃”多層虛擬,效能損耗厲害嗎?我用INCUS上面裝DEBIAN然後直接跑TAILSCALE並沒有覺得有損耗。但是,INCUS上面裝OPENWRT的損耗就厲害了,2.5GbE的網口速度連一半都不到(NAT)。這可能是之後還要研究的課題。

頂,又寫了40分鐘,收工啦!歡迎留言討論。

歡迎你的留言討論:

你可以一針見血

by Upsangel
Logo