虛擬網卡的原理
qemu-kvm技術:能讓你在一台巨大的物理機里,掏出一台台小的機器。
首先,虛擬機要有一張網卡,通過linux上的tun/tap技術實現的。虛擬機是物理機上跑着的一個軟件,這個軟件可以像其他應用打開文件一樣,打開一個tun/tap的字符誰被文件,之后,就會在物理機上看到一張虛擬的tap網卡。虛擬機里的應用會把所有的網絡包都往里面發。
網絡包到虛擬軟件這里,將網絡包轉換為文件流,寫入字符設備,就像寫一個文件一樣。內核中tun/tap字符設備驅動會收到這個寫入的文件流,交給虛擬網卡驅動,再次轉成網絡包,交給tcp/ip協議棧,從虛擬tap網卡發送出來,成為標准的網絡包。
虛擬網卡連接到雲
雲計算網絡中的注意點:
- 共享,虛擬機有多個網卡,但是物理機可能只有有限的網卡,那么多個虛擬網卡如何共享同一個出口。
- 隔離:安全隔離和流量隔離,安全隔離,兩個虛擬機屬於兩個用戶,怎么保證數據不被竊聽。流量隔離,一個瘋狂下載會不會導致另外一個上不了網。
- 互通:同一台機器上的兩個虛擬機,如何通信。
- 靈活:會經常創建,刪除。從一個機器,漂移到另一個機器。
-
共享與互通:
在物理機上,有一個虛擬的交換機,linux可以創建虛擬網橋,創建出來以后,兩個虛擬機的虛擬網卡,都連接到虛擬網橋上,這樣兩個虛擬機配置相同的子網網段就可以互相通信了。
如果要訪問外部,有兩種方式
-
橋接
在你的物理機上,會發現多了幾個網卡,其實是虛擬交換機,這個交換機將虛擬機連接在一起,在橋接模式下,物理網卡也連接到虛擬交換機上。登陸虛擬機看ip地址會發現,虛擬機的地址和物理機的,以及周邊同事的是一個網段,是因為,相當於將物理機和虛擬機放在同一個網橋上,相當於這個網橋有三台機器,是一個網段的。如下圖
-
NAT模式
在這種模式下,登陸到虛擬機里查看ip地址,發現虛擬機的網絡時虛擬機的,物理機的網絡是物理機的,兩個不同,虛擬機要訪問物理機的時候,需要將地址NAT成為物理機的地址。
另外,它還會在你的實體機里內置一個DHCP服務器,為筆記本電腦上的虛擬機動態分配ip地址。為什么橋接方式不需要呢,因為橋接將網絡打平了,虛擬機的ip是由物理網絡的DHCP服務器分配。
-
隔離
brctl創建的網橋支持VLAN功能,設置兩個虛擬的tag,這樣在這個虛擬網橋上,兩個機器是不互通的,如果想要互通,有一個命令vconfig,基於物理網卡創建帶VLAN的虛擬網卡,從這個虛擬網卡出去的包,都帶這個VLAN。
首先每個用戶分配不同的VLAN,不同的用戶使用不同的虛擬網橋,帶VLAN的虛擬網卡也連接到虛擬網橋上。網橋不通,不能相互通信,也不會轉發到另一個網橋上,另外,出了物理機,也是帶vlan id的,只要物理交換機支持vlan,就可以轉發給相同vlan的網卡和網橋,所以跨物理機,不同的vlan也不會相互通信。
VLANid只有4096個,在大規模平台中明顯不夠用,另外流量的隔離還沒有實現,有大量改進的空間。
容器網絡
-
封閉環境的兩種技術
- 看起來隔離的技術,成為namespace,也即每個namespace 中的應用看到的是不同的 IP 地址、用戶空間、程號等。
- 用起來是隔離的技術,稱為cgroup,也即明明整台機器有很多的 CPU、內存,而一個應用只能用其中的一部分。
-
命名空間 namespace
linux下,很多資源是全局的,比如進程有全局的進程id,但是,當一台 Linux 上跑多個進程的時候,如果我們覺得使用不同的路由策略,這些 進程可能會沖突,那就需要將這個進程放在一個獨立的 namespace 里面,這樣就可以獨立配置 網絡了。 網絡的 namespace 由 ip netns 命令操作。它可以創建、刪除、查詢 namespace。
-
機制網絡 cgroup
cgroup全稱 control groups,是linux內核提供的一種可以限制,隔離進程使用的機制。他有如下子系統:
- CPU子系統使用調度進程為進程控制CPU的訪問
- cpuset,如果是多核心cpu,子系統會為進程分配單獨的cpu和內存
- memory子系統,設置進程的內存限制以及產生內存資源報告
- blkio,設置限制每個塊設備的輸入輸出控制
- net_cls,這個子系統使用等級識別符標記網絡數據包,可允許linux流量控制程序tc識別從具體cgroup中生成的數據包。
容器網絡中如何融入物理網絡
docker run的機構:
容器里面有張網卡,容器外有張網卡,容器外的網卡練到docker0網橋,通過這個網橋,容器直接實現相互訪問。在linux下可以創建一對veth pair網卡,一邊發送包,另一邊就能收到。
一邊可以達到docker0網橋上,另一端如何放到容器里呢。一個容器啟動會對應一個namespace,先找到namespace,pid就是namespace的名字,然后就可以將另一端veth2賽道namespace里面。這樣就使一台容器內不得互相訪問沒有問題了,那么如何訪問外網?docker默認使用NAT模式,如果內部訪問外部就要通過SNAT。
-
所有從容器內部發出來的包,都要做地址偽裝,將源ip地址,轉換為物理網卡的ip地址,如果有多個容器,所有的容器共享一個外網的ip地址。
-
當服務器返回結果的時候,到達物理機,取出原來的私網ip,通過DNAT將地址轉還為私網ip,通過網橋docker0實現對內的訪問。
-
如果在容器內部屬於一個服務,例如部署一個網站,提供給外部進行訪問,需要通過 Docker 的端口映射技術,將容器內部的端口映射到物理機上來。
例如容器內部監聽 80 端口,可以通 Docker run 命令中的參數 -p 10080:80,將物理機上的10080 端口和容器的 80 端口映射起來, 當外部的客戶端訪問這個網站的時候,通過訪問物理機的 10080 端口,就能訪問到容器內的 80 端口了。
docker有兩種方式,一種是通過一個進程docker-proxy的方式,監聽10080,轉換為80端口,另一種是通過DNAT方式,將端口10080的DNAT成為容器的私有網絡,這樣就可以實現容器和物理網絡之間的互通了。