kubernetes從入門到精通系列16-網絡通信

kubernetes從入門到精通系列目錄:


kubernetes從入門到精通系列16-網絡通信


K8S 的網絡通信完全由 CNI 接口上的插件來實現,插件需要實現以下集中通信模型。

目前比較流行的插件有:flannel、calico、canel、kube-router …

  • 如何加載插件

k8s 在啟動的時候會去:/etc/cni/net.d/ 目錄下尋找網絡插件的配置文件,POD 在創建時候 k8s 調用這個配置文件,由插件根據這個配置文件進行創建網絡。

16.1 通信模型

  1. 容器間通信:同一個 POD 內多個容器間的通信,使用 lo 網卡通信
  2. POD間通信:POD IP 直接與 POD IP 通信
  3. POD 與 Service:POD IP 直接與 Cluster IP
  4. Service 與集群外部客戶端的通信,ingress、NodePort、Loadbacer

16.2 通信模型底層

無論哪一種網絡插件,它們用到的底層方案都是以下幾種:

  1. 虛擬網橋:brg,用純軟件實現一個虛擬網卡,一端在POD上,一端在宿主機上接入到網橋或物理接口橋上,稱為隧道網絡。
  2. 多路複用:MacVLAN,基於 MAC 的方式創建 VLAN ,為每個虛擬接口配置一個獨立的 MAC 地址,使得一個物理網卡承載多個容器使用,這樣容器直接使用物理網卡,基於 MacVLAN 進行跨節點通信。
  3. 硬件交換:網卡支持硬件交換,SR-IOV (單根-IO虛擬化) 方式,這種網卡支持直接在物理級別虛擬出多個接口,高性能。

16.3 K8S 名稱空間

K8S 名稱空間與 POD 網絡名稱空間不在一個維度,所以即使在不同的 K8S 集群名稱空間內創建的不同 POD,也可以通過網絡直接通信。

而目前應用最廣的 flannel 網絡插件,是不支持這種不同集群命名空間的網絡隔離策略的。

calico 支持地址分配,也支持不同集群命名空間的網絡隔離策略,但是它使用較為複雜,支持 BGP 三層網絡轉發,性能比 flannel 強。

也可以使用 flannel 來做網絡管理,再安裝 calico 僅僅做集群命名空間網路隔離策略,這種搭配方案。

16.4 K8S網絡拓撲

所有 POD 連接到,本機 cni0 接口這個網絡,cni0 接口發出的報文到達 flannel.1 這個接口,這個接口將報文封裝為隧道協議,通過本機的真實的物理網卡發出。

  • 查看本機的接口
<code>1: lo:                       # 本地迴環
2: ens33: # 主機物理網卡
3: docker0: # docker 默認的橋接網絡,在 k8s 中無用可以刪除
4: dummy0: #
5: kube-ipvs0: #
6: flannel.1: # flannel 虛擬網卡,封裝隧道報文
7: cni0: # 所有容器處於這個網橋
8: veth0c014b8b@if3: # 容器的網卡連接到 cni0
9: veth97c048e5@if3: # 容器的網卡連接到 cni0
11: vethd2f0bf2b@if3: # 容器的網卡連接到 cni0
12: veth648a500f@if3: # 容器的網卡連接到 cni0
/<code>
  • 下載 bridge-utils 包使用命令 brctl show cni0 查看 cni0 接口
<code>bridge    name    bridge id           STP    enabled    interfaces
cni0 8000.9a6ec95f8285 no veth0c014b8b
veth648a500f
veth7a3f56b7
veth97c048e5
vethd2f0bf2b
/<code>

16.5 flannel

flannel 是一個專為 kubernetes 定製的三層網絡解決方案,主要用於解決容器的跨主機通信問題。

16.5.1 flannel 工作模式

  • flannel.1 這個虛擬網卡支持多種傳輸模式:VxLAN、host-gw、Directrouting、udp

模式介紹VXLAN使用 VxLAN 作為隧道封裝報文host-gw不使用疊加網絡,而是在主機的路由表中創建到其他主機 subnet 的路由條目,性能較好,缺陷是:所有 node 節點必須處於同一個二層網絡中。DirectRou ting當主機位於同一子網時啟用直接路由,不在回退到 VxLAN。UDP直接使用 UDP 協議,性能差

16.5.2 VXLAN 通信過程

Flannel VXLAN 實質上是一種 “覆蓋網絡(overlay network)” ,也就是將TCP數據包裝在另一種網絡包裡面進行路由轉發和通信,目前已經支持UDP、VxLAN、AWS VPC和GCE路由等數據轉發方式。

  • flannel VXLAN 通信過程

