SpiderPool - 云原生容器网络 IPAM 插件

177 阅读15分钟

SpiderPool 来源于容器网络落地实践的经验积累,是「Daocloud 道客」开源的原生容器网络 IPAM 插件(github:github.com/spidernet-i… Underlay CNI 实现容器云平台精细化的管理和分配 IP 。

01

SpriderPool 诞生背景

传统应用云原生化

首先,在一些传统行业,如制造、教育、能源等企业,通常会直接将传统应用上云。这些应用未经微服务改造,仍需要通过某个固定 IP 进行访问,并且需要对此类 IP 进行强管控,比如严格的防火墙管控等。因此需要更灵活及更高效 的 IP 管理能力,满足此类场景需求。

其次,在传统应用微服务化过程中,用户会逐步将一部分应用容器化,部分容器化应用需要提供对外访问 IP,实现集群内外互联互通,因此这类应用同样也需要使用固定且可对外访问的 IP。

除此之外,基于对外访问 IP 的强管控需求,在客户的落地实践中,通过 Underlay CNI 分配的 IP 都需要对接传统物理子网规划,直接对外提供服务,并且考虑到容器网络安全需要在防火墙配置并放行使用的 IP ,整体的 IP 管理流程和规范冗长且复杂。并且 Underlay CNI 中的 IP 资源相对紧缺, 因此需要对 Underlay IP 进行强分配和管控,当 IP 地址释放及分配失败时,需要及时回收,防止资源浪费。

由此可见,围绕着云原生容器网络面临如下挑战:

固定并且可对外的 IP 需求旺盛,灵活高效的 IPAM 机制强需求。

02

Underlay CNI vs Overlay CNI 特性

在介绍 SpiderPool IPAM 插件之前,我们先来对比下 Underlay CNI 和 Overlay CNI 的差异性特点。

Underlay CNI IP 管理特性

  1. Pod 对接物理网络规划,无需经过 NAT 转换,直接同集群外部通信;

  2. 使用的 IP 需要进行防火墙开放,需要强管控,并且需要 Pod IP 固定;

  3. Underlay CNI 的 IP 资源有限,因此集群内外部 IP 冲突问题凸显,当 IP 无法及时回收会导致新的 Pod 启动失败。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

Overlay CNI IP 管理特性

  1. Pod Subnet 独立规划,Pod 和集群外部通信,需要经过 NAT 处理,对外暴露的仅为节点 IP, Pod IP 无需对外暴露;

  2. Overlay CNI IP 地址数量充沛,每个 Node 独立规划 CIDR Block;

  3. 防火墙不可见 Pod IP,因此在对外提供访问时,无安全风险,无需开放防火墙进行 IP 资源强管控,正由于此背景,Pod IP 无固定需求;

  4. Overlay IP 地址的分配可忽略 Underlay 网络中的冲突,泄露 IP 的回收问题,影响较小。

通过对比可见,Overlay CNI 对于 IP 管理需求较弱,并且资源很富足,当出现集群内出现 IP 冲突时,不至于造成严重后果。

而在 Underlay CNI 网络方案中, 缺失 IPAM 或者 IP 管理能力较弱的 CNI 方案中(如 SRI-OV ,Macvlan,IPVLAN ,OVS-CNI )在面对上述 IP 强管理,以及 IP 冲突管理等复杂场景时则无能为力。

SpiderPool 正是致力于满足上述的场景需求开源的 CNI IPAM 项目,将 SpiderPool 同 Underlay CNI 结合,打造云原生可上生产的云原生网络方案,「DaoCloud 道客」最新推出的 DCE 5.0 已经将 SpiderPool 产品化,作为 Underlay CNI (Macvlan,SRI-OV 等)的 IPAM 方案。

03

SpriderPool 功能

在上述背景中,SpiderPool 主要基于如下问题进行设计:

  1. 结合 Underlay CNI 提供对外访问的 IP,满足应用负载提供对外访问能力;

  2. 提供 IP 的强管控能力,包括子网的管理 ,IP 的管理,配合 物理层防火墙安全管控;

  3. IP 固定能力,当业务应用重启,仍保留分配给业务应用的 IP;

  4. 防 IP 冲突(IP 的分配和 IP 的回收机制加强)。

SpiderPool 功能列表

特性功能

IP Pool 的节点亲和性

场景

不同的 Node 上,可用的 Subnet 也许并不相同,例如:

  1. 同一数据中心内,集群接入的 Node 分属不同 Subnet;

  2. 单个集群中,Node 跨越了不同的数据中心。

在以上场景中,当同一个应用的不同副本被调度到了不同的 Node上,需要分配不同 Subnet Underlay IP 地址。

方案

IP Pool CR 中,具备了 nodeAffinity 字段,用于设置 Node Label Selector,从而实现 IP Pool。

和 Node 之间亲和性,当 Pod 被调度到某个 Node上后,IPAM 插件能够从亲和的 IP Pool 中进行 IP 地址分配。

创建 IP Pool 示例:


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderIPPool
metadata:
  name: master-ipv4-ippool
spec:
  ipVersion: 4
  subnet: 172.18.41.0/24
  ips:
    - 172.18.41.40-172.18.41.42
  nodeAffinity:  #创建 IP Pool 时,添加节点亲和性
    matchExpressions:
      - {key: node-role.kubernetes.io/beijing, operator: Exists}

IP Pool 的应用亲和性

场景

在 强管制的网络场景中,所有 Pod 能够在一个固定的 IP 地址范围内轮滚分配 IP 地址,以配合放行防火墙放行策略。

方案

因为 SpiderPool IP Pool 的 IP 集合可大可小,结合设置 IP Pool 的 podAffinity,可实现同一组或者多组应用的亲和绑定,既保证了 IP 管理方式的统一,又解耦 “应用扩容” 和 “IP地址扩容”,也固定了应用的 IP 使用范围。

示例


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderIPPool
metadata:
  name: master-ipv4-ippool
spec:
  ipVersion: 4
  subnet: 172.18.41.0/24
  ips:
    - 172.18.41.40-172.18.41.42
  podAffinity: # 创建 IP Pool 时增加 Pod 亲和性
    matchExpressions:
      - {key: app-dao2048, operator: Exists}

IP Pool 的命名空间亲和性

场景

一个 IP Pool 能实现同一个或者多个 Namespace下的应用实现亲和,而拒绝不相干 NS 的应用。

方案

通过设置 IP Pool 的 namespaceAffinity,实现同一个或者多个租户的亲和性,从而使得满足条件的应用才能够从 IP Pool 中分配到 IP 地址。

示例


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderIPPool
metadata:
  name: master-ipv4-ippool
spec:
  ipVersion: 4
  subnet: 172.18.41.0/24
  ips:
    - 172.18.41.40-172.18.41.42
  namespaceAffinity:  # 创建 SpiderPool 时增加 Namespace 亲和性
    matchExpressions:
      - {key: ns-spider, operator: Exists}

多 IP Pool 备用

场景

当 IP Pool 中的 IP 地址分配完毕,并且子网内的 IP 都已经用完,相关的应用在扩容时会导致失败,因此可设置多个备用 IP 池。

方案

方案一:给现有的 IP Pool 扩容更多的 IP 地址资源。

方案二:给应用绑定多个 IP Pool,当前置的 IP Pool 耗尽 IP 地址,IPAM 插件会尝试从后置的 IP Pool 中分配 IP 地址。

示例


annotations:
  ipam.spidernet.io/ippool: |-
    {
      "interface": "eth0",
      "ipv4": ["default-ipv4-ippool", "backup-ipv4-ippool"]  #创建 工作负载时,指定多个 IP Pool
    }

固定 IP Pool 的自动分配

场景

基础设施管理员只希望提供可用的 IP 地址,不希望操心创建 “固定 IP 范围” 的 IP Pool;而应用管理员并不关心 IP 地址的值,只希望能够获取到指定数量的 IP 地址。因此,职责上的划分导致双方只希望做最简单的集群操作。因此,“固定 IP 范围” IP Pool 的创建工作,成为了双方都不希望承担的工作量。

另外当一个 工作负载将所有固定 IP 用完之后,进行滚动发布时,会造成新 Pod 由于无剩余 IP,导致无法启动。

方案

当前 Spiderpool 能够自动为应用动态动态创建 IP Pool、绑定 IP Pool、回收 IP Pool,既解决了两个部门人员的职责解耦,同时使得 “固定IP范围”应用的操作更加简化,极大降低了 IP 地址的管理成本。

另外针对由于固定 IP 用完导致滚动发布失败的场景,Spiderpool 基于固定 IP 功能之上提供了 弹性 IP 数量,创建 工作负载时(限制于 Deployment、ReplicaSet、DaemonSet、StatefulSet、Job, CronJob),其PodTemplateSpec.Annotation 中指定一定数量的弹性 IP 数量,保障应用正常发布。

示例


annotations:
  ipam.spidernet.io/subnet: '{"ipv4": ["subnet-demo-v4"], "ipv6": ["subnet-demo-v6"]}'
  ipam.spidernet.io/ippool-ip-number: "+2" # 当为 “+2”时为弹性 IP ,当 输入为“2”时为指定固定 IP 数量
  ipam.spidernet.io/ippool-reclaim: "true"

Statefulset 固定 IP

场景

Deployment 和 Statefulset 控制器,对于 IP 地址固定的需求是不一样的:

  1. 对于 Statefulset,Pod 副本重启前后,Pod 名需要 保持不变,但是 Pod UUID 是变化的,其是有状态的,应用管理员希望该 Pod 重启前后,分配到相同的 IP

  2. 对于 Deployment ,Pod 副本重启前后,其 Pod 名字和 Pod UUID 都发生了变化,所以是无状态的,因此并不要新老交替的 Pod 使用相同的 IP,我们可能只希望 Deployment 中所有副本所使用的IP 是 固定在某个 IP范围内即可。

方案

Spiderpool 会保证 Statefulset Pod 在重启、重建场景下,持续获取到相同的 IP 地址。

注:在 Statefulset 经由 “缩容” 到 “扩容” 的变化过程中,并不保证新扩容 Pod 能够获取到之前缩容 Pod 的 IP 地址。

创建 IP Pool 示例:


apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: demo-sts
  namespace: default
spec:
  serviceName: "demo-sts-svc"
  replicas: 1
  selector:
    matchLabels:
      app: demo-sts
  template:
    metadata:
      labels:
        app: demo-sts
    spec:
      containers:
        - image: busybox
          imagePullPolicy: IfNotPresent
          name: demo-sts
          command: ["/bin/sh", "-c", "trap : TERM INT; sleep infinity & wait"]

Pod 多网卡

场景

通过 Multus 项目,可给 Pod 插入多个 CNI 的网卡,而不同网卡需要各自指定使用不同的 IP Pool,从而分配不同 Subnet下的 IP 地址,且可灵活指定接口的默认路由。

方案

可结合 Multus 的 NetworkAttachmentDefinition 配置,多套 CNI 配置分别配置不同的 IP Pool。


kind: NetworkAttachmentDefinition
spec:
  config: |
    '{ "ipam": { "default_ipv4_ippool": ["ippool1"], "type": "spiderpool" 

可结合 Pod Annotaiton,可为每张网卡分配不同 IP Pool 中的 IP 地址。


ipam.spidernet.io/ippools: |-
  [{
      "interface": "eth0", "ipv4": ["v4-ippool1"],  "ipv6": ["v6-ippool1"], "cleangateway": true
   },{
      "interface": "eth1", "ipv4": ["v4-ippool2"], "ipv6": ["v6-ippool2"], "cleangateway": false
  }]

IP 泄漏规避

挑战

在落地实践中发现,如果直接使用 Macvlan 等 CNI ,在高并发的某些场景下,极容易出现 Docker 为容器创建的网络命名空间在容器死亡后没有被内核正确回收的现象,并且导致 IP 数据混乱、IP 重分,错分、冲突等异常现象。而 Macvlan 等 CNI 本身 IPAM 回收能力又比较弱,从而导致业务 Pod IP 冲突,造成业务应用不可访问。另外发现网络命名空间泄漏问题难定位、难复现,出现原因多样化,无法从根源解决。

在 Pod 故障、重启、重建等场景下,旧 Pod 副本 IP 地址是否及时回收到 IP Pool,会影响新 Pod 副本启动的成败。在 IPAM 组件看来, IP 资源被一些 “僵尸 Pod” 占用着,从而导致可用 IP 减少。

在 Overlay IPAM 场景下,因为 CIDR 范围很大,所以该问题并不突出,而在 Underlay 场景下,IP 资源有限,且部分应用有固定 IP 地址范围的需求,该问题就会影响应用的健康运行。

方案

SpiderPool 正是致力于满足上述的场景需求及规避上述 IP 冲突问题开源的 CNI IPAM 项目,将 SpiderPool 同 Underlay CNI 结合,基于事件和周期性的双重回收机制,使得被 “浪费” 的 IP 资源在第一时间在 IP Pool 中得到释放。

预留 IP

场景

当明确某个 IP 地址已经被集群外部使用时,为了避免 IP 冲突,从存量的 IP Pool 实例找到该 IP 地址并剔除,也许是一件耗时耗力的工作。并且,网络管理员希望存量或者未来的所有 IP Pool 资源中,都不会分配出该 IP 地址。

方案

可在 ReservedIP CR 中设置希望集群不使用的 IP 地址,因此,即使是在 IP Pool 对象中包含了该 IP 地址,IPAM 插件也不会把这些 IP 地址分配给 Pod 使用 ReservedIP 中的 IP 地址可以是:

  1. 明确该 IP 地址被集群外部主机使用;

  2. 明确该 IP 地址不能被使用于网络通信,例如子网 IP、广播 IP 等。

示例


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderReservedIP
metadata:
  name: test-ipv4-reservedip
spec:
  ipVersion: 4
  ips:   # 预留 IP 段
    - 172.18.42.41-172.18.42.49

自定义路由

应用存在多种方式,可定制路由。优先级由低到高(应用路由-->IP Pool )。在 IP Pool CR 中,可指定:

  1. 默认路由和子网路由

kind: spiderippool
spec:
    gateway: 172.16.0.1
    routes: [ {“dst”: “192.168.0.0/16”, “gw”: “172.16.0.2”} ]
  1. 应用级别的路由:

#在 Pod Annotaiton 中
ipam.spidernet.io/routes : [{“dst”: “192.168.0.0/16”, “gw”: “172.16.0.2”}]

04

SpriderPool CR 设计

SpiderPool 的 通过 CRD (CustomResourceDefinitions) 方式定义子网 和 IP Pool 等资源,通过 Spider Subnet 和 Spider IP Pool CRD 两层存储设计,在 IP Pool CR 中定义了 IP 地址集合,一个 Subnet 中不同 IP 地址,分别存储在不同 的 IP Pool 实例中,一个 IP Pool 集合可根据需要进行扩充或者缩小。另外 SpiderPool 会校验 IP Pool 实例中的 地址,并保障 IP 地址不重叠。

IP Pool 的 CR 设计充分根据了 IP 地址的稀缺性,实现应用、命名空间 不同 IP Pool 的绑定从而实现 IP 资源隔离,同时也满足 IP 资源共享的场景。

  1. SpiderSubnet 对象:一个 Subnet 对应了一个 IPv4/IPv6 子网,其中存储了该子网下所有的可用 IP 地址。

  2. SpiderIPPool 对象:一个 Spider Subnet 对象下可以存在多个 SpiderIPPool 实例,SpiderIPPool 对象存储了所属 SpiderSubnet 的部分可用 IP 地址集合。Pod 从 Spider IP Pool 对象中分配 IP 地址来使用。

相关 CRD 资源

  1. spidersubnets.spiderpool.spidernet.io 用于存放和定义 IP 子网实例,存储了子网下的所有可用 IP 集合, IP Pool 中的 IP 从 IP 子网中获取。

校验合理性:Webhook 机制确保管理员创建和修改 SpiderSubnet 对象时,不会与存量 Spider Subnet 对象的子网重叠,确保其中的所有字段的值是符合规范的。

实时更新管理的 SubnetIPPool 数据:subnetIPPool Informer 会实时更新 数据到 被管理的 SpiderSubnet 对象中。

处理对象删除:在 SpiderSubnet 对象被删除时,Finalizer 确保管理的所有 SpiderIPPool 中的的 IP 都被 业务 Pod 释放了,才会真正删除 SpiderSubnet 对象,避免了 IP 泄露和冲突。

状态展示:Status 字段的用量信息展示。


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderSubnet
metadata:
  finalizers:
  - spiderpool.spidernet.io
  name: default-v4-subnet
spec:
  ipVersion: 4
  subnet: 172.19.0.0/16
  ips:
  - 172.19.40.2-172.19.40.254
  excludeIPs:xxxx
  gateway: xxxx
  routes: xxxx
  vlan: 0
status:
  totalIPCount: 253
  allocatedIPCount: 253
  controlledIPPools:
    default-v4-ippool:
      ips:
      - 172.19.40.2-172.19.40.254
  1. spiderippools.spiderpool.spidernet.io 存储了子网下的部分可用 IP 集合。CR 实例中定义了每个 IP Pool 中可使用的 IP。

校验合理性:在创建和修改 SpiderIPPool 对象时,Webhook 机制确保其中的所有字段的值是符合规范的,并且不允许 SpiderIPPool 对象之间是存在 IP 的重叠。

保障子网归属:确保 SpiderIPPool 的 spec.subnet 字段必须对应一个存量的 SpiderSubnet 对象,确保 spec.ips 中的可用 IP 地址务必是所属 SpderSubnet 对象中的闲置 IP 地址。

处理对象删除:Finalizer 拦截 SpiderIPPool 对象的删除,只有SpiderIPPool 对象中的所有 IP 被相关的 业务 Pod 释放后,才会真正删除 SpiderIPPool 实例,以避免其它 SpiderIPPool 对象的并发创建,引入了 IP 重叠。当 SpiderIPPool 对象处于 Deleting 状态时,IPAM 就会停止为新 POD 从该 Spiderippool 对象中分配 IP 地址,但允许存量 Pod 释放其中的 IP。

状态展示:实时更新 Status 字段中的状态信息。


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderIPPool
metadata:
  name: default-v4-ippool
  finalizers:
  - spiderpool.spidernet.io
spec:
  disable: false
  ipVersion: 4
  subnet: 172.19.0.0/16
  ips:
  - 172.19.40.2-172.19.40.254  excludeIPs: 172.19.40.254
  gateway: 172.19.40.1
  namespaceAffinity: xxxxx
  nodeAffinity: xxxxx
  podAffinity: xxxxx
  routes: xxxx
  vlan: 0
status:
  allocatedIPCount: 4
  allocatedIPs:
    172.19.40.21:
      containerID: ****
      pod: coredns-6d4b75cb6d-627xr
      namespace: kube-system
      interface: eth0
      node: spider-control-plane
      ownerControllerName: coredns-6d4b75cb6d
      ownerControllerType: ReplicaSet
  totalIPCount: 253
  1. spiderendpoints.spiderpool.spidernet.io 记录某个 Pod 当前以及历史分配过的 IP 信息。

status.current 字段存储了本 Pod 当前最新的 IP 分配情况,该字段可存储了所有网卡的 IP 分配,以支持 Pod 多网卡场景。

status.history 字段存储了所有历史分配 IP 情况,该信息可用于 Spiderippool 对象的 IP GC 回收。

ownerReferences 的设计,确保了该对象的回收机制。

finalizer 设计,确保该对象存储的信息不会意外丢失。


apiVersion: spiderpool.spidernet.io/v1
kind: SpiderEndpoint
metadata:
  finalizers: [“spiderpool.spidernet.io”]
  name: test-pod-788d579c4-6r2w7
  namespace: default
  ownerReferences:
  - apiVersion: v1
    kind: Pod
    name: test-pod-788d579c4-6r2w7
    uid: ca1263c8-c4ed-402c-b25a-ad3f822605f9
status:
  ownerControllerName: test-pod-788d579c4
  ownerControllerType: ReplicaSet
  current:
    containerID: ******
    creationTime: "2022-10-20T09:10:45Z"
    node: spider-worker
    ips:
    - interface: eth0
      ipv4: 172.19.40.47/16
      ipv4Pool: default-v4-ippool
      ipv6: fc00:f853:ccd:e793:f::3c/64
      ipv6Pool: default-v6-ippool
      vlan: 0
    - interface: net1
      ipv4: 172.19.40.167/16
      ipv4Pool: default-v4-ippool
      ipv6: fc00:f853:ccd:e793:f::c5/64
      ipv6Pool: default-v6-ippool
      vlan: 0
  history: *******
  1. spiderreservedips.spiderpool.spidernet.io用于存放需要 预留的 IP ,一经预留, 则 IP 无法分配给 Pod 使用。

04

SpriderPool 未来展望

SpiderPool 核心功能基本已就绪,已基于 Macvlan /SRI-OV 等 Underlay CNI 组合测试和落地,并结合 Multus 、Overlay CNI (Calico,Cilium) 实现多网卡场景下的 IP 分配和管理。在下一阶段 ,SpiderPool 将不断丰富各种使用场景,完善日志,逐步进入功能稳定期。

欢迎广大云原生技术爱好者下载使用、参与社区讨论与贡献。

SpiderPool官方社区:

github.com/spidernet-i…