Kubernetes手記(16)- 網絡通信
十六 網絡通信
K8S 的網絡通信完全由 CNI 接口上的插件來實現,插件需要實現以下集中通信模型。
目前比較流行的插件有:flannel、calico、canel、kube-router …
如何加載插件
k8s 在啟動的時候會去:/etc/cni/net.d/ 目錄下尋找網絡插件的配置文件,POD 在創建時候 k8s 調用這個配置文件,由插件根據這個配置文件進行創建網絡。
16.1 通信模型
容器間通信:同一個 POD 內多個容器間的通信,使用 lo 網卡通信
POD間通信:POD IP 直接與 POD IP 通信
POD 與 Service:POD IP 直接與 Cluster IP
Service 與集群外部客戶端的通信,ingress、NodePort、Loadbacer
16.2 通信模型底層
無論哪一種網絡插件,它們用到的底層方案都是以下幾種:
虛擬網橋:brg,用純軟件實現一個虛擬網卡,一端在POD上,一端在宿主機上接入到網橋或物理接口橋上,稱為隧道網絡。
多路復用:MacVLAN,基于 MAC 的方式創建 VLAN ,為每個虛擬接口配置一個獨立的 MAC 地址,使得一個物理網卡承載多個容器使用,這樣容器直接使用物理網卡,基于 MacVLAN 進行跨節點通信。
硬件交換:網卡支持硬件交換,SR-IOV (單根-IO虛擬化) 方式,這種網卡支持直接在物理級別虛擬出多個接口,高性能。
16.3 K8S 名稱空間
K8S 名稱空間與 POD 網絡名稱空間不在一個維度,所以即使在不同的 K8S 集群名稱空間內創建的不同 POD,也可以通過網絡直接通信。
而目前應用最廣的 flannel 網絡插件,是不支持這種不同集群命名空間的網絡隔離策略的。
calico 支持地址分配,也支持不同集群命名空間的網絡隔離策略,但是它使用較為復雜,支持 BGP 三層網絡轉發,性能比 flannel 強。
也可以使用 flannel 來做網絡管理,再安裝 calico 僅僅做集群命名空間網路隔離策略,這種搭配方案。
16.4 K8S網絡拓撲
所有 POD 連接到,本機 cni0 接口這個網絡,cni0 接口發出的報文到達 flannel.1 這個接口,這個接口將報文封裝為隧道協議,通過本機的真實的物理網卡發出。
查看本機的接口
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
下載 bridge-utils 包使用命令 brctl show cni0 查看 cni0 接口
bridge name bridge id STP enabled interfaces cni0 8000.9a6ec95f8285 no veth0c014b8b veth648a500f veth7a3f56b7 veth97c048e5 vethd2f0bf2b
16.5 flannel
flannel 是一個專為 kubernetes 定制的三層網絡解決方案,主要用于解決容器的跨主機通信問題。
16.5.1 flannel 工作模式
flannel.1 這個虛擬網卡支持多種傳輸模式:VxLAN、host-gw、Directrouting、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。
| | | |<------------------ VxLAN封裝 ----------------->|<----------- 原始報文 ------------->| +-----------+-----------+-----------+-----------+-----------+-----------+-----------+ | node 網絡 | node網絡 | node 網絡 | VxLan | POD MAC | POD IP | data | | 幀首部MAC | IP首部 | UDP 首部 | 首部 | 首部 | 首部 | Payload | +-----------+-----------+-----------+-----------+-----------+-----------+-----------+
16.5.3 flannel 部署方式
在 k8s 集群啟動前,flannel 直接部署到節點上,作為一個守護進程運行。
任何一個部署了 kubelet 的節點都應該部署 flannel ,因為 kubelet 要借助 flannel 為 POD 設置網絡接口
使用 kube-admin 直接將 k8s 自己的組件包括 flannel 運行在 k8s 之上的靜態 POD。
必須配置為共享 node 節點網絡名稱空間的 POD,所以 flannel POD 控制器為 DaemonSet。
16.5.4flannel 配置文件
配置文件選項含義
{ "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 // 是否使用直接路由模式 } }
flannel 托管到 k8s 上的配置文件,處于 kube-flannel-cfg 這個 configmap 中。
kubectl get configmap kube-flannel-cfg -n kube-system -o json
16.5.5 修改工作模式
修改 flannel 工作模式,添加 Directrouting,這個操作應該在剛剛部署完 k8s 集群時候修改,推薦修改
kubectl edit configmap kube-flannel-cfg -n kube-system
"Backend": { "Type": "vxlan", "Directrouting": true }
查看本機路由表
ip route show
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
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
下載清單文件,需要翻墻
kubectl apply -f https://docs.projectcalico.org/v3.6/getting-started/kubernetes/installation/hosted/canal/canal.yaml
16.6.2 清單定義
清單格式,詳見:kubectl explain networkpolicy
egress <[]Object> # 出站規則的對象列表 ports <[]Object> # 目標端口的對象列表 port
16.6.3 policyTypes
首先定義 名稱空間
kubectl create namespace dev kubectl create namespace prod
在兩個命名空間分別創建一個 POD
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
kubectl apply -f pod-a.yaml -n dev
拒絕所有 dev 空間的報文
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress namespace: dev spec: podSelector: {} # {} 空的選擇器表示選擇全部 policyTypes: - Ingress # 指明 Ingress 規則生效,匹配 Ingress 將被放行,如果沒定義 Ingress 則不能匹配所有,會拒絕全部 # policyTypes 沒有 Egress 表示不控制 Egress ,默認為允許
在指定命名空間應用規則文件
kubectl apply -f deny-all-ingress.yaml -n dev
查看規則
kubectl get networkpolicy -n dev
查看 dev 空間中的 POD 地址并訪問,結果是不能訪問,因為這個命名空間拒絕外部訪問
kubectl get pods -n dev -o wide
curl 10.244.1.2
查看 prod 空間中的 POD 地址并訪問,結果可以訪問,因為這個命名空間沒有定義規則
kubectl get pods -n dev -o wide
curl 10.244.2.2
允許指定網段的 POD 訪問本 POD 的 80 端口
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 ,默認為允許
查看規則
kubectl get networkpolicy -n dev
拒絕出棧的所有請求
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-egress namespace: prod spec: podSelector: {} # {} 空的選擇器表示選擇全部 policyTypes: - Egress # 指明 Egress 規則生效,匹配 Egress 將被放行,如果沒定義 Egress 則不能匹配所有,拒絕全部 # policyTypes 沒有 Ingress 表示不控制 Egress ,默認為允許
其他
自己將手記發在:https://github.com/redhatxl/awesome-kubernetes-notes
歡迎一鍵三連
Kubernetes 網絡
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。