一 網絡基礎知識
1.1 交換技術
交換技術指局域網進行網絡劃分之後,解決網絡通信問題的一種技術。分爲二層交換、三層交換、多層交換等等。
- 二層交換:一個局域網內部,數據包通過arp協議進行傳輸的網絡技術。
- 服務器通過arp協議獲取mac地址,封裝成數據幀進行數據傳遞
- 每個服務器都有arp緩存表,用來緩存局域網內的ip、mac條目,當交換機找不到目標ip的mac時,會通過arp協議進行廣播,被廣播的區域稱爲廣播域,通常一個相同網段的虛擬局域網是一個廣播域。
- 三層交換:引入路由表的交換機,稱爲路由器,解決不同網段進行通信的問題,比如上面三個不同網段的服務器(三個vlan),需要通過路由器進行相互通信
1.2 路由技術
路由器主要分爲兩個端口類型:LAN口和WAN口
- WAN口:配置公網IP,接入到互聯網,轉發來自LAN口的IP數據包。
- LAN口:配置內網IP(網關),連接內部交換機。
路由器是連接兩個或多個網絡的硬件設備,將從端口上接收的數據包,根據數據包的目的地址智能轉發出去。
路由器的功能:
- 路由
- 轉發
- 隔離子網
- 隔離廣播域
路由器是互聯網的樞紐,是連接互聯網中各個局域網、廣域網的設備,相比交換機來說,路由器的數據轉發很複雜,它會根據目的地址給出一條最優的路徑。那麼路徑信息的來源有兩種:動態路由和靜態路由。
靜態路由: 指人工手動指定到目標主機的地址然後記錄在路由表中,如果其中某個節點不可用則需要重新指定。
動態路由:則是路由器根據動態路由協議自動計算出路徑永久可用,能實時地適應網絡結構的變化。
常用的動態路由協議:
- RIP( Routing Information Protocol ,路由信息協議)
- OSPF(Open Shortest Path First,開放式最短路徑優先)
- BGP(Border Gateway Protocol,邊界網關協議)
1.3 OSI七層模型
OSI(Open System Interconnection)是國際標準化組織(ISO)制定的一個用於計算機或通信系統間互聯的標準體系,一般稱爲OSI參考模型或七層模型。
層次 | 名稱 | 功能 | 協議數據單元(PDU) | 常見協議 |
---|---|---|---|---|
7 | 應用層 | 爲用戶的應用程序提供網絡服務,提供一個接口。 | 數據 | HTTP、FTP、Telnet |
6 | 表示層 | 數據格式轉換、數據加密/解密 | 數據單元 | ASCII |
5 | 會話層 | 建立、管理和維護會話 | 數據單元 | SSH、RPC |
4 | 傳輸層 | 建立、管理和維護端到端的連接 | 段/報文 | TCP、UDP |
3 | 網絡層 | IP選址及路由選擇 | 分組/包 | IP、ICMP、RIP、OSPF |
2 | 數據鏈路層 | 硬件地址尋址,差錯效驗等。 | 幀 | ARP、WIFI |
1 | 物理層 | 利用物理傳輸介質提供物理連接,傳送比特流。 | 比特流 | RJ45、RJ11 |
1.4 TCP/UDP
TCP(Transmission Control Protocol,傳輸控制協議),面向連接協議,雙方先建立可靠的連接,再發送數據。適用於傳輸數據量大,可靠性要求高的應用場景。
UDP(User Data Protocol,用戶數據報協議),面向非連接協議,不與對方建立連接,直接將數據包發送給對方。適用於一次只傳輸少量的數據,可靠性要求低的應用場景。相對TCP傳輸速度快。
二 K8S網絡模型
Kubernetes 要求所有的網絡插件實現必須滿足如下要求:
- 一個Pod一個IP
- 所有的 Pod 可以與任何其他 Pod 直接通信,無需使用 NAT 映射
- 所有節點可以與所有 Pod 直接通信,無需使用 NAT 映射
- Pod 內部獲取到的 IP 地址與其他 Pod 或節點與其通信時的 IP 地址是同一個。
2.1 Docker容器網絡模型
先看下Linux網絡名詞:
- 網絡的命名空間: Linux在網絡棧中引入網絡命名空間,將獨立的網絡協議棧隔離到不同的命令空間中,彼此間無法通信;Docker利用這一特性,實現不同容器間的網絡隔離。
- Veth設備對: Veth設備對的引入是爲了實現在不同網絡命名空間的通信。
- Iptables/Netfilter: Docker使用Netfilter實現容器網絡轉發。
- 網橋: 網橋是一個二層網絡設備,通過網橋可以將Linux支持的不同的端口連接起來,並實現類似交換機那樣的多對多的通信。
- 路由: Linux系統包含一個完整的路由功能,當IP層在處理數據發送或轉發的時候,會使用路由表來決定發往哪裏。
Docker容器網絡示意圖如下:
2.2 Pod 網絡
問題: Pod是K8S最小調度單元,一個Pod由一個容器或多個容器組成,當多個容器時,怎麼都用這一個Pod IP?
實現: k8s會在每個Pod裏先啓動一個infra container小容器,然後讓其他的容器連接進來這個網絡命名空間,然後其他容器看到的網絡試圖就完全一樣了。即網絡設備、IP地址、Mac地址等。這就是解決網絡共享的一種解法。在Pod的IP地址就是infra container的IP地址。
在 Kubernetes 中,每一個 Pod 都有一個真實的 IP 地址,並且每一個 Pod 都可以使用此 IP 地址與 其他 Pod 通信。
Pod之間通信會有兩種情況:
- 兩個Pod在同一個Node上
- 兩個Pod在不同Node上
先看下第一種情況:兩個Pod在同一個Node上
同節點Pod之間通信道理與Docker網絡一樣的,如下圖:
- 對 Pod1 來說,eth0 通過虛擬以太網設備(veth0)連接到 root namespace;
- 網橋 cbr0 中爲 veth0 配置了一個網段。一旦數據包到達網橋,網橋使用ARP 協議解析出其正確的目標網段 veth1;
- 網橋 cbr0 將數據包發送到 veth1;
- 數據包到達 veth1 時,被直接轉發到 Pod2 的 network namespace 中的 eth0 網絡設備。
再看下第二種情況:兩個Pod在不同Node上
K8S網絡模型要求Pod IP在整個網絡中都可訪問,這種需求是由第三方網絡組件實現。
2.3 CNI(容器網絡接口)
CNI(Container Network Interface,容器網絡接口):是一個容器網絡規範,Kubernetes網絡採用的就是這個CNI規範,CNI實現依賴兩種插件,一種CNI Plugin是負責容器連接到主機,另一種是IPAM負責配置容器網絡命名空間的網絡。
CNI插件默認路徑:
# ls /opt/cni/bin/
地址:https://github.com/containernetworking/cni
當你在宿主機上部署Flanneld後,flanneld 啓動後會在每臺宿主機上生成它對應的CNI 配置文件(它其實是一個 ConfigMap),從而告訴Kubernetes,這個集羣要使用 Flannel 作爲容器網絡方案。
CNI配置文件路徑:
/etc/cni/net.d/10-flannel.conflist
當 kubelet 組件需要創建 Pod 的時候,先調用dockershim它先創建一個 Infra 容器。然後調用 CNI 插件爲 Infra 容器配置網絡。
這兩個路徑在kubelet啓動參數中定義:
--network-plugin=cni \
--cni-conf-dir=/etc/cni/net.d \
--cni-bin-dir=/opt/cni/bin
三 Kubernetes網絡組件之 Flannel
Flannel是CoreOS維護的一個網絡組件,Flannel爲每個Pod提供全局唯一的IP,Flannel使用ETCD來存儲Pod子網與Node IP之間的關係。flanneld守護進程在每臺主機上運行,並負責維護ETCD信息和路由數據包。
3.1 Flannel 部署
https://github.com/coreos/flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
3.2 Flannel工作模式及原理
Flannel支持多種數據轉發方式:
- UDP:最早支持的一種方式,由於性能最差,目前已經棄用。
- VXLAN:Overlay Network方案,源數據包封裝在另一種網絡包裏面進行路由轉發和通信
- Host-GW:Flannel通過在各個節點上的Agent進程,將容器網絡的路由信息刷到主機的路由表上,這樣一來所有的主機都有整個容器網絡的路由數據了。
3.3 vxlan模式
# kubeadm部署指定Pod網段
# kubeadm init --pod-network-cidr=10.244.0.0/16
# 二進制部署指定
# cat /opt/kubernetes/cfg/kube-controller-manager.conf
--allocate-node-cidrs=true \
--cluster-cidr=10.244.0.0/16 \
# kube-flannel.yml
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
vxlan模式數據傳輸流程
如果Pod 1訪問Pod 2,源地址10.244.1.10,目的地址10.244.2.10 ,數據包傳輸流程如下:
-
容器路由: 容器根據路由表從eth0發出
-
主機路由: 數據包進入到宿主機虛擬網卡cni0,根據路由錶轉發到flannel.1虛擬網卡,也就是,來到了隧道的入口。
# ip route
default via 192.168.217.2 dev ens33 proto static metric 100
10.244.0.0/24 via 10.244.0.0 dev flannel.1 onlink
10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.1
10.244.2.0/24 via 10.244.2.0 dev flannel.1 onlink
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.217.0/24 dev ens33 proto kernel scope link src 192.168.217.141 metric 100
- VXLAN封裝: 而這些VTEP設備(二層)之間組成二層網絡必須要知道目的MAC地址。這個MAC地址從哪獲取到呢?其實在flanneld進程啓動後,就會自動添加其他節點ARP記錄,可以通過ip命令查看,如下所示:
# ip neigh show dev flannel.1
10.244.2.0 lladdr a6:ae:e7:f2:87:ad PERMANENT
10.244.0.0 lladdr c2:66:6e:e9:71:31 PERMANENT
- 二次封包: 知道了目的MAC地址,封裝二層數據幀(容器源IP和目的IP)後,對於宿主機網絡來說這個幀並沒有什麼實際意義。接下來,Linux內核還要把這個數據幀進一步封裝成爲宿主機網絡的一個普通數據幀,好讓它載着內部數據幀,通過宿主機的eth0網卡進行傳輸。
- 封裝到UDP包發出去: 現在能直接發UDP包嘛?到目前爲止,我們只知道另一端的flannel.1設備的MAC地址,卻不知道對應的宿主機地址是什麼。
- vxlan header作爲一個默認的標識,在解包時從宿主機把數據傳到flannel.l網橋
flanneld進程也維護着一個叫做FDB的轉發數據庫,可以通過bridge fdb命令查看:
# bridge fdb show dev flannel.1
c2:66:6e:e9:71:31 dst 192.168.217.142 self permanent
a6:ae:e7:f2:87:ad dst 192.168.217.140 self permanent
42:c4:d2:75:b1:cf dst 192.168.217.140 self permanent
- flannnel模式缺點: 數據傳輸流程多,並採用隧道模式,有額外開銷,性能較低
3.4 host-gw模式
- 修改flannel網絡爲host-gw模式
# vim kube-flannel.yaml
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "host-gw"
}
}
# kubectl delete -f kube-flannel.yaml
# kubectl apply -f kube-flannel.yaml
host-gw模式數據傳輸流程
- host-gw模式進行宿主機路由,相關的網卡由宿主機路由表進行統一維護
# ip route
default via 192.168.217.2 dev ens33 proto static metric 100
10.244.0.0/24 via 192.168.217.142 dev ens33
10.244.1.0/24 dev cni0 proto kernel scope link src 10.244.1.1
10.244.2.0/24 via 192.168.217.140 dev ens33
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.217.0/24 dev ens33 proto kernel scope link src 192.168.217.141 metric 100
- host-gw模式缺點:二層交互技術,只能在同一網段使用,不能進行跨網段集羣
四 kubernetes網絡組件之Calico
4.1 BGP協議
-
BGP邊界網關協議: 一種自治系統路由協議,用來解決不同自治系統間的通信問題。
-
自治系統: 網絡單元(一個學校、一個企業、或者一個獨立的小型網絡環境),每個自治系統有唯一的ASN
4.2 Calico設計
calico是二 三層數據交換技術,通過BGP client進行主機間通信實現路由信息交換功能,Felix負責寫入路由表信息
Felix: 以DaemonSet方式部署,運行在每一個Node節點上,主要負責維護宿主機上路由規則以及ACL規則。
BGP Client(BIRD): 主要負責把 Felix 寫入 Kernel 的路由信息分發到集羣 Calico 網絡。
Etcd: 分佈式鍵值存儲,保存Calico的策略和網絡配置狀態。
calicoctl: 允許您從簡單的命令行界面實現高級策略和網絡。
Calico分爲IPIP模式、BGP模式,BGP模式純二層交換技術,不支持跨網段集羣。IPIP模式支持跨網段集羣。
4.3 Calico BGP模式部署
- 獲取calico.yaml
curl https://docs.projectcalico.org/v3.9/manifests/calico-etcd.yaml -o calico.yaml
- 修改calico.yaml
# vim calico.yaml
# 設置etcd證書的路徑,取默認值
etcd_ca: "/calico-secrets/etcd-ca"
etcd_cert: "/calico-secrets/etcd-cert"
etcd_key: "/calico-secrets/etcd-key"
# 獲取etcd ca、key、cert證書並進行編碼,覆蓋下面的null處
# cat /opt/etcd/ssl/server-key.pem | base64|tr -d '\n'
# cat /opt/etcd/ssl/server.pem | base64|tr -d '\n'
# cat /opt/etcd/ssl/ca.pem | base64|tr -d '\n'
etcd_ca: null
etcd_cert: null
etcd_key: null
- 指定calico.yaml中etcd的連接地址
# cat /opt/kubernetes/cfg/kube-apiserver.conf |grep etcd-server
--etcd-servers=https://192.168.217.140:2379,https://192.168.217.141:2379,https://192.168.217.142:2379 \
- 如果網絡不好可以先準備好calico鏡像,分發到集羣節點中,或者使用阿里雲加速器
# vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://b283u6ph.mirror.aliyuncs.com"]
}
- 關閉IPIP Always=IPIP,Never=BGP,修改子網網段 10.244.0.0/16
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
value: "Never"
# Set MTU for tunnel device used if ipip is enabled
- name: FELIX_IPINIPMTU
valueFrom:
configMapKeyRef:
name: calico-config
key: veth_mtu
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16"
- 刪除flannel網絡,以及在每個節點上刪除flannel網卡和cri網橋,防止和現有的calico網絡衝突
[root@k8s-master calico]# kubectl delete -f kube-flannel.yaml
[root@k8s-master calico]# ip route
default via 192.168.217.2 dev ens33 proto static metric 100
10.244.0.0/24 via 192.168.217.142 dev ens33
10.244.1.0/24 via 192.168.217.141 dev ens33
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.217.0/24 dev ens33 proto kernel scope link src 192.168.217.140 metric 100
[root@k8s-master calico]# ip route delete 10.244.0.0/24 via 192.168.217.142 dev ens33
[root@k8s-master calico]# ip route delete 10.244.1.0/24 via 192.168.217.141 dev ens33
[root@k8s-master calico]# ip route
default via 192.168.217.2 dev ens33 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.217.0/24 dev ens33 proto kernel scope link src 192.168.217.140 metric 100
- 安裝calico網絡
# kubectl apply -f calico.yaml
- 異常信息解決方式
# calico/node is not ready: BIRD is not ready: BGP not established
# 在calico.yaml文件加入下面的信息
# Auto-detect the BGP IP address.
- name: IP
value: "autodetect"
# 這是新加的
- name: IP_AUTODETECTION_METHOD
value: "interface=ens.*"
- BGP數據流向
- 缺點: BGP client需要兩兩連接,開啓大量tcp長連接,影響性能,尤其在服務器高達100臺以上的情況。calico node長連接狀態和長連接地址數可以通過calicoctl這個二進制命令查看
# calicoctl node status
Calico process is running.
IPv4 BGP status
+-----------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+-----------------+-------------------+-------+----------+-------------+
| 192.168.217.141 | node-to-node mesh | up | 15:51:43 | Established |
| 192.168.217.142 | node-to-node mesh | up | 15:51:59 | Established |
+-----------------+-------------------+-------+----------+-------------+
4.4 Calico RR模式
RR(route-reflector路由反射)模式,當服務器增加的時候,BGP模式的全互聯服務網格連接數成倍增加,RR模式通過指定多臺BGP節點來單獨進行路由表信息交換從而解決服務網格長連接過多的問題。
- 安裝calicoctl工具
下載工具:https://github.com/projectcalico/calicoctl/releases
# wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v3.9.1/calicoctl
# chmod +x /usr/local/bin/calicoctl
- 配置calicoctl,默認配置文件/etc/calico/calicoctl.cfg
# mkdir /etc/calico
# vim /etc/calico/calicoctl.cfg
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
datastoreType: "etcdv3"
etcdEndpoints: "https://192.168.217.140:2379,https://192.168.217.141:2379,https://192.168.217.142:2379"
etcdKeyFile: "/opt/etcd/ssl/server-key.pem"
etcdCertFile: "/opt/etcd/ssl/server.pem"
etcdCACertFile: "/opt/etcd/ssl/ca.pem"
# 這樣就可以使用calicoctl命令了
# calicoctl get nodes
NAME
k8s-master
k8s-node1
k8s-node2
- 關閉node to node BGP網格
# cat bgp.yaml
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
logSeverityScreen: Info
nodeToNodeMeshEnabled: false
asNumber: 63400
# calicoctl apply -f bgp.yaml
Successfully applied 1 'BGPConfiguration' resource(s)
- 增加一個節點的路由反射器,並設置集羣id
# calicoctl get node k8s-node2 -o yaml > node.yaml
apiVersion: projectcalico.org/v3
kind: Node
metadata:
annotations:
projectcalico.org/kube-labels: '{"beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/os":"linux","kubernetes.io/arch":"amd64","kubernetes.io/hostname":"k8s-node2","kubernetes.io/os":"linux"}'
creationTimestamp: "2020-05-06T15:34:18Z"
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
kubernetes.io/arch: amd64
kubernetes.io/hostname: k8s-node2
kubernetes.io/os: linux
name: k8s-node2
resourceVersion: "242806"
uid: fd7ddc2a-6ed1-4000-84e3-51eb17c1bc2b
spec:
bgp:
ipv4Address: 192.168.217.142/24
routeReflectorClusterID: 244.0.0.1 # 集羣ID
orchRefs:
- nodeName: k8s-node2
orchestrator: k8s
# calicoctl apply -f node.yaml
- 給這個節點,上面是k8s-node2打上RR的標籤,並讓該節點連接上這個配置,
# kubectl label node k8s-node2 route-reflector=true
# cat bgp1.yaml
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
name: peer-with-route-reflectors
spec:
nodeSelector: all() # 所有節點帶RR=true標籤的
peerSelector: route-reflector == 'true'
# calicoctl apply -f bgp1.yml
# calicoctl node status # 只與這個節點進行長連接
Calico process is running.
IPv4 BGP status
+-----------------+---------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+-----------------+---------------+-------+----------+-------------+
| 192.168.217.142 | node specific | up | 17:03:31 | Established |
+-----------------+---------------+-------+----------+-------------+
- 利用相同的方式可以把多個節點做成RR節點
4.5 IPIP模式介紹
calico BGP模式和host-gw設計理念一樣,同樣屬於二層交換模式,只能相同vlan的集羣中使用。如果要在不同的vlan中使用就需要開啓IPIP模式,IPIP模式是三層交換模式。