Linux 網路:拆分 eth0(w/多個 ipv4)為每個 ipv4 提供自己的虛擬設備和命名空間
我正在嘗試使用 Linux 網路名稱空間建構一個小項目,但我對所有可用的 linux 網路功能和容器化技術有點不知所措,因此不確定我是否以正確的方式解決這個問題。
問題/項目
我目前有一個
eth0
帶有單個網路設備1.1.1.1
(我希望創建一個我有一堆(網路)命名空間的情況,每個命名空間都有效地擁有自己的單個專有公共 IPv4 地址/介面。1.1.1.2``1.1.1.3``1.1.1.12
我的目標是啟動多個 shell,每個 shell 都與自己的網路命名空間(以及 pid、ipc、…命名空間)隔離。因此,例如,第7 個shell 將使用
ns7
具有單個(虛擬)乙太網介面的網路命名空間,該介面具有靜態 ip1.1.1.7
。在那個 shell 中,我可以(例如)啟動 apache/nginx,讓它在 *:80 上監聽,然後它將在1.1.1.7:80
. 指向任何其他 IPv4 地址上的埠 80 的任何流量都將永遠無法到達ns7
,同樣,指向的任何流量1.1.1.7
都只能到達命名空間中的程序ns7
。基本思想是命名空間實際上是永久的。命名空間本身以及相關的虛擬網路設備將在系統啟動時(重新)創建和啟動。
潛在的解決方案(我在正確的軌道上嗎?)
從我能夠在沒有動手實驗的情況下拼湊而成的情況下,解決方案應該如下所述,我在正確的軌道上嗎?
- 創建並啟動(虛擬)L2 橋接設備
br0
。確保我們在 L2(而不是 L3)執行。- 更改目前的乙太網設備
eth0
配置,使其在啟動時仍然出現,但不再設置任何 IP 地址(既不是靜態也不是 DHCP),也分配eth0
給br0
網橋。- 創建一些網路命名空間
ip netns add ns2
,ip netns add ns3
, …,ip netns add ns12
. 我會將 default/root 命名空間視為ns1
.- 創建多個虛擬乙太網介面對
net2a
~net2b
,net3a
~net3b
,net4a
~net4b
, … 對於每一對,將a
-version 連接到br0
網橋,並將b
-version 分配給它各自的命名空間。- 在每個命名空間中,為本地 veth 設備(如 )分配
net2b
適當ns2
的 IPv4 地址資訊並啟動設備。- 我可能必須啟用 IPv4 轉發*(?)* (
/proc/sys/net/ipv4/ip_forward
) 和/或啟用 ARP 過濾*(?)* (/proc/sys/net/ipv4/conf/all/arp_filter
)。- 每個命名空間都有它自己的防火牆配置(據我了解),因此在每個命名空間中執行一些 iptables/nftables shell 腳本來設置一些合理的預設值並根據本地需求進行調整。
對於那些更熟悉這些虛擬 linux 網路設備的人來說,這聽起來像是(大致)可行的計劃嗎?
額外細節(以防萬一)
- **作業系統資訊:**我執行 CentOS 8,其中特別包括和
kernel 4.18
,僅用於手動防火牆配置(而不是 firewalld 的東西)。systemd``SELinux``nftables
- **背景:**所有提供的地址(如
1.1.1.1
)和介面名稱(如eth0
)等都希望顯然是虛構的,在某種程度上出於隱私原因,但為了簡潔/簡單起見,我聲明的意圖也是如此每個命名空間中的一個外殼”。- **實際需求:**在這些命名空間環境中將執行許多不同類型的軟體,每個命名空間將有一個獨特的工作,並且通常涉及多個服務;我的主要願望之一是完全隔離 IPv4 地址。此外,許多目標程序是伺服器/守護程序(例如我的 apache httpd 範例),我希望它們能夠綁定到實際的面向公眾的介面/埠,而不是綁定到私有 ipv4 或 unixsocket 上的埠,然後讓根命名空間中的軟體充當反向代理中間件;
- 為什麼不只是碼頭工人:(TL / DR)這是一個選項,但我想一起定制一些有趣的東西(Longer Rant)幾乎所有這些命名空間環境都是供個人使用的,一個將執行我的私人郵件伺服器,一個用於託管一些個人的網路伺服器低-交通站點,用於一些實時 webdev 工作的網路伺服器,一對執行自己的 sshd+webstack 來充當一些業餘愛好者朋友的免費迷你 VPS,一些執行一些高度自動化的流程,諸如此類。我知道我正在嘗試做的事情與 docker 提供的常見容器化堆棧之間存在巨大的重疊,事實上我描述的系統已經做了大部分事情,其中大部分使用 Podman(與 docker 幾乎相同)和其餘的大部分只是在公共根命名空間中並排執行。由於各種原因,我喜歡乾淨利落地對其中一些進行微觀管理,如果我可以將內容分離到多個永久命名空間中,這將容易得多,我發現我越是嘗試根據自己的意願調整內容,容器軟體就越會妨礙我。由於 containersoftware 提供的唯一東西,我實際使用的,實際上是 linux 核心功能,我覺得這是一個值得放棄的項目包裝器並弄清楚如何在沒有它的情況下完成這些事情。而且我也喜歡深入研究這些東西所帶來的教育價值,因為這不是我日常工作通常涉及的事情。
- **IPC:**我沒有重要的理由讓(個體內部的程序)命名空間必須通過 IP 與其他命名空間(也不與預設命名空間)通信。不過,如果我對此改變主意(並假設到目前為止我的想法大部分是正確的),我想我可以通過為每個命名空間設置一個帶有額外veth -pairs的額外 L2 橋來重複部分過程,並分配那些私有
192.168.x.x
樣式的 IPv4 地址。- **VPS/雲:**有問題的機器不是物理機,而是VPS/虛擬伺服器/雲伺服器。機器上目前存在的唯一/單個網路設備。這
eth0
實際上被稱為ens3
,即使在完成 CentOS 安裝之前,它也會立即自動執行,因此本身就已經是一個虛擬設備。lsmod
目前顯示veth
並virtio_net
載入。我認為我的託管服務提供商使用 Qemu 提供了這個 VPS。我不確定這是否重要,我想它不應該。雖然我確實花了一些時間研究是否可以像目前一樣複製(或創建更多)介面ens3
然後直接為它們分配一個單一的 IPv4 和命名空間,無需橋接設備和 veth-pair。該搜尋並沒有真正產生任何結果,我只是最終假設如果沒有託管服務提供商人員在管理程序級別更改設置的幫助,這將是不可能的。雖然它們通常很有幫助,而且我想可能會對此類操作持開放態度,但這會使我的解決方案對未來的變化不太靈活,所以如果可能的話,我更願意在我可以完全控制的設備上處理這個問題。- **IPv6:**為了簡潔起見,我避免提及 IPv6,我也確實有一個 IPv6 地址塊,併計劃以類似的方式使用它們。但我認為最好先讓 IPv4 正常工作,然後啟用 IPv6 並從那裡開始,我無法想像它會有太大的不同。
- *我的實現:我還不完全確定如何實現這一切,一旦我真正設法讓事情第一次工作。我想,對於項目的網路部分,我將創建一個
network-setup.sh
shell 腳本來測試所有與網路相關的必需品(如命名空間、橋接設備、veth 設備……)的存在,然後重新創建或設置補缺什麼。然後附帶一個執行該 shell 腳本的*systemd 單元文件,並根據network-online.target
. 然後在(引導)過程中稍後執行的另一個shell 腳本和單元文件unshare
,它使用或systemd -versioninit
實際啟動相關流程。但如果有人有更好的主意,我很樂意聽到。- **不同的命名空間實現:**我能聞到的一個潛在的複雜性是,我的印像是 util-linux (
man unshare
) 呼叫的網路命名空間與 iproute2 (man ip-netns
) 在同一術語中的含義不同。但是,我仍然不確定前者是否是後者的超集/擴展,或者它是否是完全不同的不兼容實現。事實上,在閱讀容器相關技術時,這似乎是一個反復出現的問題。
使用 veth-pairs 橋接的方法可以使用,但有一個更簡單的方法:
使用 a
macvlan
,請參閱此處或此處了解一些詳細資訊和討論。這是一個使用物理介面(在您的情況下,
eth0
)作為父(或“主”)的虛擬介面,對使用相同父的其他設備完全透明,並且可以移動到網路命名空間中。然後,您可以將命名空間內的 IPv4 或 IPv6 地址分配給此介面,它的工作方式就像您擁有該容器獨有的附加物理網路介面一樣。
根據您是否希望容器相互通信,有不同的風格。閱讀文件了解詳細資訊。
是的,如果你想要一個防火牆(iptables),你也必須在每個命名空間中這樣做。
順便說一句,Docker 和其他使用命名空間的虛擬化方法也使用
macvlan
s,所以如果你想要的只是 apache、nginx 等,請考慮使用 Docker 和/或 Docker Compose,它會完成所有其餘工作(不同的文件系統、本地 DNS、埠映射)。