Linux 虛擬網絡
Network Namespace
- Linux內核提供的功能
- 實現網絡虛擬化的重要功能
- 能創建多個隔離的網絡空間
- 每個空間有獨立的網絡棧
- 多個空間之間試圖隔離互不干擾
虛擬網絡設備
- veth
屬於可轉移設備,就是可以在不同namespace種進行轉移的設備
是成對出現的虛擬網絡設備,發送到Veth一端虛擬設備的請求會從另一端的虛擬設備中發出,在容器的虛擬化場景中,會使用Veth來鏈接不同網絡的namespace
linux 提供了 veth pair 。可以把 veth pair 當做是雙向的 pipe(管道),從一個方向發送的網絡數據,可以直接被另外一端接收到;或者也可以想象成兩個 namespace 直接通過一個特殊的虛擬網卡連接起來,可以直接通信。
-
lo
自身的迴環設備 -
vxlan
什麼是vxlan?
vxlan是一種網絡虛擬化技術,通過把源主機發出的數據包封裝在UDP中.並且使用物理網絡的IP,MAC作爲外層頭進行封裝,然後在IP網絡上傳輸,到達目的地後由隧道終結點解封裝並把數據發送給目標主機.
什麼是隧道技術?
是一種數據包封裝技術.可以把原始IP包封裝在另外一個數據包的數據淨荷中進行傳輸.
使用隧道的原因是在不兼容的網絡上傳輸數據或者在不安全網絡上提供一個安全路徑.
- bridge 網橋
veth pair只能實現兩個網絡接口之間的通信
如果實現多個網絡接口之間的通信。就是Bridge網橋技術。簡單說來,網橋就是把一臺機器上的若干個網絡接口連接起來。結果就是其中一個網口收到的報文會被轉發到其他網口。實現了不同網絡接口之間的報文相互轉發
網橋工作原理
網橋對報文的轉發基於MAC地址,網橋能夠解析收發的報文,讀取目標MAC地址的信息,然後根據自己的MAC表信息,來決定轉發的目標網絡端口
如果遇到一個從來沒有記錄過的地址,可以廣播給所有的網絡端口
多個網絡端口藉助網橋進行通信與報文轉發
Linux內核通過一個虛擬的網橋設備實現橋接,這個虛擬設備可以綁定若干個以太網接口設備,從而把他們連接起來
對於協議棧上層,只看得到br0,上層協議棧需要發送報文到br0種,網橋設備的處理代碼再判斷報文被轉發到eth0或者是eth1.
反過來,從eth0或者eth1接收到的報文被提交給網橋的處理代碼,也會在br0判斷報文應該被轉發丟棄還是提交到協議棧上層
iptables/netfilter
- iptables是Linux實現的防火牆,可以理解爲一個客戶端代理
- netfilter是真正的防火牆框架
- 兩者組成了具有封包過濾,封包重定向和地址轉換(NAT)功能的包過濾防火牆
Docker 網絡模型
- Docker使用Linux的Bridge技術,在宿主機虛擬一個Docker容器網橋(docker0),Docker啓動一個容器的時候會根據Docker網橋的網段分配給容器一個IP地址,即Container-IP
- 同時Docker網橋是每個容器的默認網關
- 因爲同一個宿主機內的容器都接入同一個網橋,所以容器之間能夠通過容器的Container-IP直接通信
四種Docker 網絡模式
- host模式
容器直接使用宿主機的IP和端口.但是容器的文件系統,進程列表等還是和宿主機隔離
使用host模式的容器可以直接使用宿主機的IP地址和外界通信.容器內部的服務端口可以使用宿主機的端口,不需要進行NAT.host最大優勢是網絡性能比較好.
缺點: 端口沒有做隔離,會有端口占用現象
- container模式
指定新創建的容器和已經存在的一個容器共享一個Network Namespace.
新創建容器不會創建自己的網卡和配置自己的IP,而是和一個指定的容器共享IP,端口範圍等
兩個容器除了網絡,其他如文件系統,進程列表還是隔離的
兩個容器的進程通過lo網卡設備通信 (localhost)
- none模式
Docker容器沒有進行任何網絡配置.Docker容器沒有網卡,IP,路由等信息.需要我們自己爲Docker容器添加網卡,配置IP
網絡模式下容器只有lo迴環網絡.這種網絡沒有辦法聯網,封閉網絡能夠很好保證容器的安全性.
bridge模式
在宿主機創建一個叫docker0的虛擬網橋.
宿主機上啓動的Docker容器會連接到這個虛擬網橋上
這個虛擬網橋工作方式和物理交換機類似 主機所有容器通過交換機連在一個二層網絡中
從docker0子網中分配一個IP給容器使用,並且設置docker0的IP地址作爲容器的默認網關.在主機上創建一對虛擬網卡設備veth pair.
Docker把veth pair設備的一端放在新創建的容器中,命名爲eth0
另外一端放在宿主機上,以vethxxx這樣的方式命名.然後把這個網絡設備加入到docker0網橋中.
bridge模式就是docker的默認網絡模式.
K8s 網絡模型
約法三章:
- 任意Pod之間可以直接通信,無需經過顯式使用NAT來接收數據和地址的轉換
- node和pod之間可以直接通信.無需使用明顯地址轉換
- pod的私有ip(自己看到自己的ip)和別人看到它所用的ip是一樣的,中間不會經過轉換
四大目標:
搞清楚
- 外部世界和service之間如何通信?
- service如何與pod通訊?
- pod和pod之間調用怎麼做到通信?
- pod內部容器之間的通信?
本文解決後面兩個問題
容器網絡方案:
大體分爲Underlay 和 Overlay兩種方案
-
underlay
與host網絡同層,與host網絡使用同樣的網段,輸入輸出基礎設備,容器IP地址是不是需要與host網絡取得協同.啥意思呢,就是ip地址是否由host網絡來進行中心分配或者統一劃分. -
overlay
不一樣的地方:並不需要從host網絡的ipm的管理組件去申請IP
只需要與host網絡不衝突,這個ip可以自由分配
總結: underlay和overlay區別在於容器網絡是否與宿主機網絡同層
Netns
Network Namespace
runC容器的技術不依賴於任何硬件,執行基礎就在內核裏面.進程內核代表就是task.
如果不需要隔離,那麼用的主機空間就是主機的空間,不需要設置特別的空間隔離數據結構.
- Network namespace是實現網絡虛擬化的內核基礎,創建了隔離的網絡空間.一個namespace裏面,
- 有獨立的附屬網絡設備(lo,veth等虛擬設備/物理網卡)
- 獨立的協議棧,IP地址和路由表
- iptables規則
- ipvs等
ipvs 是啥?iptables是啥?
ipvs
- IP Virtual Server
實現了傳輸層負載均衡.也就是通常所說的4層LAN,作爲Linux內核一部分.
ipvs運行在主機上,在真實的服務器集羣中充當負載均衡器.
ipvs可以將基於TCP和UDP的服務請求轉發到真實的服務器.使得真實服務器的服務在單個IP地址上顯示爲虛擬服務.
iptables
iptables不是防火牆.我們可以理解成一個客戶端代理.用戶通過iptables這個代理,把用戶的安全設定執行到防火牆中
先回顧以下報文從網卡到
當客戶端訪問服務端的web服務的時候,客戶端發送報文到網卡。
tcp/ip協議棧是內核的一部分,所以客戶端的信息會通過內核的TCP協議傳輸到用戶空間的web服務中。
這個時候客戶端報文的終點爲web服務監聽的套接字。
我們所說的防火牆,是內核空間的一部分,所有進出報文都需要通過關卡。符合條件的關卡纔可以放行。
這些關卡在iptables中稱爲"鏈"
上面那個是demo啦
當我們開啓了防火牆功能的時候,報文需要經過以下關卡,也就是要根據實際情況不同,報文經過的轉發鏈其實是不同的。
下圖中紅色的框就是“鏈”,鏈是因爲每個關卡中所有規則都會串成一條鏈。
報文只有滿足鏈上所有規則的時候才能通過這個關卡。
到本機某進程的報文: PREROUTING -> INPUT
由本機轉發的報文: PREROUTING -> FORWARD -> POSTROUTING
由本機的某進程發出報文: OUTPUT->POSTROUTING
我們回到K8s網絡的討論
如果網絡是需要隔離的話,並不需要特別設置空間隔離數據結構(nsproxy)
一個隔離的網絡空間會有什麼?
-
有自己的網卡或者是網絡設備
-
網卡可能是虛擬的,也可能是物理網卡
-
擁有自己的IP地址,IP表和路由表
-
擁有自己的協議棧
-
擁有自己的status
-
擁有自己的iptables和ipvs
-
Pod和Netns的關係
每個Pod都有獨立的網絡空間。
所有容器都會通過pod的IP對外提供服務。
宿主機還有Root namespace,可以看作成一個特殊的網絡空間,不過pid爲1
K8s的容器網絡實現方案
- Flannel 最爲普遍的實現,可以提供多種網絡backend的實現
- Calico 主要採用策略路由,節點之間採用BGP協議進行路由同步
- Cilium Flannel和Calico優點集合的產物
- WeaveNet 可以對數據做加密
Flannel
- 目前最爲普遍的方案,通過把backend機制獨立,支持多種數據路徑,也可以適用於overlay/underlay多種場景
- 封裝可以選用用戶態udp,內核Vxlan,如果集羣規模不大,處在同一二層域,那麼也可以採用host-gw方式
上面解決的是容器的包如何到達host,這裏通過加一個網橋Bridge.它的bckend其實是獨立的,也就是這個包如何離開host,採用何種封裝方法,或者是是否需要封裝,都是可選擇的。
Network Policy
提供基於策略的的網絡控制,用來隔離應用並且減少攻擊面。
使用Node Selector模擬傳統的分段網絡,並且通過策略控制他們之間的流量以及來自外部的流量,因爲我們約法三章的時候提到Pod之間是可以實現全互聯的。帶來的問題是,在K8s集羣中,可能希望某些Pod不能去訪問其他的Pod,這個時候需要用到策略。
Network Policy需要決定:
- 控制對象,如實例裏面的spec部分,通過podSelector或者是namespace中的selector來選擇一組特定的pod來接受我們控制
- 決定流向考慮 需要控制入方向還是出方向
流與端口
Network Policy之前,需要注意
- apiserver開啓extensions/v1beta1/networkpolicies
- 網絡插件要支持Network Policy,例如Calico,Romana,Weave Net和trireme
下面我們着重解決文章開始提出的問題:
Pod內容器之間如何通信?
簡而言之,container之間的默認網關都是Docker網橋,同一個宿主機內的容器都接入同一個網橋,那麼容器之間可以通過容器的Container-IP直接通信
- IP在K8s中是以Pod爲單位進行分配的
- 一個Pod內部的所有容器會共享一個網絡堆棧(共享網絡命名空間,包括IP地址,網絡設備和配置)
- 所以一個Pod的容器之間是不會跨宿主機進行操作的。
- Pod其實就相當於一個邏輯主機,所以一個Pod內部的容器都好像在一臺機器上一樣,甚至可以用localhost地址訪問彼此的端口。
Pod之間的通信
分爲兩類:同一個Node內的Pod之間的通信,和不同Node之間Pod的通信。
- 同一個Node內部的Pod通信
每個Pod都有一個真實的全局IP地址。
Pod1和Pod2都是通信veth pair連接到同一個docker0網橋上
它們的IP1,IP2都是通過docker0動態獲取。他們和網橋本身的IP3是在同一個網段。
Pod1和Pod2處於同一個局域網,他們之間可以通過docker0作爲路由來進行通信。
不同Node上的Pod之間的通信
Pod之間假設通過訪問對方的Pod IP進行通信。
不同Node之間的通信只能通過Node的物理網卡進行
Pod的IP地址由各個Node上的docker0網橋動態分配。
需要滿足三個條件
- 我們知道Pod IP 和 Node IP之間映射關係,通過NodeIP轉發到Pod IP
- 整個Kubernetes集羣中對Pod的IP分配不能出現衝突
- 從Pod發出的數據包不應該進行NAT地址轉換
對於第一個條件:K8s會記錄Pod IP和Node IP之間的映射關係,信息保存在etcd中
對於第二個條件:以Flannel實現的容器跨主機通信爲例,我們做解析
- 每個主機上安裝並運行etcd和flannel
- 在etcd中規劃配置所有主機的docker0子網範圍
- 每個主機上的flannelID根據etcd中的配置,爲本主機的docker0分配子網,保證所有主機上的網段不重複。然後再把結果存入etcd中。etcd存儲主機上docker子網信息和本主機IP的對應關係(key:value - docker子網:本主機ip)
- 當需要與其他主機上的容器進行通信的時候,查找etcd數據庫,找到目的容器子網對應的宿主機ip
- 裝包: 把原始數據包封裝在VXLAN或者是UDP數據包中。IP層以宿主機目的IP進行封裝
- VXLAN或者UDP數據包到達目的宿主機解封裝
ref
https://www.cnblogs.com/hongdada/p/9758939.html
K8s網絡實現
https://www.jianshu.com/p/22a7032bb7bd