在 K8S 上 POD 與 POD 是直接通過對方的 IP 地址進行通信的,POD 發出的報文經過 cni0 網橋到達 flannel ,flannel 將報文封裝上一層 VxLAN 的首部,外層又被封裝一層 UDP 協議的首部,發送給本機物理網卡,本機物理網卡又將 flannel 發過來的報文外層封裝上 IP 首部和以太網幀首部(MAC)由網卡發出,另外一個 node 節點收到報文,內核發現是一個 VxLAN 的包,拆掉 IP 首部送給 flannel 應用程序,flannel 拆掉 VxLAN 首部並將內部的數據發送給,cni0 網橋,cni0 收到後轉發給 POD。

<code>|                                               |                                   |
|||
+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| node 網絡 | node網絡 | node 網絡 | VxLan | POD MAC | POD IP | data |
| 幀首部MAC | IP首部 | UDP 首部 | 首部 | 首部 | 首部 | Payload |
+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
/<code>

16.5.3 flannel 部署方式

  1. 在 k8s 集群啟動前,flannel 直接部署到節點上,作為一個守護進程運行。
<code>任何一個部署了 kubelet 的節點都應該部署 flannel ,因為 kubelet 要藉助 flannel 為 POD 設置網絡接口
/<code>
  1. 使用 kube-admin 直接將 k8s 自己的組件包括 flannel 運行在 k8s 之上的靜態 POD。
<code>必須配置為共享 node 節點網絡名稱空間的 POD,所以 flannel POD 控制器為 DaemonSet。
/<code>

16.5.4flannel 配置文件

  • 配置文件選項含義
<code>{
"Network": "10.244.0.0/16", // flannel 使用的 CIDR 格式的網絡地址,用於為 POD 配置網絡功能
"SubnetLen": 24, // 把 Network 切分為子網供各 node 節點使用時,使用多長的掩碼切分,默認為 24

"SubnetMin": "10.244.10.0/24", // 用於分配給 node 的子網起始地址,從這個網絡開始分配網絡
"SubnetMax": "10.244.255.0/24" // 用於分配給 nide 的子網結束位置,這個是最大分配的網路
"Backend": { // 指明 POD 與 POD 跨節點通信時候使用的 flannel 工作模式
"Type": "vxlan", // 工作模式
"Directrouting": true // 是否使用直接路由模式
}
}
/<code>
  • flannel 託管到 k8s 上的配置文件,處於 kube-flannel-cfg 這個 configmap 中。
<code>kubectl get configmap kube-flannel-cfg -n kube-system -o json
/<code>

16.5.5 修改工作模式

  • 修改 flannel 工作模式,添加 Directrouting,這個操作應該在剛剛部署完 k8s 集群時候修改,推薦修改
<code>kubectl edit configmap kube-flannel-cfg -n kube-system
/<code>
<code>"Backend": {
"Type": "vxlan",
"Directrouting": true
}
/<code>
  • 查看本機路由表
<code>ip route show 

/<code>
<code>default via 172.16.100.254 dev ens33 proto static metric 100
10.244.1.0/24 via 10.244.1.0 dev ens33 # 必須為 dev 物理網卡接口,否則 Directrouting 沒有設置成功
10.244.2.0/24 via 10.244.2.0 dev ens33 # 必須為 dev 物理網卡接口,否則 Directrouting 沒有設置成功
172.16.100.0/24 dev ens33 proto kernel scope link src 172.16.100.101 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
/<code>

16.6 Calico

Calico 創建和管理⼀個扁平的三層網絡(不需要 overlay),每個容器會分配一個可路由的 ip。由於通信時不需要解包和封包,網絡性能損耗小,易於排查,且易於水平擴展。

小規模部署時可以通過 bgp client 直接互聯,大規模下可通過指定的 BGP route reflector 來完成,這樣保證所有的數據流量都是通過 IP 路由的方式完成互聯的。

Calico 基於 iptables 還提供了豐富而靈活的網絡 Policy,保證通過各個節點上的 ACLs 來提供 Workload 的多租戶隔離、安全組以及其他可達性限制等功能。

有個新的項目:canel,它集合了 flannel 和 calico 的優點。

  • 注意

Calico 目前不支持工作在 iptables 下的 kube-proxy,下面介紹 canal 網絡策略的使用

16.6.1 安裝 canal

  • 下載清單文件,需要翻牆
