Kubernetes 網絡並沒有原生的方案,它從一開始就給我們送來了一個選擇題。到底選哪種網絡方案纔是最佳的方案呢?網絡問題一直讓社區用戶很困惑,以至於在早期,不同場景下的方案如雨後春筍般湧現出來。其中比較優秀的就是今天選擇給大家介紹的網絡組件 Calico。這裏我們要強調的是,Calico 方案並不是唯一方案,我們在社區仍然能看到很多優秀的方案比如 Cilium、OvS、Contiv、Flannel 等,至於選擇它來講解東西向流量的組件落地,實在是當前國內業界大部分的方案都是以 Cailico 實踐爲主,介紹它可以起到一個案例示範的作用。
容器網絡路由的原理
衆所周知容器原生網絡模型基於單機的 veth 虛擬網橋實現,無法跨主機互聯互通。如果想讓容器跨主機互聯互通,需要支持以下 3 點:
-
網絡控制面需要保證容器 IP 的唯一性 -
兩個容器需要放在一個數據平面 -
需要工具來自動解決容器網絡地址轉換
這裏我們通過一個原生網絡路由的例子來幫助大家理解容器網絡互聯互通的基本原理:
圖:Docker 19.03.12 版本直接路由模式圖例
分別對主機 1 和主機 2 上的 docker0 進行配置,重啓 docker 服務生效
編輯主機 1 上的 /etc/docker/daemon.json
文件,添加內容:"bip" : "ip/netmask"
。
{
"bip": "172.17.1.252/24"
}
編輯主機 2 上的 /etc/docker/daemon.json
文件,添加內容:"bip" : "ip/netmask"
。
{
"bip": "172.17.2.252/24"
}
主機 1 和主機 2 上均執行如下命令,重啓 Docker 服務以使修改後的 docker0 網段生效。
systemctl restart docker
添加路由規則
主機 1 上添加路由規則如下:
route add -net 172.17.2.0/24 gw 172.26.15.215
主機 2 上添加路由規則如下:
route add -net 172.17.1.0/24 gw 172.26.14.120
理論上配置完路由後應該從主機 1 可以連接到主機 2 的 docker0,實際場景下因爲交換機會檢查 docker0 的 mac 地址,並把這個非法的地址下的數據包直接 DROP 掉,讓跨主機的容器無法想通,但這個並不妨礙我們理解原理。Calico 網絡路由原理和以上示範靜態路由原理是一致的,那麼它是如何實現連通的呢?
安裝 Calico 後,主機上檢查如下:
主機 1 上的
vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UNKNOWN group default
link/ether 66:18:b6:89:bd:6f brd ff:ff:ff:ff:ff:ff
inet 192.168.206.0/32 brd 192.168.206.0 scope global vxlan.calico
主機 2 上的
vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1410 qdisc noqueue state UNKNOWN group default
link/ether 66:85:17:26:23:b1 brd ff:ff:ff:ff:ff:ff
inet 192.168.49.0/32 brd 192.168.49.0 scope global vxlan.calico
對比可以知道,和上面範例中分配 IP 段一樣,Calico 也是爲每臺主機分配固定的 IP 段保證容器網絡 IP 不衝突。我們再來看下路由規則:
root@ip-172-26-8-126:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.26.0.1 0.0.0.0 UG 100 0 0 eth0
172.26.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
172.26.0.1 0.0.0.0 255.255.255.255 UH 100 0 0 eth0
192.168.49.1 0.0.0.0 255.255.255.255 UH 0 0 0 cali3f1b566e6d6
192.168.49.2 0.0.0.0 255.255.255.255 UH 0 0 0 cali408c6db5188
192.168.206.0 172.26.5.8 255.255.255.192 UG 0 0 0 eth0
root@ip-172-26-5-8:~# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.26.0.1 0.0.0.0 UG 100 0 0 eth0
172.26.0.0 0.0.0.0 255.255.240.0 U 0 0 0 eth0
172.26.0.1 0.0.0.0 255.255.255.255 UH 100 0 0 eth0
192.168.49.0 172.26.8.126 255.255.255.192 UG 0 0 0 eth0
192.168.206.1 0.0.0.0 255.255.255.255 UH 0 0 0 cali517a7f7f853
192.168.206.3 0.0.0.0 255.255.255.255 UH 0 0 0 cali8d8ae1f64d9
192.168.206.4 0.0.0.0 255.255.255.255 UH 0 0 0 cali99a5d6c4e2d
192.168.206.5 0.0.0.0 255.255.255.255 UH 0 0 0 cali3b6d130f2eb
192.168.206.6 0.0.0.0 255.255.255.255 UH 0 0 0 calid8aeffc724c
兩臺主機路由表上都做了對方 IP 的路由信息。
我們通過部署容器來測試網絡連通性:
root@ip-172-26-5-8:~# cat pingtest-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pingtest-deployment
labels:
app: pingtest
spec:
replicas: 3
selector:
matchLabels:
app: pingtest
template:
metadata:
labels:
app: pingtest
spec:
containers:
- name: pingtest
image: busybox
args: ["sleep", "infinity"]
root@ip-172-26-5-8:~# kubectl apply -f pingtest-deployment.yaml
root@ip-172-26-5-8:~# kubectl get pod -l app=pingtest -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pingtest-deployment-6dcb8d6c77-8ntqf 1/1 Running 0 10m 192.168.49.4 ip-172-26-8-126 <none> <none>
pingtest-deployment-6dcb8d6c77-l5hq2 1/1 Running 0 10m 192.168.49.5 ip-172-26-8-126 <none> <none>
pingtest-deployment-6dcb8d6c77-6fcdn 1/1 Running 0 6m48s 192.168.206.7 ip-172-26-5-8 <none> <none>
因爲最新的 Calico 默認配置的模式是 vxlanMode 模式,你沒有修改路由器的權限,所以需要修改 ipipMode 爲 Always。
root@ip-172-26-12-198:~# cat pool.json
{
"kind": "IPPoolList",
"apiVersion": "projectcalico.org/v3",
"metadata": {
"resourceVersion": "2306"
},
"items": [
{
"kind": "IPPool",
"apiVersion": "projectcalico.org/v3",
"metadata": {
"name": "default-ipv4-ippool",
"uid": "0ba1e107-0582-4b7b-b99f-f7105525e987",
"resourceVersion": "763",
"creationTimestamp": "2020-08-10T16:59:28Z"
},
"spec": {
"cidr": "192.168.0.0/16",
"vxlanMode": "Never",
"ipipMode": "Always",
"natOutgoing": true,
"blockSize": 26,
"nodeSelector": "all()"
}
}
]
}
修改後在命令行下查看路由規則的辦法,確認虛擬網絡走了 tunnel 網卡口:
root@ip-172-26-12-198:~# ip route
default via 172.26.0.1 dev eth0 proto dhcp src 172.26.12.198 metric 100
172.26.0.0/20 dev eth0 proto kernel scope link src 172.26.12.198
172.26.0.1 dev eth0 proto dhcp scope link src 172.26.12.198 metric 100
192.168.31.0 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.31.0/26 via 172.26.5.10 dev eth0 proto 80 onlink
192.168.31.1 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.31.3 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.31.4 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.31.5 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.31.7 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.31.64/26 via 172.26.5.10 dev tunl0 proto bird onlink
192.168.41.137 dev calie486eacd845 scope link
192.168.41.138 dev calif383cce9723 scope link
192.168.41.139 dev calia4f3d6b96e0 scope link
192.168.41.140 dev cali391d55f6fc3 scope link
192.168.41.141 dev cali981dc37e1ca scope link
192.168.41.142 dev calic0a72d40721 scope link
192.168.41.143 dev calicfb8f80c8c5 scope link
blackhole 192.168.41.192/26 proto bird
192.168.41.193 dev calia6f4721616e scope link
通過 kubectl exec 可以進入 Pod 容器進行連通性測試:
root@ip-172-26-12-198:~# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pingtest-deployment-6dcb8d6c77-95vrw 1/1 Running 0 23m 192.168.41.139 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-p4cqx 1/1 Running 0 23m 192.168.41.140 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-kfmhp 1/1 Running 0 23m 192.168.41.137 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-w582x 1/1 Running 0 23m 192.168.41.141 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-ts9fh 1/1 Running 0 23m 192.168.41.138 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-ppt2n 1/1 Running 0 22m 192.168.41.142 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-qw46c 1/1 Running 0 22m 192.168.41.143 ip-172-26-12-198 <none> <none>
pingtest-deployment-6dcb8d6c77-972zw 1/1 Running 0 22m 192.168.31.7 ip-172-26-5-10 <none> <none>
root@ip-172-26-12-198:~# kubectl exec -it pingtest-deployment-6dcb8d6c77-972zw -- sh
/ # ping 192.168.41.138
PING 192.168.41.138 (192.168.41.138): 56 data bytes
64 bytes from 192.168.41.138: seq=0 ttl=62 time=0.449 ms
64 bytes from 192.168.41.138: seq=1 ttl=62 time=0.501 ms
Calico 網絡的性能
sh-4.4# iperf3 -s
-----------------------------------------------------------
Server listening on 5201
-----------------------------------------------------------
Accepted connection from 172.26.5.10, port 53246
[ 5] local 192.168.31.68 port 5201 connected to 172.26.5.10 port 53248
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.00 sec 2.42 GBytes 20.8 Gbits/sec
[ 5] 1.00-2.00 sec 3.07 GBytes 26.4 Gbits/sec
[ 5] 2.00-3.00 sec 2.83 GBytes 24.3 Gbits/sec
[ 5] 3.00-4.00 sec 3.05 GBytes 26.2 Gbits/sec
[ 5] 4.00-5.00 sec 3.12 GBytes 26.8 Gbits/sec
[ 5] 5.00-6.00 sec 2.87 GBytes 24.7 Gbits/sec
[ 5] 6.00-7.00 sec 3.02 GBytes 26.0 Gbits/sec
[ 5] 7.00-8.00 sec 3.04 GBytes 26.1 Gbits/sec
[ 5] 8.00-9.00 sec 3.08 GBytes 26.5 Gbits/sec
[ 5] 9.00-10.00 sec 2.93 GBytes 25.2 Gbits/sec
[ 5] 10.00-10.04 sec 104 MBytes 24.6 Gbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate
[ 5] 0.00-10.04 sec 29.5 GBytes 25.3 Gbits/sec receiver
在規模配置在 10 臺以下的情況下,容器傳輸效率依賴主機網卡性能,結果說明性能不差。
總結
Calico 作爲業內常用的方案,它的好處就是靈活配置。因爲它有 BGP 協議支持,可以跨數據中心的互聯互通。從實踐角度來看,它具備複雜場景下靈活配置的特點,所以也在業界主流比較推薦。當然這裏我們的目的並不是推薦 Calico,我們仍然需要依據你當前集羣的具體需要來規劃,讓容器網絡能更方便的使用。
參考文章:
https://docs.docker.com/network/bridge/
https://www.tecmint.com/test-network-throughput-in-linux/
本文分享自微信公衆號 - 雲原生技術愛好者社區(programmer_java)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。