網絡組件 Calico 的落地實踐

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源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章