<code>kubectl apply -f https://docs.projectcalico.org/v3.6/getting-started/kubernetes/installation/hosted/canal/canal.yaml
/<code>

16.6.2 清單定義

  • 清單格式,詳見:kubectl explain networkpolicy
<code>egress                      # 出站規則的對象列表
ports # 目標端口的對象列表
port <string> # 數字形式或者是命名的端口
protocol # 協議 TCP、UDP
to # 目標地址對象列表
ipBlock <object> # 一組 IP 地址
cidr <string> # CIDR 表示的 IP 範圍
except # 排除 CIDR 中的某些地址
namespaceSelector <object> # 名稱空間選擇器
podSelector <object> # POD 選擇器,目標地址可以也是一組 POD
ingress # 入站規則的對象列表
from # 源地址對象列表
ipBlock <object> # 一組 IP 地址
cidr <string> # CIDR 表示的 IP 範圍
except # 排除 CIDR 中的某些地址
namespaceSelector <object> # 名稱空間選擇器
podSelector <object> # POD 選擇器,源地址也可以是一組 POD
ports # POD 自己的端口,表示控制自己的端口是否可以被訪問,的對象列表

port # 數字形式或者是命名的端口
protocol # 協議 TCP、UDP
podSelector <object> # POD 選擇器決定規則應用在哪些 POD 上
policyTypes # 可以是 "Ingress", "Egress", 或者 "Ingress,Egress" ,表示放行滿足這些規則訪問
/<object>/<object>/<object>/<string>/<object>/<object>/<object>/<string>/<object>/<string>/<code>

16.6.3 policyTypes

  • 首先定義 名稱空間
<code>kubectl create namespace dev
kubectl create namespace prod
/<code>
  • 在兩個命名空間分別創建一個 POD
<code>apiVersion: v1
kind: Pod
metadata:
name: pod1
namespace: dev
labels:
app: myapp
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1

---
apiVersion: v1
kind: Pod
metadata:
name: pod1
namespace: prod
labels:
app: myapp
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1

/<code>
<code>kubectl apply -f pod-a.yaml -n dev
/<code>
  • 拒絕所有 dev 空間的報文
<code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: dev
spec:
podSelector: {} # {} 空的選擇器表示選擇全部
policyTypes:
- Ingress # 指明 Ingress 規則生效,匹配 Ingress 將被放行,如果沒定義 Ingress 則不能匹配所有,會拒絕全部
# policyTypes 沒有 Egress 表示不控制 Egress ,默認為允許
/<code>
  • 在指定命名空間應用規則文件
<code>kubectl apply -f deny-all-ingress.yaml -n dev
/<code>
  • 查看規則
<code>kubectl get networkpolicy -n dev
/<code>
  • 查看 dev 空間中的 POD 地址並訪問,結果是不能訪問,因為這個命名空間拒絕外部訪問
<code>kubectl get pods -n dev -o wide
/<code>
<code>curl 10.244.1.2
/<code>
  • 查看 prod 空間中的 POD 地址並訪問,結果可以訪問,因為這個命名空間沒有定義規則
<code>kubectl get pods -n dev -o wide
/<code>
<code>curl 10.244.2.2
/<code>
  • 允許指定網段的 POD 訪問本 POD 的 80 端口
<code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-80-ingress
namespace: dev
spec:
podSelector:
matchLabels:
app: myapp
ingress:
- from:
- ipBlock: # 指定源地址為 IP 地址塊
cidr: 10.244.0.0/16 # 掩碼形式指出源地址 IP 地址範圍
except: # 排除 cidr 範圍內的某個地址
- 10.244.1.2/32
ports:
- port: 80 # 入棧且目標端口為 80 的則匹配
protocol: TCP
- port: 443
protocol: TCP
policyTypes:

- Ingress # 指明 Ingress 規則生效,匹配 Ingress 將被放行,如果沒定義 Ingress 則不能匹配所有,拒絕全部
# policyTypes 沒有 Egress 表示不控制 Egress ,默認為允許
/<code>
  • 查看規則
<code>kubectl get networkpolicy -n dev
/<code>
  • 拒絕出棧的所有請求
<code>apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: prod
spec:
podSelector: {} # {} 空的選擇器表示選擇全部
policyTypes:
- Egress # 指明 Egress 規則生效,匹配 Egress 將被放行,如果沒定義 Egress 則不能匹配所有,拒絕全部
# policyTypes 沒有 Ingress 表示不控制 Egress ,默認為允許/<code>


分享到:


相關文章: