Spiderpool v0.6.0:公有云场景下统一的云原生 Underlay 网络方案

97 阅读5分钟

**
图片**

当前公有云厂商众多,如:阿里云、华为云、腾讯云、AWS 等,但当前开源社区的主流 CNI 插件难以通过 Underlay 的网络方式运行其上,只能使用每个公有云厂商的专有 CNI 插件,也没有统一的公有云 Underlay 解决方案。尤其是在混合云场景下,统一的 CNI 方案能够便于多云管理。 本文将介绍一种适用于任意的公有云环境中的云原生 Underlay 网络解决方案:Spiderpool (github.com/spidernet-i…

01

统一的云原生 Underlay 网络方案

Spiderpool 能基于 IPVlan Underlay CNI 运行在公有云环境上,它的实现原理如下:

  1. 公有云下使用 Underlay 网络,但公有云的每个云服务器的每张网卡只能分配有限的 IP 地址,当应用运行在某个云服务器上时,需要同步获取到 VPC 网络中分配给该云服务器不同网卡的合法 IP 地址,才能实现通信。根据上述分配 IP 的特点,Spiderpool 的 CR:SpiderIPPool 可以设置 nodeName,multusName 实现节点拓扑的功能,通过 IP 池与节点、IPvlan Multus 配置的亲和性,能最大化的利用与管理节点可用的 IP 地址,给应用分配到合法的 IP 地址,让应用在 VPC 网络内自由通信,包括 Pod 与 Pod 通信,Pod 与云服务器通信等。

  2. 公有云的 VPC 网络中,基于网络安全管控和数据包转发的原理,当网络数据报文中出现 VPC 网络未知的 MAC 和 IP 地址时,它无法得到正确的转发。例如,基于 Macvlan 和 OVS 原理的 Underlay CNI 插件,Pod 网卡中的 MAC 地址是新生成的,会导致 Pod 无法通信。针对该问题,Spiderpool 可搭配 IPVlan CNI 进行解决。IPVlan 基于三层网络,无需依赖二层广播,并且不会重新生成 Mac 地址,与父接口保持一致,因此通过 IPvlan 可以解决公有云中关于 MAC 地址合法性的问题。

02

实施要求

  1. 使用 IPVlan 做集群 CNI 时,系统内核版本必须大于 4.2。

  2. 已安装 Helm (helm.sh/docs/intro/…

03

步骤

公有云环境

准备一个公有云环境,例如:以阿里云为例,给虚拟机分配 2 个网卡,每张网卡均分配一些辅助私网 IP,如图:

图片

图源:系统界面截图

使用上述配置的虚拟机,搭建一套 Kubernetes 集群,集群的网络拓扑图如下:

图片

安装 Spiderpool

通过 Helm 安装 Spiderpool。

helm repo add spiderpool https://spidernet-io.github.io/spiderpool

helm repo update spiderpool

helm install spiderpool spiderpool/spiderpool --namespace kube-system --set ipam.enableStatefulSet=false --set multus.multusCNI.defaultCniCRName="ipvlan-eth0"

如果您使用的是中国大陆的云厂商服务器,可以指定参数 --set global.imageRegistryOverride=ghcr.m.daocloud.io,以帮助您更快的拉取镜像。

Spiderpool 可以为控制器: Statefulset 类型的应用副本固定 IP 地址。在公有云的 Underlay 网络场景中,云主机只能使用限定的 IP 地址,当 StatefulSet 类型的应用副本漂移到其他节点,但由于原固定的 IP 在其他节点是非法不可用的,漂移后的 Pod 在新节点上运行将出现网络不可用的问题。对此场景,将 ipam.enableStatefulSet 设置为 false,禁用该功能。

通过 multus.multusCNI.defaultCniCRName 指定集群的 Multus clusterNetwork,clusterNetwork 是 Multus 插件的一个特定字段,用于指定 Pod 的默认网络接口。

安装 CNI 配置

Spiderpool 为简化书写 JSON 格式的 Multus CNI 配置,它提供了 SpiderMultusConfig CR 来自动管理 Multus NetworkAttachmentDefinition CR。如下是创建 IPvlan SpiderMultusConfig 配置的示例:

IPVLAN_MASTER_INTERFACE0="eth0"
IPVLAN_MULTUS_NAME0="ipvlan-$IPVLAN_MASTER_INTERFACE0"
IPVLAN_MASTER_INTERFACE1="eth1"
IPVLAN_MULTUS_NAME1="ipvlan-$IPVLAN_MASTER_INTERFACE1"

cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: ${IPVLAN_MULTUS_NAME0}
  namespace: kube-system
spec:
  cniType: ipvlan
  coordinator:
    mode: underlay
    tunePodRoutes: true
    podCIDRType: cluster
  enableCoordinator: true
  ipvlan:
    master:
    - ${IPVLAN_MASTER_INTERFACE0}
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: ${IPVLAN_MULTUS_NAME1}
  namespace: kube-system
spec:
  cniType: ipvlan
  coordinator:
    mode: underlay
    tunePodRoutes: true
    podCIDRType: cluster
  enableCoordinator: true
  ipvlan:
    master:
    - ${IPVLAN_MASTER_INTERFACE1}
EOF

在本文示例中,使用如上配置,创建如下的两个 IPvlan SpiderMultusConfig,将基于它们自动生成的 Multus NetworkAttachmentDefinition CR,它们分别对应了宿主机的 eth0 与 eth1 网卡。

~# kubectl get spidermultusconfigs.spiderpool.spidernet.io -n kube-system
NAME          AGE
ipvlan-eth0   10m
ipvlan-eth1   10m

~# kubectl get network-attachment-definitions.k8s.cni.cncf.io -n kube-system
NAME          AGE
ipvlan-eth0   10m
ipvlan-eth1   10m

创建 IPPools

Spiderpool 的 CR:SpiderIPPool 提供了 nodeName、multusName 与 ips 字段:

  • nodeName: 当 nodeName 不为空时,Pod 在某个节点上启动,并尝试从 SpiderIPPool 分配 IP 地址, 若 Pod 所在节点符合该 nodeName ,则能从该 SpiderIPPool 中成功分配出 IP,若 Pod 所在节点不符合 nodeName,则无法从该 SpiderIPPool 中分配出 IP。当 nodeName 为空时,Spiderpool 对 Pod 不实施任何分配限制。
  • multusName: Spiderpool 通过该字段与 Multus CNI 深度结合以应对多网卡场景。当 multusName 不为空时,SpiderIPPool 会使用对应的 Multus CR 实例为 Pod 配置网络,若 multusName 对应的 Multus CR 不存在,那么 Spiderpool 将无法为 Pod 指定 Multus CR。当 multusName 为空时,Spiderpool 对 Pod 所使用的 Multus CR 不作限制。
  • spec.ips: 该字段的值必须设置。由于公有云限制了节点可使用的 IP 地址,故该值的范围必须在 nodeName 对应主机的辅助私网 IP 范围内,您可以从阿里云的弹性网卡界面获取。

依据如上所述,使用如下的 Yaml,为每个节点的每张网卡 ( eth0、eth1 ) 分别创建了一个 SpiderIPPool,它们将为不同节点上的 Pod 提供 IP 地址。

~# cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
  name: master-172
spec:
  default: true
  ips:
  - 172.31.199.185-172.31.199.189
  subnet: 172.31.192.0/20
  gateway: 172.31.207.253
  nodeName:
  - master
  multusName:
  - kube-system/ipvlan-eth0
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
  name: master-192
spec:
  default: true
  ips:
  - 192.168.0.156-192.168.0.160
  subnet: 192.168.0.0/24
  gateway: 192.168.0.253
  nodeName:
  - master
  multusName:
  - kube-system/ipvlan-eth1
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
  name: worker-172
spec:
  default: true
  ips:
  - 172.31.199.190-172.31.199.194
  subnet: 172.31.192.0/20
  gateway: 172.31.207.253
  nodeName:
  - worker
  multusName:
  - kube-system/ipvlan-eth0
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
  name: worker-192
spec:
  default: true
  ips:
  - 192.168.0.161-192.168.0.165
  subnet: 192.168.0.0/24
  gateway: 192.168.0.253
  nodeName:
  - worker
  multusName:
  - kube-system/ipvlan-eth1
EOF

创建应用

以下的示例 Yaml 中,会创建 2 组 daemonSet 应用和 1 个 service ,其中:

  • v1.multus-cni.io/default-network:用于指定应用所使用的子网,示例中的应用分别使用了不同的子网。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: test-app-1
  name: test-app-1
  namespace: default
spec:
  selector:
    matchLabels:
      app: test-app-1
  template:
    metadata:
      labels:
        app: test-app-1
      annotations:
        v1.multus-cni.io/default-network: kube-system/ipvlan-eth0
    spec:
      containers:
      - image: busybox
        command: ["sleep""3600"]
        imagePullPolicy: IfNotPresent
        name: test-app-1
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: test-app-2
  name: test-app-2
  namespace: default
spec:
  selector:
    matchLabels:
      app: test-app-2
  template:
    metadata:
      labels:
        app: test-app-2
      annotations:
        v1.multus-cni.io/default-network: kube-system/ipvlan-eth1
    spec:
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        name: test-app-2
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  name: test-svc
  labels:
    app: test-app-2
spec:
  type: ClusterIP
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: test-app-2
EOF

Spiderpool 自动为应用分配 IP 地址,应用的 IP 均在期望的 IP 池内:

~# kubectl get spiderippool
NAME         VERSION   SUBNET            ALLOCATED-IP-COUNT   TOTAL-IP-COUNT   DEFAULT
master-172   4         172.31.192.0/20   1                    5                true
master-192   4         192.168.0.0/24    1                    5                true
worker-172   4         172.31.192.0/20   1                    5                true
worker-192   4         192.168.0.0/24    1                    5                true

测试连通性

测试 Pod 与宿主机的通讯情况:

~# kubectl get nodes -owide
NAME     STATUS   ROLES           AGE     VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION              CONTAINER-RUNTIME
master   Ready    control-plane   2d12h   v1.27.3   172.31.199.183   <none>        CentOS Linux 7 (Core)   6.4.0-1.el7.elrepo.x86_64   containerd://1.7.1
worker   Ready    <none>          2d12h   v1.27.3   172.31.199.184   <none>        CentOS Linux 7 (Core)   6.4.0-1.el7.elrepo.x86_64   containerd://1.7.1

~# kubectl exec -ti test-app-1-b7765b8d8-422sb -- ping 172.31.199.183 -c 2
PING 172.31.199.183 (172.31.199.183): 56 data bytes
64 bytes from 172.31.199.183: seq=0 ttl=64 time=0.088 ms
64 bytes from 172.31.199.183: seq=1 ttl=64 time=0.054 ms

--- 172.31.199.183 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.054/0.071/0.088 ms

测试 Pod 与跨节点、跨子网 Pod 的通讯情况:

~# kubectl exec -ti test-app-1-b7765b8d8-422sb -- ping 172.31.199.193 -c 2
PING 172.31.199.193 (172.31.199.193): 56 data bytes
64 bytes from 172.31.199.193: seq=0 ttl=64 time=0.460 ms
64 bytes from 172.31.199.193: seq=1 ttl=64 time=0.210 ms

--- 172.31.199.193 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.210/0.335/0.460 ms

~# kubectl exec -ti test-app-1-b7765b8d8-422sb -- ping 192.168.0.161 -c 2
PING 192.168.0.161 (192.168.0.161): 56 data bytes
64 bytes from 192.168.0.161: seq=0 ttl=64 time=0.408 ms
64 bytes from 192.168.0.161: seq=1 ttl=64 time=0.194 ms

--- 192.168.0.161 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.194/0.301/0.408 ms

测试 Pod 与 ClusterIP 的通讯情况:

~# kubectl get svc test-svc
NAME       TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
test-svc   ClusterIP   10.233.23.194   <none>        80/TCP    26s

~# kubectl exec -ti test-app-2-7c56876fc6-7brhf -- curl 10.233.23.194 -I
HTTP/1.1 200 OK
Server: nginx/1.10.1
Date: Fri, 21 Jul 2023 06:45:56 GMT
Content-Type: text/html
Content-Length: 4086
Last-Modified: Fri, 21 Jul 2023 06:38:41 GMT
Connection: keep-alive
ETag: "64ba27f1-ff6"
Accept-Ranges: bytes

04

Spiderpool v0.6.0 新增功能

Spiderpool 在  v0.6.0  (github.com/spidernet-i…) 中新增如下功能:

  1. Spiderpool CR 中新增 nodeName、multusName 字段,用于支持节点拓扑,能按需配置网络。

  2. Spiderpool 提供了 SpiderMultusConfig CR ,它能简化书写 JSON 格式的 Multus CNI 配置,自动管理 Multus NetworkAttachmentDefinition CR。

  3. Spiderpool 提供了 coordinator 插件,解决 Underlay Pod 无法访问 ClusterIP 、调谐 Pod 的路由、检测 Pod 的 IP 是否冲突、Pod 的网关是否可达等。参考 coordinator 文档 (github.com/spidernet-i…)

  4. IPVlan 的深度支持,适用于任何公有云环境。 

  5. 支持多个默认 IP 池,简化使用成本。

  6. 增加 CNI 插件 ifacer,用于自动创建子接口,参考 ifacer 文档(github.com/spidernet-i…

  7. 支持通过 Pod 注解指定默认网卡。

  8. 支持自动池的回收开关支持,可以自定义自动池是否删除。

  9. 集群子网弹性 IP 的支持,可以很好地解决应用在滚动更新时,旧 Pod 未删除,新 Pod 没有可用 IP 的问题。

此外,Spiderpool Underlay 网络解决方案也完美支持网络出入口流量访问。您可以参考 Spiderpool 出入口流量示例 (github.com/spidernet-i…

05

总结

Spiderpool 能够运行在任意的公有云环境中,在多云、混合云的场景下提供了一种统一的 Underlay 网络解决方案。


 本文作者 

图片

杨涛

现任「DaoCloud 道客」云原生网络测试工程师