From 72efb3a4bcae17a88cbdde60a43d25fc8348a910 Mon Sep 17 00:00:00 2001 From: ty-dc Date: Mon, 17 Jul 2023 16:45:59 +0800 Subject: [PATCH] fix: update some outdated documentation Signed-off-by: ty-dc Signed-off-by: tao.yang --- README-zh_CN.md | 2 +- docs/README-zh_CN.md | 2 +- ...formance-zh_CH.md => performance-zh_CN.md} | 36 +-- docs/concepts/performance.md | 36 +-- .../ip-allocation-across-networks-1.png | Bin 0 -> 43480 bytes .../ip-allocation-across-networks-2.png | Bin 0 -> 107475 bytes docs/usage/_feature_example_zh.md | 2 +- docs/usage/_install_example_zh.md | 2 +- docs/usage/gc-zh_CN.md | 51 +--- docs/usage/gc.md | 44 +--- docs/usage/install/install-zh_CN.md | 78 +++++- docs/usage/install/install.md | 16 +- .../install/overlay/get-started-calico.md | 4 +- .../install/overlay/get-started-cilium.md | 1 - .../underlay/get-started-calico-zh_CN.md | 67 +++-- .../install/underlay/get-started-calico.md | 57 ++--- .../underlay/get-started-kind-zh_CN.md | 78 +++--- .../install/underlay/get-started-kind.md | 76 +++--- .../underlay/get-started-macvlan-zh_CN.md | 166 +++++------- .../install/underlay/get-started-macvlan.md | 167 +++++------- .../install/underlay/get-started-ovs-zh_CN.md | 134 +++++----- .../usage/install/underlay/get-started-ovs.md | 131 +++++----- .../underlay/get-started-weave-zh_CN.md | 43 ++-- .../install/underlay/get-started-weave.md | 43 ++-- docs/usage/ippool-affinity-namespace.md | 8 +- docs/usage/ippool-affinity-node.md | 6 +- docs/usage/ippool-affinity-pod.md | 22 +- docs/usage/ippool-multi.md | 2 +- docs/usage/ippool-namespace.md | 2 +- docs/usage/ipv6.md | 2 +- docs/usage/multi-interfaces-annotation.md | 2 +- docs/usage/network-topology-zh_CN.md | 217 ++++++++++++++++ docs/usage/network-topology.md | 237 ++++++++++++++---- docs/usage/reserved-ip.md | 2 +- docs/usage/route.md | 28 +-- docs/usage/spider-subnet.md | 16 +- docs/usage/third-party-controller.md | 2 +- test/Makefile.defs | 2 +- 38 files changed, 1024 insertions(+), 760 deletions(-) rename docs/concepts/{performance-zh_CH.md => performance-zh_CN.md} (81%) create mode 100644 docs/images/ip-allocation-across-networks-1.png create mode 100644 docs/images/ip-allocation-across-networks-2.png diff --git a/README-zh_CN.md b/README-zh_CN.md index 585bf0b058..4846ec1bb0 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -227,7 +227,7 @@ Spiderpool 提供了节点拓扑的 IP 池功能,与虚拟机的相同 IP 分 * 设置全局的预留 IP,让 IPAM 不分配出这些 IP 地址,这样能避免与集群外部的已用 IP 冲突。 可参考[例子](./docs/usage/reserved-ip.md)。 -* 分配和释放 IP 地址的高效性能,可参考[报告](./docs/concepts/performance-zh_CH.md)。 +* 分配和释放 IP 地址的高效性能,可参考[报告](./docs/concepts/performance-zh_CN.md)。 * 合理的 IP 回收机制设计,使得集群或应用在故障恢复过程中,能够及时分配到 IP 地址。可参考[例子](./docs/usage/gc.md)。 diff --git a/docs/README-zh_CN.md b/docs/README-zh_CN.md index 9521f4eaf0..abd4f14f77 100644 --- a/docs/README-zh_CN.md +++ b/docs/README-zh_CN.md @@ -227,7 +227,7 @@ Spiderpool 提供了节点拓扑的 IP 池功能,与虚拟机的相同 IP 分 * 设置全局的预留 IP,让 IPAM 不分配出这些 IP 地址,这样能避免与集群外部的已用 IP 冲突。 可参考[例子](./usage/reserved-ip.md)。 -* 分配和释放 IP 地址的高效性能,可参考[报告](./concepts/performance-zh_CH.md)。 +* 分配和释放 IP 地址的高效性能,可参考[报告](./concepts/performance-zh_CN.md)。 * 合理的 IP 回收机制设计,使得集群或应用在故障恢复过程中,能够及时分配到 IP 地址。可参考[例子](./usage/gc.md)。 diff --git a/docs/concepts/performance-zh_CH.md b/docs/concepts/performance-zh_CN.md similarity index 81% rename from docs/concepts/performance-zh_CH.md rename to docs/concepts/performance-zh_CN.md index 05ce3d08ee..be44e423cd 100644 --- a/docs/concepts/performance-zh_CH.md +++ b/docs/concepts/performance-zh_CN.md @@ -1,5 +1,7 @@ # Spiderpool 性能测试 +**简体中文** | [**English**](./performance.md) + *[Spiderpool](https://github.com/spidernet-io/spiderpool) 是一个适用于 underlay 网络的高性能 IPAM CNI 插件,此文将对比其与市面上主流的 underlay IPAM CNI 插件(如 [Whereabouts](https://github.com/k8snetworkplumbingwg/whereabouts),[Kube-OVN](https://github.com/kubeovn/kube-ovn))以及被广泛使用的 overlay IPAM CNI 插件 [calico-ipam](https://github.com/projectcalico/calico) 在 ”1000 Pod“ 场景下的性能表现。* ## 背景 @@ -17,29 +19,29 @@ - OS: `CentOS Linux 8` - kernel: `4.18.0-348.7.1.el8_5.x86_64` -| Node | Role | CPU | Memory | -| -------- | ------------- | ---- | ------ | -| master1 | control-plane | 4C | 8Gi | -| master2 | control-plane | 4C | 8Gi | -| master3 | control-plane | 4C | 8Gi | -| worker4 | | 3C | 8Gi | -| worker5 | | 3C | 8Gi | -| worker6 | | 3C | 8Gi | -| worker7 | | 3C | 8Gi | -| worker8 | | 3C | 8Gi | -| worker9 | | 3C | 8Gi | -| worker10 | | 3C | 8Gi | +| Node | Role | CPU | Memory | +| -------- | ------------- | --- | ------ | +| master1 | control-plane | 4C | 8Gi | +| master2 | control-plane | 4C | 8Gi | +| master3 | control-plane | 4C | 8Gi | +| worker4 | | 3C | 8Gi | +| worker5 | | 3C | 8Gi | +| worker6 | | 3C | 8Gi | +| worker7 | | 3C | 8Gi | +| worker8 | | 3C | 8Gi | +| worker9 | | 3C | 8Gi | +| worker10 | | 3C | 8Gi | ## 测试对象 本次测试基于 `0.3.1` 版本的 [CNI Specification](https://www.cni.dev/docs/spec/),以 [macvlan](https://www.cni.dev/plugins/current/main/macvlan/) 搭配 Spiderpool 作为测试方案,并选择了开源社区中其它几种对接 underlay 网络的方案作为对比: -| Main CNI | Main CNI 版本 | IPAM CNI | IPAM CNI 版本 | 特点 | -| ------------------- | ------------- | ------------------------- | ------------- | ------------------------------------------------------------ | +| Main CNI | Main CNI 版本 | IPAM CNI | IPAM CNI 版本 | 特点 | +| ------------------- | ------------- | ------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | macvlan | `v1.1.1` | Spiderpool | `v0.4.1` | 集群中存在多个 IP 池,每个池中的 IP 地址都可以被集群中的任意一个节点上的 Pod 所使用,当集群中的多个 Pod 并发的从同一个池中分配 IP 地址时,存在竞争。支持托管 IP 池的全生命流程,使其同步的与工作负载创建、扩缩容、删除,弱化了过大的共享池所带来的并发或存储问题。 | -| macvlan | `v1.1.1` | Whereabouts (CRD backend) | `v0.6.1` | 各节点可以定义各自可用的 IP 池范围,若节点间存在重复定义的 IP 地址,那么这些 IP 地址上升为一种共享资源。 | -| Kube-OVN (underlay) | `v1.11.3` | Kube-OVN | `v1.11.3` | 以子网来组织 IP 地址,每个 Namespace 可以归属于特定的子网, Namespace 下的 Pod 会自动从所属的子网中获取 IP 地址。子网也是一种集群资源,同一个子网的 IP 地址可以分布在任意一个节点上。 | -| Calico | `v3.23.3` | calico-ipam (CRD backend) | `v3.23.3` | 每个节点独享一个或多个 IP block,各节点上的 Pod 仅使用本地 IP block 中的 IP 地址,节点间无任何竞争与冲突,分配的效率非常高。 | +| macvlan | `v1.1.1` | Whereabouts (CRD backend) | `v0.6.1` | 各节点可以定义各自可用的 IP 池范围,若节点间存在重复定义的 IP 地址,那么这些 IP 地址上升为一种共享资源。 | +| Kube-OVN (underlay) | `v1.11.3` | Kube-OVN | `v1.11.3` | 以子网来组织 IP 地址,每个 Namespace 可以归属于特定的子网, Namespace 下的 Pod 会自动从所属的子网中获取 IP 地址。子网也是一种集群资源,同一个子网的 IP 地址可以分布在任意一个节点上。 | +| Calico | `v3.23.3` | calico-ipam (CRD backend) | `v3.23.3` | 每个节点独享一个或多个 IP block,各节点上的 Pod 仅使用本地 IP block 中的 IP 地址,节点间无任何竞争与冲突,分配的效率非常高。 | ## 方案 diff --git a/docs/concepts/performance.md b/docs/concepts/performance.md index b0c80ee13f..2b1e86cc0e 100644 --- a/docs/concepts/performance.md +++ b/docs/concepts/performance.md @@ -1,5 +1,7 @@ # Spiderpool Performance Testing +**English** | [**简体中文**](./performance-zh_CN.md) + *[Spiderpool](https://github.com/spidernet-io/spiderpool) is a high-performance IPAM CNI plugin for underlay networks. This report will compare its performance with the mainstream underlay IPAM CNI plugins (such as [Whereabouts](https://github.com/k8snetworkplumbingwg/whereabouts), [Kube-OVN](https://github.com/kubeovn/kube-ovn)) and the widely used overlay IPAM CNI plugin [calico-ipam](https://github.com/projectcalico/calico) under the "1000 Pod" scenario.* ## Background @@ -17,29 +19,29 @@ Why do we need to do performance testing on the underlay IPAM CNI plugin? - OS: `CentOS Linux 8` - kernel: `4.18.0-348.7.1.el8_5.x86_64` -| Node | Role | CPU | Memory | -| -------- | ------------- | ---- | ------ | -| master1 | control-plane | 4C | 8Gi | -| master2 | control-plane | 4C | 8Gi | -| master3 | control-plane | 4C | 8Gi | -| worker4 | | 3C | 8Gi | -| worker5 | | 3C | 8Gi | -| worker6 | | 3C | 8Gi | -| worker7 | | 3C | 8Gi | -| worker8 | | 3C | 8Gi | -| worker9 | | 3C | 8Gi | -| worker10 | | 3C | 8Gi | +| Node | Role | CPU | Memory | +| -------- | ------------- | --- | ------ | +| master1 | control-plane | 4C | 8Gi | +| master2 | control-plane | 4C | 8Gi | +| master3 | control-plane | 4C | 8Gi | +| worker4 | | 3C | 8Gi | +| worker5 | | 3C | 8Gi | +| worker6 | | 3C | 8Gi | +| worker7 | | 3C | 8Gi | +| worker8 | | 3C | 8Gi | +| worker9 | | 3C | 8Gi | +| worker10 | | 3C | 8Gi | ## Objects This test is based on the [CNI Specification](https://www.cni.dev/docs/spec/) `0.3.1`, using [macvlan](https://www.cni.dev/plugins/current/main/macvlan/)with Spiderpool, and selecting several other underlay network solutions in the open source community for comparison: -| Main CNI | Main CNI Version | IPAM CNI | IPAM CNI Version | Features | -| ------------------- | ---------------- | ------------------------- | ---------------- | ------------------------------------------------------------ | +| Main CNI | Main CNI Version | IPAM CNI | IPAM CNI Version | Features | +| ------------------- | ---------------- | ------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | macvlan | `v1.1.1` | Spiderpool | `v0.4.1` | There are multiple IP pools in a cluster, and the IP addresses in each pool can be used by Pods on any Node in the cluster. Competition occurs when multiple Pods in a cluster allocate IP addresses from the same pool. Support hosting the entire lifecycle of an IP pool, synchronizing it with workload creation, scaling, deletion, and reducing concurrency or storage issues caused by overly large shared pools. | -| macvlan | `v1.1.1` | Whereabouts (CRD backend) | `v0.6.1` | Each Node can define its own available IP pool ranges. If there are duplicate IP addresses defined between Nodes, these IP addresses are promoted as a shared resource. | -| Kube-OVN (underlay) | `v1.11.3` | Kube-OVN | `v1.11.3` | IP addresses are organized by Subnet. Each Namespace can belong to a specific Subnet. Pods under the Namespace will automatically obtain IP addresses from the Subnet they belong to. Subnets are also a cluster resource, and the IP addresses of the same Subnet can be distributed on any Node. | -| Calico | `v3.23.3` | calico-ipam (CRD backend) | `v3.23.3` | Each Node has one or more IP blocks exclusively, and the Pods on each Node only use the IP addresses in the local IP block. There is no competition or conflict between Nodes, and the allocation efficiency is very high. | +| macvlan | `v1.1.1` | Whereabouts (CRD backend) | `v0.6.1` | Each Node can define its own available IP pool ranges. If there are duplicate IP addresses defined between Nodes, these IP addresses are promoted as a shared resource. | +| Kube-OVN (underlay) | `v1.11.3` | Kube-OVN | `v1.11.3` | IP addresses are organized by Subnet. Each Namespace can belong to a specific Subnet. Pods under the Namespace will automatically obtain IP addresses from the Subnet they belong to. Subnets are also a cluster resource, and the IP addresses of the same Subnet can be distributed on any Node. | +| Calico | `v3.23.3` | calico-ipam (CRD backend) | `v3.23.3` | Each Node has one or more IP blocks exclusively, and the Pods on each Node only use the IP addresses in the local IP block. There is no competition or conflict between Nodes, and the allocation efficiency is very high. | ## Plan diff --git a/docs/images/ip-allocation-across-networks-1.png b/docs/images/ip-allocation-across-networks-1.png new file mode 100644 index 0000000000000000000000000000000000000000..9cef17968e45e49d954986478a2bab32082edc73 GIT binary patch literal 43480 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�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ⅇ75xVA??+CjgwsUoC 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 X1hKGLJV#OSs0%e8={&5wZyEG&t(Q;- literal 0 HcmV?d00001 diff --git a/docs/images/ip-allocation-across-networks-2.png b/docs/images/ip-allocation-across-networks-2.png new file mode 100644 index 0000000000000000000000000000000000000000..d248faff7c3aa95d10aded89c96b7785b2ec6c5e GIT binary patch literal 107475 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 ZdKv@DAB~e)77*}HNnTa1RK_Iue*w!tMb-cS literal 0 HcmV?d00001 diff --git a/docs/usage/_feature_example_zh.md b/docs/usage/_feature_example_zh.md index 40ca29a95f..c5e307863c 100644 --- a/docs/usage/_feature_example_zh.md +++ b/docs/usage/_feature_example_zh.md @@ -10,7 +10,7 @@ ## 实施要求 -安装要求,如 内核限制、K8S版本、第三方项目版本等,本项目安装时哪些选型要打开或关闭 +安装要求,如内核限制、K8s 版本、第三方项目版本等,本项目安装时哪些选型要打开或关闭 ## 步骤 diff --git a/docs/usage/_install_example_zh.md b/docs/usage/_install_example_zh.md index 78d852559f..7d459631c4 100644 --- a/docs/usage/_install_example_zh.md +++ b/docs/usage/_install_example_zh.md @@ -6,7 +6,7 @@ ## 实施要求 -安装要求,如 内核限制、K8S版本、第三方项目版本等 +安装要求,如内核限制、K8s 版本、第三方项目版本等 ## 步骤 diff --git a/docs/usage/gc-zh_CN.md b/docs/usage/gc-zh_CN.md index f6dd330c15..2878a3a1d0 100644 --- a/docs/usage/gc-zh_CN.md +++ b/docs/usage/gc-zh_CN.md @@ -2,53 +2,18 @@ [**English**](./gc.md) | **简体中文** -Spiderpool 有一个 IP 垃圾回收机制,它可以帮助清理 CNI `cmdDel` 失败后泄漏的 IP。 +## 介绍 -## 启用 IP 回收支持 +在 Kubernetes 中,垃圾回收(Garbage Collection,简称GC)对于 IP 地址的回收非常重要。IP 地址的可用性关系到 Pod 是否能够启动成功。GC 机制可以自动回收这些不再使用的 IP 地址,避免资源浪费和 IP 地址的耗尽。本文将介绍 Spiderpool 优秀的 GC 能力。 -检查 `spiderpool-controller` Kubernetes 部署的 `SPIDERPOOL_GC_IP_ENABLED` 环境属性是否已设置为 `true`(默认已启用)。 +## 项目功能 -```shell -kubectl edit deploy spiderpool-controller -n kube-system -``` +在 IPAM 中记录了分配给 Pod 使用的 IP 地址,但是这些 Pod 在 Kubernetes 集群中已经不复存在,这些 IP 可称为 `僵尸 IP` ,Spiderpool 可针对 `僵尸 IP` 进行回收,它的实现原理如下: -## 设计 +在集群中 `delete Pod` 时,但由于`网络异常`或 `cni 二进制 crash` 等问题,导致调用 `cni delete` 失败,从而导致 IP 地址无法被 cni 回收。 -spiderpool-controller 使用 `Pod informer` 和定期间隔扫描所有 SpiderIPPool 实例来清理泄漏的 IP 及其相应的 -SpiderEndpoint 对象。使用内存缓存来追踪应该清理的具有相应 IP 和 SpiderEndpoint 对象的 Pod。 +- 在 `cni delete 失败` 等故障场景,如果一个曾经分配了 IP 的 Pod 被销毁后,但在 IPAM 中还记录分配着IP 地址,形成了僵尸 IP 的现象。Spiderpool 针对这种问题,会基于周期和事件扫描机制,自动回收这些僵尸 IP 地址。 -以下是释放 IP 的几种情况: +节点意外宕机后,集群中的 Pod 永久处于 `deleting` 状态,Pod 占用的 IP 地址无法被释放。 -* Pod 被 `deleted`,不包括 StatefulSet 重启其 Pod 的情况。 - -* Pod 正在 `Terminating`,我们将在 `spec.terminationGracePeriodSecond` 后释放其 IP, - 您可以设置 `AdditionalGraceDelay`(默认为 0 秒)环境变量以添加延迟时间。 - 您还可以使用环境变量 `SPIDERPOOL_GC_TERMINATING_POD_IP_ENABLED`(默认已启用)确定是否回收 - `Terminating` 状态的 Pod。此环境变量可能在以下两种情况中有所帮助: - - 1. 如果集群中的某个节点挂了,您必须依靠 IP GC 来释放这些 IP。 - 2. 在某些基础模式下,如果不释放正在终止 Pod 的 IP,新 Pod 将因为缺少 IP 资源无法获取可用的 IP 去运行。 - - 然而,有一种特殊情况需要注意:如果节点由于接口或网络问题与 Master API 服务器失去连接, - 则 Pod 网络仍然可以正常工作。在这种情况下,如果我们释放其 IP 并将其分配给其他 Pod,会导致 IP 冲突。 - -* Pod 处于 `Succeeded` 或 `Failed` 阶段,我们将在 `pod.DeletionGracePeriodSeconds` 后清理 Pod 的 IP, - 您可以设置 `AdditionalGraceDelay`(默认为 0 秒)环境变量以添加延迟时间。 - -* SpiderIPPool 分配的 IP 所对应的 Pod 在 Kubernetes 中不存在,不包括 StatefulSet 重启其 Pod 的情况。 - -* Pod UID 不同于 SpiderIPPool IP 分配的 Pod UID。 - -## 注意事项 - -* `spiderpool-controller` 有多个副本并使用领导者选举。IP 垃圾回收 `pod informer` 仅为 `Master` 服务。 - 但是,每个备份都会使用 `scan all SpiderIPPool` 以立即释放应清理的泄漏 IP。 - 在上述 Pod 状态下,它不会追踪内存缓存中的 Pod。 - -* 我们可以使用环境变量 `SPIDERPOOL_GC_ADDITIONAL_GRACE_DELAY`(默认为 5 秒)更改追踪 Pod `AdditionalGraceDelay`。 - -* 如果集群中有一个节点损坏,且启用了 `SPIDERPOOL_GC_TERMINATING_POD_IP_ENABLED` 环境变量, - IP GC 将强制释放不可达的 Pod 对应的 IP。还有一种罕见情况,即在 Pod 的 `DeletionGracePeriod` 时间之后, - 您的 Pod 仍然存活。IP GC 仍将强制释放无法访问的 Pod 对应的 IP。对于这两种情况,我们建议 Main CNI 具有检查 - IP 冲突的功能。[Veth](https://github.com/spidernet-io/plugins) 插件已经实现了此功能, - 您可以协调使用 `Macvlan` 或 `SR-IOV` CNI。 +- 对处于 `Terminating` 状态的 Pod,Spiderpool 将在 Pod 的 `spec.terminationGracePeriodSecond` 后,自动释放其 IP 地址。该功能可通过环境变量 `SPIDERPOOL_GC_TERMINATING_POD_IP_ENABLED` 来控制。该能力能够用以解决 `节点意外宕机` 的故障场景。 diff --git a/docs/usage/gc.md b/docs/usage/gc.md index d45e50bfcc..b443d1da05 100644 --- a/docs/usage/gc.md +++ b/docs/usage/gc.md @@ -2,46 +2,18 @@ **English** | [**简体中文**](./gc-zh_CN.md) -Spiderpool has an IP garbage collection mechanism that helps to clean up leaked IPs once CNI cmdDel fails. +## Introduce -## Enable IP GC Support +In Kubernetes, garbage collection (Garbage Collection, GC for short) is very important for the recycling of IP addresses. The availability of IP addresses is critical to whether a Pod can start successfully. The GC mechanism can automatically reclaim these unused IP addresses, avoiding waste of resources and exhaustion of IP addresses. This article will introduce Spiderpool's excellent GC capabilities. -Check the `SPIDERPOOL_GC_IP_ENABLED` environment property of the `spiderpool-controller` Kubernetes deployment to see if it is already set to `true`. (It is enabled by default.) +## Project Functions -```shell -kubectl edit deploy spiderpool-controller -n kube-system -``` +The IP addresses assigned to Pods are recorded in IPAM, but these Pods no longer exist in the Kubernetes cluster. These IPs can be called `zombie IPs`. Spiderpool can recycle `zombie IPs`. Its implementation principle is as follows : -## Design +When `deleting Pod` in the cluster, but due to problems such as `network exception` or `cni binary crash`, the call to `cni delete` fails, resulting in the IP address not being reclaimed by cni. -The spiderpool-controller uses `pod informer` and regular interval `scan all SpiderIPPool` to clean up leaked IPs and corresponding SpiderEndpoint objects. -We used a memory cache to record the Pods object that the corresponding IPs and SpiderEndpoint objects should be cleaned up. +- In failure scenarios such as `cni delete failure`, if a Pod that has been assigned an IP is destroyed, but the IP address is still recorded in the IPAM, a phenomenon of zombie IP is formed. For this kind of problem, Spiderpool will automatically recycle these zombie IP addresses based on the cycle and event scanning mechanism. -Here are several cases in which we release IP: +After a node goes down unexpectedly, the Pod in the cluster is permanently in the `deleting` state, and the IP address occupied by the Pod cannot be released. -* Pod was `deleted`, except StatefulSet restarts its Pod situation. - -* Pod is `Terminating`, we will release its IPs after `spec.terminationGracePeriodSecond`, you can set environment `AdditionalGraceDelay`(default 0 seconds) to add delay duration. you can also determine whether gc `Terminating` status Pod or not with environment `SPIDERPOOL_GC_TERMINATING_POD_IP_ENABLED`. (It would be enabled by default). There are two cases that this env may help: - - 1. If one node encounters downtime in your cluster, you must rely on the IP GC to release the IPs. - 2. In some underlay mode, if you do not release one IP with terminating Pod and the new Pod cannot fetch available IP to start because of the IP resources shortage. - - But there's a special case we should watch out for: if the node lost the connection with the master API server due to the node Interface or network issues, the Pod network may also be good and still serves well. In this case, if we release its IPs and allocate them to other Pods, this will lead to IP conflict. - -* Pod is in the `Succeeded` or `Failed` phase, we'll clean the Pod's IPs after `pod.DeletionGracePeriodSeconds`, you can set the `AdditionalGraceDelay`(default 0 seconds) environment variable to add delay duration. - -* SpiderIPPool allocated IP corresponding Pod does not exist in Kubernetes, except StatefulSet restarts its Pod situation. - -* The Pod UID is different from the SpiderIPPool IP allocation Pod UID. - -## Notice - -* The `spiderpool-controller` has multiple replicas and uses leader election. The IP Garbage Collection `pod informer` only serves the `Master`. - However, every backup will use `scan all SpiderIPPool` to release the leaked IPs that should be cleaned up immediately. It will not trace the Pod into memory cache with the upper Pod status cases. - -* We can change tracing Pod `AdditionalGraceDelay` with the environment `SPIDERPOOL_GC_ADDITIONAL_GRACE_DELAY`(default 5 seconds). - -* If one node breaks in your cluster, the IP GC will forcibly release the unreachable Pod corresponding IPs if you enable the `SPIDERPOOL_GC_TERMINATING_POD_IP_ENABLED` environment variable. - There is also a rare situation where your Pod is still alive even after the `DeletionGracePeriod` duration. The IP GC will still forcibly release the unreachable Pod corresponding IPs. - For these two cases, we recommend that the Main CNI has the ability to check for IP conflicts. - The [Veth](https://github.com/spidernet-io/plugins) plugin already implements this feature, and you can use it in collaboration with `Macvlan` or `SR-IOV` CNI. +- For a Pod in `Terminating` state, Spiderpool will automatically release its IP address after the Pod's `spec.terminationGracePeriodSecond`. This feature can be controlled by the environment variable `SPIDERPOOL_GC_TERMINATING_POD_IP_ENABLED`. This capability can be used to solve the failure scenario of `unexpected node downtime`. diff --git a/docs/usage/install/install-zh_CN.md b/docs/usage/install/install-zh_CN.md index 7d6c4a35de..2aa9718b06 100644 --- a/docs/usage/install/install-zh_CN.md +++ b/docs/usage/install/install-zh_CN.md @@ -1,3 +1,79 @@ # 安装 -[**English**](./install-zh_CN.md) | **简体中文** +[**English**](./install.md) | **简体中文** + +## 用法 + +安装 Spiderpool 有两种场景: + +- 在 Underlay NICs 下安装 Spiderpool + + 对于这一使用场景,集群可以使用一个或多个 Underlay CNI 来运行 Pod。 + + 当 Pod 中有一个或多个 Underlay NIC 时,Spiderpool 可以帮助其分配 IP 地址、调整路由、连接 Pod 和本地节点、检测 IP 冲突等。 + +- 为 Overlay CNI 的 Pod 添加 Underaly CNI 的辅助网卡 + + 对于这一使用场景,集群可以使用一个 Overlay CNI 和其他 Underlay CNI 来运行 Pod。 + + 当一个 Pod 中有一个或多个不同的网卡时,Spiderpool 可以帮助分配 IP 地址、调整路由、连接 Pod 和本地节点、检测 IP 冲突等。 + +## 在 Underlay NICs 下安装 Spiderpool + +任何与第三方 IPAM 插件兼容的 CNI 项目都可以与 Spiderpool 良好配合,例如: + +[macvlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan), +[vlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/vlan), +[ipvlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/ipvlan), +[sriov CNI](https://github.com/k8snetworkplumbingwg/sriov-cni), +[ovs CNI](https://github.com/k8snetworkplumbingwg/ovs-cni), +[Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni), +[calico CNI](https://github.com/projectcalico/calico), +[weave CNI](https://github.com/weaveworks/weave) + +以下是 Underlay NICs 下安装 Spiderpool 的示例: + +- [macvlan in Kind](./underlay/get-started-kind-zh_CN.md) + +- [SRIOV CNI](./underlay/get-started-sriov-zh_CN.md), 适合裸机主机这样的场景。 + +- [calico CNI](./underlay/get-started-calico-zh_CN.md) + +- [weave CNI](./underlay/get-started-weave-zh_CN.md) + +- [ovs CNI](./underlay/get-started-ovs-zh_CN.md), 适合裸机主机这样的场景。 + +以下示例是在集群中使用两个 CNI 的高级示例: + +- [SRIOV and macvlan](./underlay/get-started-macvlan-and-sriov.md),这个适用于裸机主机等场景,有些节点有 SRIOV 网卡而有些节点没有 + +## 在云基础设施上安装 Underlay CNI + +- [alibaba cloud](./cloud/get-started-alibaba.md) + +- [vmware vsphere](./cloud/get-started-vmware.md) + +- [openstack](./cloud/get-started-openstack.md) + +## 为 Overlay CNI 的 Pod 添加 Underaly CNI 的辅助网卡 + +以下示例是安装 Spiderpool 的指南: + +- [calico and macvlan CNI](./overlay/get-started-calico.md) + +- [cilium and macvlan CNI](./overlay/get-started-cilium.md) + +## 卸载 + +一般情况下,您可以通过以下方式卸载当前的 Spiderpool 版本: + +```bash +helm uninstall spiderpool -n kube-system +``` + +然而,Spiderpool 的某些 CR 中存在 [finalizers](https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers/),`helm uninstall` cmd 可能无法清理所有相关的 CR。 获取下列示例的清理脚本并执行它,以确保下次部署 Spiderpool 时不会出现意外错误。 + +```bash +wget https://raw.githubusercontent.com/spidernet-io/spiderpool/main/tools/scripts/cleanCRD.sh +chmod +x cleanCRD.sh && ./cleanCRD.sh +``` diff --git a/docs/usage/install/install.md b/docs/usage/install/install.md index 7857bdf0ee..36032358b4 100644 --- a/docs/usage/install/install.md +++ b/docs/usage/install/install.md @@ -18,24 +18,22 @@ It could have two kinds of scenes to install spiderpool: When one or more NIC of different NIC in a pod, spiderpool could help assign IP address, tune routes, connect the pod and local node, detect IP conflict etc. -## Installation for underlay NICs +## Install Spiderpool in Underlay NICs Any CNI project compatible with third-party IPAM plugins, can work well with spiderpool, such as: -[macvlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan), -[vlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/vlan), +[macvlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan), +[vlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/vlan), [ipvlan CNI](https://github.com/containernetworking/plugins/tree/main/plugins/main/ipvlan), -[sriov CNI](https://github.com/k8snetworkplumbingwg/sriov-cni), -[ovs CNI](https://github.com/k8snetworkplumbingwg/ovs-cni), -[Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni), -[calico CNI](https://github.com/projectcalico/calico), +[sriov CNI](https://github.com/k8snetworkplumbingwg/sriov-cni), +[ovs CNI](https://github.com/k8snetworkplumbingwg/ovs-cni), +[Multus CNI](https://github.com/k8snetworkplumbingwg/multus-cni), +[calico CNI](https://github.com/projectcalico/calico), [weave CNI](https://github.com/weaveworks/weave) The following examples are guides to install spiderpool: * [macvlan in Kind](./underlay/get-started-kind.md) -* [macvlan CNI](./underlay/get-started-macvlan.md), this is suitable for scenes like bare metal host, vmware VM with promiscuous bridge. - * [SRIOV CNI](./underlay/get-started-sriov.md), this is suitable for scenes like bare metal host. * [calico CNI](./underlay/get-started-calico.md) diff --git a/docs/usage/install/overlay/get-started-calico.md b/docs/usage/install/overlay/get-started-calico.md index 0592e93b15..508018a0ae 100644 --- a/docs/usage/install/overlay/get-started-calico.md +++ b/docs/usage/install/overlay/get-started-calico.md @@ -1 +1,3 @@ -# calico +# Calico + +_TODO._ diff --git a/docs/usage/install/overlay/get-started-cilium.md b/docs/usage/install/overlay/get-started-cilium.md index 3bb0bed3ea..e69de29bb2 100644 --- a/docs/usage/install/overlay/get-started-cilium.md +++ b/docs/usage/install/overlay/get-started-cilium.md @@ -1 +0,0 @@ -# cilium diff --git a/docs/usage/install/underlay/get-started-calico-zh_CN.md b/docs/usage/install/underlay/get-started-calico-zh_CN.md index 542b354664..c6f6845f74 100644 --- a/docs/usage/install/underlay/get-started-calico-zh_CN.md +++ b/docs/usage/install/underlay/get-started-calico-zh_CN.md @@ -18,31 +18,26 @@ Spiderpool 可用作 Underlay 网络场景下,为 Deployment、StatefulSet 等 确认 calico 开启了 fullmesh 方式的 BGP 配置。 -* 确认 SpiderPool 开启 Subnet 功能。 - * Helm、Calicoctl 二进制工具 ## 安装 Spiderpool ```shell helm repo add spiderpool https://spidernet-io.github.io/spiderpool -helm install spiderpool spiderpool/spiderpool --namespace kube-system --set ipam.enableSpiderSubnet=true --set multus.multusCNI.install=false +helm repo update spiderpool +helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.install=false ``` -> Spiderpool 默认 IPv4-Only, 如需启用 IPv6 请参考 [Spiderpool IPv6](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/ipv6.md) -> -> `ipam.enableSpiderSubnet=true`: Spiderpool 的 subnet 功能需要被打开。 -> > 如果您是国内用户,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` 避免 Spiderpool 的镜像拉取失败。 -创建 Pod 的子网(SpiderSubnet): +创建 Pod 使用的 SpiderIPPool 实例: ```shell cat << EOF | kubectl apply -f - apiVersion: spiderpool.spidernet.io/v2beta1 -kind: SpiderSubnet +kind: SpiderIPPool metadata: - name: nginx-subnet-v4 + name: nginx-ippool-v4 labels: ipam.spidernet.io/subnet-cidr: 10-244-0-0-16 spec: @@ -55,19 +50,21 @@ EOF 验证安装: ```shell -[root@master ~]# kubectl get po -n kube-system | grep spiderpool - spiderpool-agent-27fr2 1/1 Running 0 2m - spiderpool-agent-8vwxj 1/1 Running 0 2m - spiderpool-controller-bc8d67b5f-xwsql 1/1 Running 0 2m - [root@master ~]# kubectl get ss +[root@master ~]# kubectl get po -n kube-system |grep spiderpool + spiderpool-agent-7hhkz 1/1 Running 0 13m + spiderpool-agent-kxf27 1/1 Running 0 13m + spiderpool-controller-76798dbb68-xnktr 1/1 Running 0 13m + spiderpool-init 0/1 Completed 0 13m + [root@master ~]# kubectl get sp NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT - nginx-subnet-v4 4 10.244.0.0/16 0 25602 + nginx-ippool-v4 4 10.244.0.0/16 0 25602 ``` ## 配置 Calico BGP [可选] -本例希望 calico 以 underlay 方式工作,将 Spiderpool 子网(`10.244.0.0/16`)通过 BGP 协议宣告至 BGP Router,确保集群外的客户端可以通过 BGP Router 直接访问 Pod 真实的 IP 地址。 -如果您并不需要集群外部可以直接访问到 pod ip,可忽略本步骤。 +本例希望 calico 以 underlay 方式工作,将 Spiderpool 的 IP 池所在的子网(`10.244.0.0/16`)通过 BGP 协议宣告至 BGP Router,确保集群外的客户端可以通过 BGP Router 直接访问 Pod 真实的 IP 地址。 + +> 如果您并不需要集群外部可以直接访问到 Pod IP,可忽略本步骤。 网络拓扑如下: @@ -105,7 +102,7 @@ EOF > * Router 侧的 AS 为 `23000`, 集群节点侧 AS 为 `64512`。Router 与节点之间为 `ebgp`, 节点之间为 `ibgp` > * 需要关闭 `ebgp-requires-policy`, 否则 BGP 会话无法建立 > * 172.16.13.11/21 为集群节点 IP - > + > > 更多配置参考 [frrouting](https://docs.frrouting.org/en/latest/bgp.html)。 2. 配置 Calico 的 BGP 邻居 @@ -151,7 +148,7 @@ EOF ``` > peerIP 为 BGP Router 的 IP 地址 - > + > > asNumber 为 BGP Router 的 AS 号 查看 BGP 会话是否成功建立: @@ -182,7 +179,7 @@ cat << EOF | calicoctl apply -f - apiVersion: projectcalico.org/v3 kind: IPPool metadata: - name: spiderpool-subnet + name: spiderpool-ippool spec: blockSize: 26 cidr: 10.244.0.0/16 @@ -194,7 +191,7 @@ EOF ``` > cidr 需要对应 Spiderpool 的子网: `10.244.0.0/16` -> +> > 设置 ipipMode 和 vxlanMode 为: Never ## 切换 Calico 的 `IPAM` 为 Spiderpool @@ -225,8 +222,7 @@ spec: template: metadata: annotations: - ipam.spidernet.io/subnet: '{"ipv4":["nginx-subnet-v4"]}' - ipam.spidernet.io/ippool-ip-number: '+3' + ipam.spidernet.io/ippool: '{"ipv4":["nginx-ippool-v4"]}' labels: app: nginx spec: @@ -241,21 +237,18 @@ spec: EOF ``` -> `ipam.spidernet.io/subnet`: 从 "nginx-subnet-v4" SpiderSubnet 中分配固定 IP -> -> `ipam.spidernet.io/ippool-ip-number`: '+3' 表示应用分配的固定 IP 数量比应用副本数多 3 个,用于应用滚动发布时有临时 IP 可用 +> `ipam.spidernet.io/ippool`: 从 "nginx-ippool-v4" SpiderIPPool 中分配固定 IP +> -当应用 Pod 被创建,Spiderpool 从 annnotations 指定的 `subnet: nginx-subnet-v4` 中自动创建了一个名为 `auto-nginx-v4-eth0-452e737e5e12` 的 IP 池,并与应用绑定。IP 范围为: `10.244.100.90-10.244.100.95`, 池 IP 数量为 `5`: +当应用 Pod 被创建,Spiderpool 从 annnotations 指定的 `ippool: nginx-ippool-v4` 中给 Pod 分配 IP。 ```shell [root@master1 ~]# kubectl get sp -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -auto-nginx-v4-eth0-452e737e5e12 4 10.244.0.0/16 2 5 false false -[root@master ~]# kubectl get sp auto-nginx-v4-eth0-452e737e5e12 -o jsonpath='{.spec.ips}' -["10.244.100.90-10.244.100.95"] +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +nginx-ippool-v4 4 10.244.0.0/16 2 25602 false false ``` -当副本重启,其 IP 都被固定在 `auto-nginx-v4-eth0-452e737e5e12` 的 IP 池范围内: +当副本重启,其 IP 都被固定在 `nginx-ippool-v4` 的 IP 池范围内: ```shell [root@master1 ~]# kubectl get po -o wide @@ -264,7 +257,7 @@ nginx-644659db67-szgcg 1/1 Running 0 23s 10.244.100.90 nginx-644659db67-98rcg 1/1 Running 0 23s 10.244.100.92 master1 ``` -扩容副本数到 `3`, 新副本的 IP 地址仍然从自动池: `auto-nginx-v4-eth0-452e737e5e12(10.244.100.90-10.244.100.95)` 中分配: +扩容副本数到 `3`, 新副本的 IP 地址仍然从 IP 池: `nginx-ippool-v4` 中分配: ```shell [root@master1 ~]# kubectl scale deploy nginx --replicas 3 # scale pods @@ -276,12 +269,12 @@ nginx-644659db67-98rcg 1/1 Running 0 1m 10.244.100.92 nginx-644659db67-brqdg 1/1 Running 0 10s 10.244.100.94 master1 ``` -查看自动池: `auto-nginx-v4-eth0-452e737e5e12` 的 `ALLOCATED-IP-COUNT` 和 `TOTAL-IP-COUNT` 都新增 1 : +查看 IP 池: `nginx-ippool-v4` 的 `ALLOCATED-IP-COUNT` 新增 1 : ```shell [root@master1 ~]# kubectl get sp -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -auto-nginx-v4-eth0-452e737e5e12 4 10.244.0.0/16 3 6 false false +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +nginx-ippool-v4 4 10.244.0.0/16 3 25602 false false ``` ## 结论 diff --git a/docs/usage/install/underlay/get-started-calico.md b/docs/usage/install/underlay/get-started-calico.md index 5860eab2ef..49d8e1739d 100644 --- a/docs/usage/install/underlay/get-started-calico.md +++ b/docs/usage/install/underlay/get-started-calico.md @@ -18,31 +18,26 @@ Spiderpool is able to provide static IPs to Deployments, StatefulSets, and other Confirm that Calico has enabled BGP configuration in full-mesh mode. -* SpiderPool's subnet feature needs to be enabled. - * Helm and Calicoctl ## Install Spiderpool ```shell helm repo add spiderpool https://spidernet-io.github.io/spiderpool -helm install spiderpool spiderpool/spiderpool --namespace kube-system --set ipam.enableSpiderSubnet=true --set multus.multusCNI.install=false +helm repo update spiderpool +helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.install=false ``` -> Spiderpool is IPv4-Only by default. If you want to enable IPv6, refer to [Spiderpool IPv6](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/ipv6.md). -> -> `ipam.enableSpiderSubnet=true`: SpiderPool's subnet feature needs to be enabled. -> > If you are mainland user who is not available to access ghcr.io,You can specify the parameter `-set global.imageRegistryOverride=ghcr.m.daocloud.io` to avoid image pulling failures for Spiderpool. -Create a subnet for a Pod (SpiderSubnet): +Create the SpiderIPPool instance used by the Pod: ```shell cat << EOF | kubectl apply -f - apiVersion: spiderpool.spidernet.io/v2beta1 -kind: SpiderSubnet +kind: SpiderIPPool metadata: - name: nginx-subnet-v4 + name: nginx-ippool-v4 labels: ipam.spidernet.io/subnet-cidr: 10-244-0-0-16 spec: @@ -55,19 +50,19 @@ EOF Verify the installation: ```shell -[root@master ~]# kubectl get po -n kube-system | grep spiderpool -spiderpool-agent-27fr2 1/1 Running 0 2m -spiderpool-agent-8vwxj 1/1 Running 0 2m -spiderpool-controller-bc8d67b5f-xwsql 1/1 Running 0 2m - -[root@master ~]# kubectl get ss +[root@master ~]# kubectl get po -n kube-system |grep spiderpool +spiderpool-agent-7hhkz 1/1 Running 0 13m +spiderpool-agent-kxf27 1/1 Running 0 13m +spiderpool-controller-76798dbb68-xnktr 1/1 Running 0 13m +spiderpool-init 0/1 Completed 0 13m +[root@master ~]# kubectl get sp NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT -nginx-subnet-v4 4 10.244.0.0/16 0 25602 +nginx-ippool-v4 4 10.244.0.0/16 0 25602 ``` ## Configure Calico BGP [optional] -In this example, we want Calico to work in underlay mode and announce the Spiderpool subnet (`10.244.0.0/16`) to the BGP router via the BGP protocol, ensuring that clients outside the cluster can directly access the real IP addresses of the Pods through BGP router. +In this example, we want Calico to work in underlay mode and announce the subnet where Spiderpool's IPPool resides (`10.244.0.0/16`) to the BGP router via the BGP protocol, ensuring that clients outside the cluster can directly access the real IP addresses of the Pods through BGP router. > If you don't need external clients to access pod IPs directly, skip this step. @@ -227,8 +222,7 @@ spec: template: metadata: annotations: - ipam.spidernet.io/subnet: '{"ipv4":["nginx-subnet-v4"]}' - ipam.spidernet.io/ippool-ip-number: '+3' + ipam.spidernet.io/ippool: '{"ipv4":["nginx-ippool-v4"]}' labels: app: nginx spec: @@ -243,22 +237,17 @@ spec: EOF ``` -> `ipam.spidernet.io/subnet`: Assign static IPs from "nginx-subnet-v4" SpiderSubnet -> -> `ipam.spidernet.io/ippool-ip-number`: '+3' means the number of static IPs allocated to the application is three more than the number of its replicas, guaranteeing available temporary IPs during application rolling updates. +> `ipam.spidernet.io/ippool`: Assign static IPs from "nginx-ippool-v4" SpiderIPPool -When a Pod is created, Spiderpool automatically creates an IP pool named `auto-nginx-v4-eth0-452e737e5e12` from `subnet: nginx-subnet-v4` specified in the annotations and binds it to the Pod. The IP range is `10.244.100.90-10.244.100.95`, and the number of IPs in the pool is `5`: +When the application Pod is created, Spiderpool assigns the IP to the Pod from the `ippool: nginx-ippool-v4` specified in the annnotations. ```shell [root@master1 ~]# kubectl get sp -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -auto-nginx-v4-eth0-452e737e5e12 4 10.244.0.0/16 2 5 false false - -[root@master ~]# kubectl get sp auto-nginx-v4-eth0-452e737e5e12 -o jsonpath='{.spec.ips}' -["10.244.100.90-10.244.100.95"] +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +nginx-ippool-v4 4 10.244.0.0/16 2 25602 false false ``` -When the replicas restart, its IP is fixed within the IP pool range of `auto-nginx-v4-eth0-452e737e5e12`: +When replicas are restarted, their IPs are fixed within the range of the `nginx-ippool-v4` IPPool: ```shell [root@master1 ~]# kubectl get po -o wide @@ -267,7 +256,7 @@ nginx-644659db67-szgcg 1/1 Running 0 23s 10.244.100.90 nginx-644659db67-98rcg 1/1 Running 0 23s 10.244.100.92 master1 ``` -When the replica count increases to `3`, the IP address of the new replica is still assigned from the automatic pool: `auto-nginx-v4-eth0-452e737e5e12(10.244.100.90-10.244.100.95)` +Expand the number of replicas to `3`, the IP address of the new replica is still allocated from the IPPool: `nginx-ippool-v4`: ```shell [root@master1 ~]# kubectl scale deploy nginx --replicas 3 # scale pods @@ -280,12 +269,12 @@ nginx-644659db67-98rcg 1/1 Running 0 1m 10.244.100.92 nginx-644659db67-brqdg 1/1 Running 0 10s 10.244.100.94 master1 ``` -Check if both `ALLOCATED-IP-COUNT` and `TOTAL-IP-COUNT` of the automatic pool `auto-nginx-v4-eth0-452e737e5e12` increase by 1: +View IP pool: Added 1 to `ALLOCATED-IP-COUNT` of `nginx-ippool-v4`: ```shell [root@master1 ~]# kubectl get sp -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -auto-nginx-v4-eth0-452e737e5e12 4 10.244.0.0/16 3 6 false false +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +nginx-ippool-v4 4 10.244.0.0/16 3 5 false false ``` ## Conclusion diff --git a/docs/usage/install/underlay/get-started-kind-zh_CN.md b/docs/usage/install/underlay/get-started-kind-zh_CN.md index 09910ae0da..1d1dcae959 100644 --- a/docs/usage/install/underlay/get-started-kind-zh_CN.md +++ b/docs/usage/install/underlay/get-started-kind-zh_CN.md @@ -2,39 +2,53 @@ [**English**](./get-started-kind.md) | **简体中文** -Kind 是一个使用 Docker 容器节点运行本地 Kubernetes 集群的工具。Spiderpool 提供了安装 Kind 集群的脚本,能快速搭建一套以 Macvlan 为 main CNI 搭配 Multus、Spiderpool 的 Kind 集群,您可以使用它来进行 Spiderpool 的测试与体验。 +Kind 是一个使用 Docker 容器节点运行本地 Kubernetes 集群的工具。Spiderpool 提供了安装 Kind 集群的脚本,您可以使用它来部署符合您需求的集群,进行 Spiderpool 的测试与体验。 ## 先决条件 * 已安装 [Go](https://go.dev/) -## Kind 上集群部署 Spiderpool +* 克隆 Spiderpool 代码仓库到本地主机上,并进入 Spiderpool 工程的根目录。 -1. 克隆 Spiderpool 代码仓库到本地主机上,并进入 Spiderpool 工程的根目录。 - ```bash git clone https://github.com/spidernet-io/spiderpool.git && cd spiderpool ``` -2. 执行 `make dev-doctor`,检查本地主机上的开发工具是否满足部署 Kind 集群与 Spiderpool 的条件,如果缺少组件会为您自动安装。 - -3. 通过以下方式获取 Spiderpool 的最新镜像。 +* 通过以下方式获取 Spiderpool 的最新镜像。 ```bash ~# SPIDERPOOL_LATEST_IMAGE_TAG=$(curl -s https://api.github.com/repos/spidernet-io/spiderpool/releases | jq -r '.[].tag_name | select(("^v1.[0-9]*.[0-9]*$"))' | head -n 1) ``` -4. 执行以下命令,创建 Kind 集群,并为您安装 Multus、Macvlan、Spiderpool。 +* 执行 `make dev-doctor`,检查本地主机上的开发工具是否满足部署 Kind 集群与 Spiderpool 的条件,如果缺少组件会为您自动安装。 - ```bash - ~# make e2e_init -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG - ``` +## Spiderpool 脚本支持的多种安装模式 - 注意:如果您是国内用户,您可以使用如下命令,避免拉取 Spiderpool 与 Multus 镜像失败。 +如果您在中国大陆,安装时可以额外指定参数 `-e E2E_CHINA_IMAGE_REGISTRY=true` ,以帮助您更快的拉取镜像。 - ```bash - ~# make e2e_init -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG -e SPIDERPOOL_REGISTER=ghcr.m.daocloud.io -e E2E_MULTUS_IMAGE_REGISTER=ghcr.m.daocloud.io - ``` +### 安装不带子网功能的 Spiderpool 在 Underlay CNI(Macvlan) 集群 + + ```bash + ~# make e2e_init_underlay -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` + +### 安装具有子网功能的 Spiderpool 在 Underlay CNI(Macvlan)集群 + + ```bash + ~# make e2e_init_underlay_subnet -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` + +### 安装 Spiderpool 在 Calico Overlay CNI 集群 + + ```bash + ~# make e2e_init_overlay_calico -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` + +### 安装 Spiderpool 在 Cilium Overlay CNI 集群 + + ```bash + ~# make e2e_init_overlay_cilium -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` ## 验证安装 @@ -44,30 +58,32 @@ Kind 是一个使用 Docker 容器节点运行本地 Kubernetes 集群的工具 ~# export KUBECONFIG=$(pwd)/test/.cluster/spider/.kube/config ``` -您可以看到如下的内容输出: +您可以看到类似如下的内容输出: ```bash -~# kubectl get nodes +~# kubectl get nodes NAME STATUS ROLES AGE VERSION spider-control-plane Ready control-plane 2m29s v1.26.2 spider-worker Ready 2m58s v1.26.2 ~# kubectll get po -n kube-sysem | grep spiderpool -spiderpool-agent-fmx74 1/1 Running 0 4m26s -spiderpool-agent-jzfh8 1/1 Running 0 4m26s -spiderpool-controller-79fcd4d75f-n9kmd 1/1 Running 0 4m25s -spiderpool-controller-79fcd4d75f-scw2v 1/1 Running 0 4m25s -spiderpool-init 1/1 Running 0 4m26s - -~# kubectl get spidersubnet -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT -default-v4-subnet 4 172.18.0.0/16 253 253 -default-v6-subnet 6 fc00:f853:ccd:e793::/64 253 253 +NAME READY STATUS RESTARTS AGE +spiderpool-agent-4dr97 1/1 Running 0 3m +spiderpool-agent-4fkm4 1/1 Running 0 3m +spiderpool-controller-7864477fc7-c5dk4 1/1 Running 0 3m +spiderpool-controller-7864477fc7-wpgjn 1/1 Running 0 3m +spiderpool-init 0/1 Completed 0 3m +spiderpool-multus-66xnx 1/1 Running 0 3m +spiderpool-multus-xwxv4 1/1 Running 0 3m ~# kubectl get spiderippool -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -default-v4-ippool 4 172.18.0.0/16 5 253 true false -default-v6-ippool 6 fc00:f853:ccd:e793::/64 5 253 true false +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT +default-v4-ippool 4 172.18.0.0/16 5 253 true +default-v6-ippool 6 fc00:f853:ccd:e793::/64 5 253 true +vlan100-v4 4 172.100.0.0/16 0 2559 false +vlan100-v6 6 fd00:172:100::/64 0 65009 false +vlan100-v4 4 172.200.0.0/16 0 2559 false +vlan200-v6 6 fd00:172:200::/64 0 65009 false ``` Spiderpool 提供的快速安装 Kind 集群脚本会自动为您创建一个应用,以验证您的 Kind 集群是否能够正常工作,以下是应用的运行状态: @@ -124,6 +140,6 @@ test-app-84d5699474-dbtl5 1/1 Running 0 6m23s 172.18.40.112 * 删除测试镜像 ```bash - ~# docker rmi -f $(docker images | grep spiderpool | awk '{print $3}') + ~# docker rmi -f $(docker images | grep spiderpool | awk '{print $3}') ~# docker rmi -f $(docker images | grep multus | awk '{print $3}') ``` diff --git a/docs/usage/install/underlay/get-started-kind.md b/docs/usage/install/underlay/get-started-kind.md index 4b952d57bb..57449ad7b5 100644 --- a/docs/usage/install/underlay/get-started-kind.md +++ b/docs/usage/install/underlay/get-started-kind.md @@ -2,39 +2,53 @@ **English** | [**简体中文**](./get-started-kind-zh_CN.md) -kind is a tool for running local Kubernetes clusters using Docker container “nodes”. Spiderpool provides a script for installing a Kind cluster, which allows you to quickly build a set of Kind clusters with Macvlan as the main CNI and Multus and Spiderpool, which you can use to test and experience Spiderpool. +Kind is a tool for running local Kubernetes clusters using Docker container "nodes". Spiderpool provides a script to install the Kind cluster, you can use it to deploy a cluster that meets your needs, and test and experience Spiderpool. ## Prerequisites * [Go](https://go.dev/) has already been installed. -## Deploying Spiderpool on a Kind cluster - -1. Clone the Spiderpool code repository to the local host and go to the root directory of the Spiderpool project. +* Clone the Spiderpool code repository to the local host and go to the root directory of the Spiderpool project. ```bash ~# git clone https://github.com/spidernet-io/spiderpool.git && cd spiderpool ``` -2. Execute `make dev-doctor` to check that the development tools on the local host meet the conditions for deploying a Kind cluster with Spiderpool, and that the components are automatically installed for you if they are missing. - -3. Get the latest image of Spiderpool. +* Get the latest image of Spiderpool. ```bash ~# SPIDERPOOL_LATEST_IMAGE_TAG=$(curl -s https://api.github.com/repos/spidernet-io/spiderpool/releases | jq -r '.[].tag_name | select(("^v1.[0-9]*.[0-9]*$"))' | head -n 1) ``` -4. Execute the following command to create a Kind cluster and install Multus, Macvlan, Spiderpool for you. +* Execute `make dev-doctor` to check that the development tools on the local host meet the conditions for deploying a Kind cluster with Spiderpool, and that the components are automatically installed for you if they are missing. - ```bash - ~# make e2e_init -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG - ``` +## Various installation modes supported by Spiderpool script - Note: If you are mainland user who is not available to access ghcr.io, you can use the following command to avoid failures in pulling Spiderpool and Multus images. +If you are mainland user who is not available to access ghcr.io, Additional parameter `-e E2E_CHINA_IMAGE_REGISTRY=true` can be specified during installation to help you pull images faster. - ```bash - ~# make e2e_init -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG -e SPIDERPOOL_REGISTER=ghcr.m.daocloud.io -e E2E_MULTUS_IMAGE_REGISTER=ghcr.m.daocloud.io - ``` +### Install Spiderpool without subnet function in Underlay CNI (Macvlan) cluster + + ```bash + ~# make e2e_init_underlay -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` + +### Install Spiderpool with subnets in Underlay CNI (Macvlan) cluster + + ```bash + ~# make e2e_init_underlay_subnet -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` + +### Install Spiderpool on Calico Overlay CNI cluster + + ```bash + ~# make e2e_init_overlay_calico -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` + +## Install Spiderpool on Cilium Overlay CNI cluster + + ```bash + ~# make e2e_init_overlay_cilium -e E2E_SPIDERPOOL_TAG=$SPIDERPOOL_LATEST_IMAGE_TAG + ``` ## Check that everything is working @@ -47,27 +61,29 @@ Execute the following command in the root directory of the Spiderpool project to It should be possible to observe the following: ```bash -~# kubectl get nodes +~# kubectl get nodes NAME STATUS ROLES AGE VERSION spider-control-plane Ready control-plane 2m29s v1.26.2 spider-worker Ready 2m58s v1.26.2 ~# kubectll get po -n kube-sysem | grep spiderpool -spiderpool-agent-fmx74 1/1 Running 0 4m26s -spiderpool-agent-jzfh8 1/1 Running 0 4m26s -spiderpool-controller-79fcd4d75f-n9kmd 1/1 Running 0 4m25s -spiderpool-controller-79fcd4d75f-scw2v 1/1 Running 0 4m25s -spiderpool-init 1/1 Running 0 4m26s - -~# kubectl get spidersubnet -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT -default-v4-subnet 4 172.18.0.0/16 253 253 -default-v6-subnet 6 fc00:f853:ccd:e793::/64 253 253 +NAME READY STATUS RESTARTS AGE +spiderpool-agent-4dr97 1/1 Running 0 3m +spiderpool-agent-4fkm4 1/1 Running 0 3m +spiderpool-controller-7864477fc7-c5dk4 1/1 Running 0 3m +spiderpool-controller-7864477fc7-wpgjn 1/1 Running 0 3m +spiderpool-init 0/1 Completed 0 3m +spiderpool-multus-66xnx 1/1 Running 0 3m +spiderpool-multus-xwxv4 1/1 Running 0 3m ~# kubectl get spiderippool -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -default-v4-ippool 4 172.18.0.0/16 5 253 true false -default-v6-ippool 6 fc00:f853:ccd:e793::/64 5 253 true false +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT +default-v4-ippool 4 172.18.0.0/16 5 253 true +default-v6-ippool 6 fc00:f853:ccd:e793::/64 5 253 true +vlan100-v4 4 172.100.0.0/16 0 2559 false +vlan100-v6 6 fd00:172:100::/64 0 65009 false +vlan100-v4 4 172.200.0.0/16 0 2559 false +vlan200-v6 6 fd00:172:200::/64 0 65009 false ``` The Quick Install Kind Cluster script provided by Spiderpool will automatically create an application for you to verify that your Kind cluster is working properly and the following is the running state of the application: @@ -124,6 +140,6 @@ As tested, everything works fine with the Kind cluster. You can test and experie * Delete test's images ```bash - ~# docker rmi -f $(docker images | grep spiderpool | awk '{print $3}') + ~# docker rmi -f $(docker images | grep spiderpool | awk '{print $3}') ~# docker rmi -f $(docker images | grep multus | awk '{print $3}') ``` diff --git a/docs/usage/install/underlay/get-started-macvlan-zh_CN.md b/docs/usage/install/underlay/get-started-macvlan-zh_CN.md index 6fc96026d8..d765b775fb 100644 --- a/docs/usage/install/underlay/get-started-macvlan-zh_CN.md +++ b/docs/usage/install/underlay/get-started-macvlan-zh_CN.md @@ -2,7 +2,7 @@ [**English**](./get-started-macvlan.md) | **简体中文** -Spiderpool 可用作 Underlay 网络场景下提供固定 IP 的一种解决方案,本文将以 [Multus](https://github.com/k8snetworkplumbingwg/multus-cni)、[Macvlan](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan)、[Veth](https://github.com/spidernet-io/plugins)、[Spiderpool](https://github.com/spidernet-io/spiderpool) 为例,搭建一套完整的 underlay 网络解决方案,该方案能够满足以下各种功能需求: +Spiderpool 可用作 Underlay 网络场景下提供固定 IP 的一种解决方案,本文将以 [Multus](https://github.com/k8snetworkplumbingwg/multus-cni)、[Macvlan](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan)、[Spiderpool](https://github.com/spidernet-io/spiderpool) 为例,搭建一套完整的 underlay 网络解决方案,该方案能够满足以下各种功能需求: * 通过简易运维,应用可分配到固定的 Underlay IP 地址 @@ -30,121 +30,91 @@ Spiderpool 可用作 Underlay 网络场景下提供固定 IP 的一种解决方 ~# chmod +x /opt/cni/bin/macvlan ``` -## 安装 Veth - -[`Veth`](https://github.com/spidernet-io/plugins) 是一个 CNI 插件,它能够帮助一些 CNI (例如 Macvlan、SR-IOV 等)解决如下问题: - -* 在 Macvlan CNI 场景下,帮助 Pod 实现 clusterIP 通信 - -* 若 Pod 的 Macvlan IP 不能与本地宿主机通信,会影响 Pod 的健康检测。Veth 插件能够帮助 Pod 与宿主机通信,解决健康检测场景下的联通性问题 - -* 在 Pod 多网卡场景下,Veth 能自动够协调多网卡间的策略路由,解决多网卡通信问题 - -请在所有的节点上,下载安装 Veth 二进制: - -```shell -~# wget https://github.com/spidernet-io/plugins/releases/download/v0.1.4/spider-plugins-linux-amd64-v0.1.4.tar - -~# tar xvfzp ./spider-plugins-linux-amd64-v0.1.4.tar -C /opt/cni/bin - -~# chmod +x /opt/cni/bin/veth -``` - -## 安装 Multus - -[`Multus`](https://github.com/k8snetworkplumbingwg/multus-cni) 是一个 CNI 插件项目,它通过调度第三方 CNI 项目,能够实现为 Pod 接入多张网卡。并且,Multus 提供了 CRD 方式管理 Macvlan 的 CNI 配置,避免在每个主机上手动编辑 CNI 配置文件。 +## 安装 Spiderpool -1. 通过 manifest 安装 Multus 的组件。 +1. 安装 Spiderpool。 ```bash - ~# kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/v3.9/deployments/multus-daemonset.yml - ``` + helm repo add spiderpool https://spidernet-io.github.io/spiderpool -2. 确认 Multus 运维状态: + helm repo update spiderpool - ```bash - ~# kubectl get pods -A | grep -i multus - kube-system kube-multus-ds-hfzpl 1/1 Running 0 5m - kube-system kube-multus-ds-qm8j7 1/1 Running 0 5m + helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.defaultCniCRName="macvlan-conf" ``` - 确认节点上存在 Multus 的配置文件 `ls /etc/cni/net.d/00-multus.conf` - -3. 为 Macvlan 创建 Multus 的 NetworkAttachmentDefinition 配置。 - - 需要确认如下参数: - - * 确认 Macvlan 所需的宿主机父接口,本例子以宿主机 eth0 网卡为例,从该网卡创建 Macvlan 子接口给 Pod 使用 + > 如果您是国内用户,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` 避免 Spiderpool 的镜像拉取失败。 + > + > 通过 `multus.multusCNI.defaultCniCRName` 指定集群的 Multus clusterNetwork,clusterNetwork 是 Multus 插件的一个特定字段,用于指定 Pod 的默认网络接口。 - * 为使用 Veth 插件来实现 clusterIP 通信,需确认集群的 service CIDR,例如可基于命令 `kubectl -n kube-system get configmap kubeadm-config -oyaml | grep service` 查询 +2. 创建 SpiderIPPool 实例。 - 以下为创建 NetworkAttachmentDefinition 的配置: + 创建与网络接口 `eth0` 在同一个子网的 IP 池以供 Pod 使用,以下是创建相关的 SpiderIPPool 示例: ```shell - MACVLAN_MASTER_INTERFACE="eth0" - SERVICE_CIDR="10.96.0.0/16" - cat < 如果您是国内用户,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` 避免 Spiderpool 的镜像拉取失败。 +## 创建 CNI 配置 -2. 创建 SpiderSubnet 实例。 +Spiderpool 为简化书写 JSON 格式的 Multus CNI 配置,它提供了 SpiderMultusConfig CR 来自动管理 Multus NetworkAttachmentDefinition CR。如下是创建 Macvlan SpiderMultusConfig 配置的示例: - Macvlan 是以宿主机 eth0 为父接口,因此,需要创建 eth0 底层的 Underlay 子网供 Pod 使用。 - 以下是创建相关的 SpiderSubnet 示例: +* 确认 Macvlan 所需的宿主机父接口,本例子以宿主机 eth0 网卡为例,从该网卡创建 Macvlan 子接口给 Pod 使用 ```shell + MACVLAN_MASTER_INTERFACE="eth0" cat < 更多 Spiderpool 注解的使用请参考 [Spiderpool 注解](https://spidernet-io.github.io/spiderpool/concepts/annotation/)。 - - * `v1.multus-cni.io/default-network`:该 annotation 指定了使用的 Multus 的 CNI 配置。 - > 更多 Multus 注解使用请参考 [Multus 注解](https://github.com/k8snetworkplumbingwg/multus-cni/blob/master/docs/quickstart.md)。 - 2. 查看 Pod 运行状态: ```bash @@ -213,17 +175,17 @@ Spiderpool 可用作 Underlay 网络场景下提供固定 IP 的一种解决方 test-app-f9f94688-8982v 1/1 Running 0 2m13s 172.18.30.138 ipv4-control-plane ``` -3. Spiderpool 自动为应用创建了 IP 固定池,应用的 IP 将会自动固定在该 IP 范围内: +3. 应用的 IP 将会固定在该 IP 范围内: ```bash ~# kubectl get spiderippool - NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE - auto-deployment-default-test-app-v4-a0ae75eb5d47 4 172.18.0.0/16 2 2 false + NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT + ippool-test 4 172.18.0.0/16 2 10 false ~# kubectl get spiderendpoints - NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE CREATETION TIME - test-app-f9f94688-2srj7 eth0 auto-deployment-default-test-app-v4-a0ae75eb5d47 172.18.30.139/16 ipv4-worker 3m5s - test-app-f9f94688-8982v eth0 auto-deployment-default-test-app-v4-a0ae75eb5d47 172.18.30.138/16 ipv4-control-plane 3m5s + NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE CREATETION TIME + test-app-f9f94688-2srj7 eth0 ippool-test 172.18.30.139/16 ipv4-worker 3m5s + test-app-f9f94688-8982v eth0 ippool-test 172.18.30.138/16 ipv4-control-plane 3m5s ``` 4. 测试 Pod 与 Pod 的通讯情况: diff --git a/docs/usage/install/underlay/get-started-macvlan.md b/docs/usage/install/underlay/get-started-macvlan.md index 8bc16a4255..052c6293e6 100644 --- a/docs/usage/install/underlay/get-started-macvlan.md +++ b/docs/usage/install/underlay/get-started-macvlan.md @@ -2,7 +2,7 @@ **English** | [**简体中文**](./get-started-macvlan-zh_CN.md) -Spiderpool provides a solution for assigning static IP addresses in underlay networks. In this page, we'll demonstrate how to build a complete underlay network solution using [Multus](https://github.com/k8snetworkplumbingwg/multus-cni), [Macvlan](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan), [Veth](https://github.com/spidernet-io/plugins), and [Spiderpool](https://github.com/spidernet-io/spiderpool), which meets the following kinds of requirements: +Spiderpool provides a solution for assigning static IP addresses in underlay networks. In this page, we'll demonstrate how to build a complete underlay network solution using [Multus](https://github.com/k8snetworkplumbingwg/multus-cni), [Macvlan](https://github.com/containernetworking/plugins/tree/main/plugins/main/macvlan) and [Spiderpool](https://github.com/spidernet-io/spiderpool), which meets the following kinds of requirements: * Applications can be assigned static Underlay IP addresses through simple operations. @@ -28,117 +28,89 @@ tar xvfzp ./cni-plugins-linux-amd64-v1.2.0.tgz -C /opt/cni/bin chmod +x /opt/cni/bin/macvlan ``` -## Install Veth - -[`Veth`](https://github.com/spidernet-io/plugins) is a CNI plugin designed to resolve the following issues in other CNIs like Macvlan and SR-IOV: - -* Enable clusterIP communication for Pods in Macvlan CNI environments - -* Facilitate connection between Pods and the host during health checks where Pods' Macvlan IPs are unable to communicate with the host - -* Address communication issues in multiple NICs for Pods by automatically coordinating policy routing between NICs - -Download and install the Veth binary on all nodes: - -```bash -wget https://github.com/spidernet-io/plugins/releases/download/v0.1.4/spider-plugins-linux-amd64-v0.1.4.tar -tar xvfzp ./spider-plugins-linux-amd64-v0.1.4.tar -C /opt/cni/bin -chmod +x /opt/cni/bin/veth -``` - -## Install Multus - -[`Multus`](https://github.com/k8snetworkplumbingwg/multus-cni) is a CNI plugin that allows Pods to have multiple NICs by scheduling third-party CNIs. The management of the Macvlan CNI configuration is simplified through the CRD-based approach provided by Multus, with nothing for manual editing of CNI configuration files on each host. - -1. Install Multus via the manifest: - - ```bash - kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/v3.9/deployments/multus-daemonset.yml - ``` +## Install Spiderpool -2. Confirm the operational status of Multus: +1. Install Spiderpool. ```bash - ~# kubectl get pods -A | grep -i multus - kube-system kube-multus-ds-hfzpl 1/1 Running 0 5m - kube-system kube-multus-ds-qm8j7 1/1 Running 0 5m + helm repo add spiderpool https://spidernet-io.github.io/spiderpool + helm repo update spiderpool + helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.defaultCniCRName="macvlan-conf" ``` - Verify the existence of the Multus configuration files `ls /etc/cni/net.d/00-multus.conf` on the node. - -3. Create a NetworkAttachmentDefinition for Macvlan. - - The following parameters need to be confirmed: - - * Verify the required host parent interface for Macvlan. In this case, a Macvlan sub-interface will be created for Pods from the host parent interface --eth0. + > If you are mainland user who is not available to access ghcr.io,You can specify the parameter `-set global.imageRegistryOverride=ghcr.m.daocloud.io` to avoid image pulling failures for Spiderpool. + > + > Specify the Multus clusterNetwork of the cluster through `multus.multusCNI.defaultCniCRName`, clusterNetwork is a specific field of the Multus plugin, which is used to specify the default network interface of the Pod. - * To implement clusterIP communication using Veth, confirm the service CIDR of the cluster through a query command `kubectl -n kube-system get configmap kubeadm-config -oyaml | grep service` or other methods. +2. Create a SpiderIPPool instance. - The following is the configuration for creating a NetworkAttachmentDefinition: + Create an IP Pool in the same subnet as the network interface `eth0` for Pods to use, the following is an example of creating a related SpiderIPPool: ```bash - MACLVAN_MASTER_INTERFACE="eth0" - SERVICE_CIDR="10.96.0.0/16" - cat < If you are mainland user who is not available to access ghcr.io,You can specify the parameter `-set global.imageRegistryOverride=ghcr.m.daocloud.io` to avoid image pulling failures for Spiderpool. +## Create CNI configuration -2. Create a SpiderSubnet instance. +To simplify writing Multus CNI configuration in JSON format, Spiderpool provides SpiderMultusConfig CR to automatically manage Multus NetworkAttachmentDefinition CR. Here is an example of creating a Macvlan SpiderMultusConfig configuration: - An Underlay subnet for eth0 needs to be created for Pods as Macvlan uses eth0 as the parent interface. - Here is an example of creating a SpiderSubnet instance:: +* Verify the required host parent interface for Macvlan. In this case, a Macvlan sub-interface will be created for Pods from the host parent interface --eth0. - ```bash + ```shell + MACVLAN_MASTER_INTERFACE="eth0" cat < For more information on Spiderpool annotations, refer to [Spiderpool Annotations](../../../reference/annotation.md). - - * `v1.multus-cni.io/default-network`:specifies the CNI configuration for Multus. - - > For more information on Multus annotations, refer to [Multus Quickstart](https://github.com/k8snetworkplumbingwg/multus-cni/blob/master/docs/quickstart.md). - 2. Check the status of Pods: ```bash @@ -214,13 +175,13 @@ chmod +x /opt/cni/bin/veth ```bash ~# kubectl get spiderippool - NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE - auto-deployment-default-test-app-v4-a0ae75eb5d47 4 172.18.0.0/16 2 2 false + NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT + ippool-test 4 172.18.0.0/16 2 10 false ~# kubectl get spiderendpoints - NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE CREATETION TIME - test-app-f9f94688-2srj7 eth0 auto-deployment-default-test-app-v4-a0ae75eb5d47 172.18.30.139/16 ipv4-worker 3m5s - test-app-f9f94688-8982v eth0 auto-deployment-default-test-app-v4-a0ae75eb5d47 172.18.30.138/16 ipv4-control-plane 3m5s + NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE CREATETION TIME + test-app-f9f94688-2srj7 eth0 ippool-test 172.18.30.139/16 ipv4-worker 3m5s + test-app-f9f94688-8982v eth0 ippool-test 172.18.30.138/16 ipv4-control-plane 3m5s ``` 4. Test the communication between Pods: diff --git a/docs/usage/install/underlay/get-started-ovs-zh_CN.md b/docs/usage/install/underlay/get-started-ovs-zh_CN.md index 7d07029fa2..0d5f045697 100644 --- a/docs/usage/install/underlay/get-started-ovs-zh_CN.md +++ b/docs/usage/install/underlay/get-started-ovs-zh_CN.md @@ -68,47 +68,6 @@ ec16d9e1-6187-4b21-9c2f-8b6cb75434b9 ovs_version: "2.17.3" ``` -## 安装 Multus - -[`Multus`](https://github.com/k8snetworkplumbingwg/multus-cni) 是一个 CNI 插件项目,它通过调度第三方 CNI 项目,能够实现为 Pod 接入多张网卡。并且 Multus 提供了 CRD 方式管理 Ovs-cni 的 CNI 配置,避免在每个主机上手动编辑 CNI 配置文件,能够降低运维工作量。 - -1. 通过 manifest 安装 Multus - - ```shell - ~# kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/v3.9/deployments/multus-daemonset.yml - ``` - -2. 为 Ovs-cni 创建 Multus 的 NetworkAttachmentDefinition 配置 - - 需要确认如下参数: - - * 确认 ovs-cni 所需的宿主机网桥,例如可基于命令 `ovs-vsctl show` 查询,本例子以宿主机的网桥:`br1` 为例 - -```bash -cat < 如果您是国内用户,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` 避免 Spiderpool 的镜像拉取失败。 + > 如果您是国内用户,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` 以帮助您快速的拉取镜像。 + > + > 通过 `multus.multusCNI.defaultCniCRName` 指定集群的 Multus clusterNetwork,clusterNetwork 是 Multus 插件的一个特定字段,用于指定 Pod 的默认网络接口。 -2. 创建 SpiderSubnet 实例。 +2. 创建 SpiderIPPool 实例。 - Pod 会从该子网中获取 IP,进行 Underlay 的网络通讯,所以该子网需要与接入的 Underlay 子网对应。 - - 以下是创建相关的 SpiderSubnet 示例: + Pod 会从该 IP 池中获取 IP,进行 Underlay 的网络通讯,所以该 IP 池的子网需要与接入的 Underlay 子网对应。以下是创建相关的 SpiderIPPool 示例: ```shell cat < ~# kubectl get spiderippool -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -auto-test-app-v4-eth0-9b208a961acd 4 172.18.0.0/16 2 2 false false +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +ippool-test 4 172.18.0.0/16 2 2 false false -~# kubectl get spiderendpoints -NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE -test-app-6f8dddd88d-hstg7 eth0 auto-test-app-v4-eth0-9b208a961acd 172.18.30.131/16 ipv4-worker -test-app-6f8dddd88d-rj7sm eth0 auto-test-app-v4-eth0-9b208a961acd 172.18.30.132/16 ipv4-control-plane +~# kubectl get spiderendpoints +NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE +test-app-6f8dddd88d-hstg7 eth0 ippool-test 172.18.30.131/16 ipv4-worker +test-app-6f8dddd88d-rj7sm eth0 ippool-test 172.18.30.132/16 ipv4-control-plane ``` 测试 Pod 与 Pod 的通讯情况,以跨节点 Pod 为例: diff --git a/docs/usage/install/underlay/get-started-ovs.md b/docs/usage/install/underlay/get-started-ovs.md index 51b46d117b..788f3fef6a 100644 --- a/docs/usage/install/underlay/get-started-ovs.md +++ b/docs/usage/install/underlay/get-started-ovs.md @@ -68,47 +68,6 @@ ec16d9e1-6187-4b21-9c2f-8b6cb75434b9 ovs_version: "2.17.3" ``` -## Install Multus - -[`Multus`](https://github.com/k8snetworkplumbingwg/multus-cni) is a CNI plugin that allows Pods to have multiple NICs by scheduling third-party CNIs. The management of the ovs-cni CNI configuration is simplified through the CRD-based approach provided by Multus, with nothing for manual editing of CNI configuration files on each host. - -1. Install Multus via the manifest: - - ```bash - kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/v3.9/deployments/multus-daemonset.yml - ``` - -2. Create a NetworkAttachmentDefinition for ovs-cni. - - The following parameters need to be confirmed: - - * Confirm the required host bridge for ovs-cni, for example based on the command `ovs-vsctl show`, this example takes the host bridge: `br1` as an example. - -```bash -cat < If you are mainland user who is not available to access ghcr.io,You can specify the parameter `-set global.imageRegistryOverride=ghcr.m.daocloud.io` to avoid image pulling failures for Spiderpool. + > + > Specify the Multus clusterNetwork of the cluster through `multus.multusCNI.defaultCniCRName`, clusterNetwork is a specific field of the Multus plugin, which is used to specify the default network interface of the Pod. -2. Create a SpiderSubnet instance. +2. Create a SpiderIPPool instance. - The Pod will obtain an IP address from this subnet for underlying network communication, so the subnet needs to correspond to the underlying subnet that is being accessed. + The Pod will obtain an IP address from the IPPool for underlying network communication, so the subnet of the IPPool needs to correspond to the underlying subnet being accessed. Here is an example of creating a SpiderSubnet instance: ```bash cat < ~# kubectl get spiderippool -NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE -auto-test-app-v4-eth0-9b208a961acd 4 172.18.0.0/16 2 2 false false +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +ippool-test 4 172.18.0.0/16 2 2 false false -~# kubectl get spiderendpoints -NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE -test-app-6f8dddd88d-hstg7 eth0 auto-test-app-v4-eth0-9b208a961acd 172.18.30.131/16 ipv4-worker -test-app-6f8dddd88d-rj7sm eth0 auto-test-app-v4-eth0-9b208a961acd 172.18.30.132/16 ipv4-control-plane +~# kubectl get spiderendpoints +NAME INTERFACE IPV4POOL IPV4 IPV6POOL IPV6 NODE +test-app-6f8dddd88d-hstg7 eth0 ippool-test 172.18.30.131/16 ipv4-worker +test-app-6f8dddd88d-rj7sm eth0 ippool-test 172.18.30.132/16 ipv4-control-plane ``` Testing Pod communication with cross-node Pods: diff --git a/docs/usage/install/underlay/get-started-weave-zh_CN.md b/docs/usage/install/underlay/get-started-weave-zh_CN.md index 451fcdd0fd..6268d8fe9a 100644 --- a/docs/usage/install/underlay/get-started-weave-zh_CN.md +++ b/docs/usage/install/underlay/get-started-weave-zh_CN.md @@ -29,22 +29,20 @@ ```shell helm repo add spiderpool https://spidernet-io.github.io/spiderpool - helm repo update spiderpool - helm install spiderpool spiderpool/spiderpool --namespace kube-system --set ipam.enableSpiderSubnet=true --set multus.multusCNI.install=false + helm repo update spiderpool + helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.install=false ``` - - > `ipam.enableSpiderSubnet=true`: SpiderPool 的 subnet 功能需要被打开。 - > + > 如果您是国内用户,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` 避免 Spiderpool 的镜像拉取失败。 - 等待 Pod Running, 创建 Pod 的子网(SpiderSubnet): + 等待 Pod Running, 创建 Pod 所使用的 IP 池: ```shell cat << EOF | kubectl apply -f - apiVersion: spiderpool.spidernet.io/v2beta1 - kind: SpiderSubnet + kind: SpiderIPPool metadata: - name: weave-subnet-v4 + name: weave-ippool-v4 labels: ipam.spidernet.io/subnet-cidr: 10-32-0-0-12 spec: @@ -54,18 +52,19 @@ EOF ``` - > `Weave` 使用 `10.32.0.0/12` 作为集群默认子网。所以这里需要创建一个相同子网的 SpiderSubnet + > `Weave` 使用 `10.32.0.0/12` 作为集群默认子网。所以需要创建一个相同子网内 SpiderIPPool。 3. 验证安装 ```shell [root@node1 ~]# kubectl get po -n kube-system | grep spiderpool - spiderpool-agent-lgdw7 1/1 Running 0 65s - spiderpool-agent-x974l 1/1 Running 0 65s - spiderpool-controller-9df44bc47-hbhbg 1/1 Running 0 65s - [root@node1 ~]# kubectl get ss + spiderpool-agent-7hhkz 1/1 Running 0 13m + spiderpool-agent-kxf27 1/1 Running 0 13m + spiderpool-controller-76798dbb68-xnktr 1/1 Running 0 13m + spiderpool-init 0/1 Completed 0 13m + [root@node1 ~]# kubectl get sp NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE - weave-subnet-v4 4 10.32.0.0/12 0 12901 false + weave-ippool-v4 4 10.32.0.0/12 0 12901 false ``` ## 切换 `Weave` 的 `IPAM` 为 `Spiderpool` @@ -133,7 +132,7 @@ ## 创建应用 -使用注解: `ipam.spidernet.io/subnet` 指定 Pod 从该 SpiderSubnet 中分配 IP: +使用注解: `ipam.spidernet.io/ippool` 指定 Pod 从该 SpiderIPPool 中分配 IP: ```shell [root@node1 ~]# cat << EOF | kubectl apply -f - @@ -149,7 +148,7 @@ template: metadata: annotations: - ipam.spidernet.io/subnet: '{"ipv4":["weave-subnet-v4"]}' + ipam.spidernet.io/ippool: '{"ipv4":["weave-ippool-v4"]}' labels: app: nginx spec: @@ -161,23 +160,19 @@ EOF ``` -> _spec.template.metadata.annotations.ipam.spidernet.io/subnet_:指定 Pod 从 SpiderSubnet: `weave-subnet-v4` 中分配 IP +> _spec.template.metadata.annotations.ipam.spidernet.io/ippool_:指定 Pod 从 SpiderIPPool: `weave-ippool-v4` 中分配 IP -Pod 成功创建, 并且从 Spiderpool Subnet 中分配 IP 地址: +Pod 成功创建, 并且从 Spiderpool 中分配 IP 地址: ```shell [root@node1 ~]# kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-5745d9b5d7-2rvn7 1/1 Running 0 8s 10.32.22.190 node1 nginx-5745d9b5d7-5ssck 1/1 Running 0 8s 10.32.35.87 node2 - ``` -Spiderpool 为该 Nginx 应用自动创建了一个 IP 池: `auto-deployment-default-nginx-v4-a0ae75eb5d47`, 池的 IP 数量为 2: - - ```shell [root@node1 ~]# kubectl get sp - NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE - auto-deployment-default-nginx-v4-a0ae75eb5d47 4 10.32.0.0/12 2 2 false + NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE + weave-ippool-v4 4 10.32.0.0/12 2 2 false ``` 测试连通性,以 Pod 跨节点通信为例: diff --git a/docs/usage/install/underlay/get-started-weave.md b/docs/usage/install/underlay/get-started-weave.md index 863dd89192..569fb5a257 100644 --- a/docs/usage/install/underlay/get-started-weave.md +++ b/docs/usage/install/underlay/get-started-weave.md @@ -30,21 +30,19 @@ ```shell helm repo add spiderpool https://spidernet-io.github.io/spiderpool helm repo update spiderpool - helm install spiderpool spiderpool/spiderpool --namespace kube-system --set ipam.enableSpiderSubnet=true --set multus.multusCNI.install=false + helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.install=false ``` - + > If you are mainland user who is not available to access ghcr.io,You can specify the parameter `-set global.imageRegistryOverride=ghcr.m.daocloud.io` to avoid image pulling failures for Spiderpool. - > - > "ipam.enableSpiderSubnet=true": SpiderPool's subnet feature needs to be enabled. - - Wait for Pod Running and create a subnet for Pod (SpiderSubnet): + + Wait for Pod Running and create the IPPool used by Pod: ```shell cat << EOF | kubectl apply -f - apiVersion: spiderpool.spidernet.io/v2beta1 - kind: SpiderSubnet + kind: SpiderIPPool metadata: - name: weave-subnet-v4 + name: weave-ippool-v4 labels: ipam.spidernet.io/subnet-cidr: 10-32-0-0-12 spec: @@ -54,19 +52,20 @@ EOF ``` - > `Weave` uses `10.32.0.0/12` as the cluster's default subnet, and thus a SpiderSubnet with the same subnet needs to be created in this case + > `Weave` uses `10.32.0.0/12` as the cluster's default subnet, and thus a SpiderIPPool with the same subnet needs to be created in this case. 3. Verify installation ```shell [root@node1 ~]# kubectl get po -n kube-system | grep spiderpool - spiderpool-agent-lgdw7 1/1 Running 0 65s - spiderpool-agent-x974l 1/1 Running 0 65s - spiderpool-controller-9df44bc47-hbhbg 1/1 Running 0 65s - [root@node1 ~]# kubectl get ss + spiderpool-agent-7hhkz 1/1 Running 0 13m + spiderpool-agent-kxf27 1/1 Running 0 13m + spiderpool-controller-76798dbb68-xnktr 1/1 Running 0 13m + spiderpool-init 0/1 Completed 0 13m + [root@node1 ~]# kubectl get sp NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE - weave-subnet-v4 4 10.32.0.0/12 0 12901 false - ``` + weave-ippool-v4 4 10.32.0.0/12 0 12901 false + ``` ## Switch `Weave`'s `IPAM` to Spiderpool @@ -135,7 +134,7 @@ cat <<< $(jq '.plugins[0].ipam.type = "spiderpool" ' /etc/cni/net.d/10-weave.con ## Create applications -Specify that the Pods will be allocated IPs from that SpiderSubnet via the annotation `ipam.spidernet.io/subnet`: +Specify that the Pods will be allocated IPs from that SpiderSubnet via the annotation `ipam.spidernet.io/ippool`: ```shell [root@node1 ~]# cat << EOF | kubectl apply -f - @@ -151,7 +150,7 @@ Specify that the Pods will be allocated IPs from that SpiderSubnet via the annot template: metadata: annotations: - ipam.spidernet.io/subnet: '{"ipv4":["weave-subnet-v4"]}' + ipam.spidernet.io/ippool: '{"ipv4":["weave-ippool-v4"]}' labels: app: nginx spec: @@ -163,7 +162,7 @@ Specify that the Pods will be allocated IPs from that SpiderSubnet via the annot EOF ``` -> _spec.template.metadata.annotations.ipam.spidernet.io/subnet_: specifies that the Pods will be assigned IPs from SpiderSubnet: `weave-subnet-v4`. +> _spec.template.metadata.annotations.ipam.spidernet.io/subnet_: specifies that the Pods will be assigned IPs from SpiderSubnet: `weave-ippool-v4`. The Pods have been created and allocated IP addresses from Spiderpool Subnets: @@ -172,14 +171,10 @@ The Pods have been created and allocated IP addresses from Spiderpool Subnets: NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-5745d9b5d7-2rvn7 1/1 Running 0 8s 10.32.22.190 node1 nginx-5745d9b5d7-5ssck 1/1 Running 0 8s 10.32.35.87 node2 - ``` - -Spiderpool has automatically created an IP pool for the Nginx application named `auto-deployment-default-nginx-v4-a0ae75eb5d47`, with a pool size of 2 IP addresses: - ```shell [root@node1 ~]# kubectl get sp - NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE - auto-deployment-default-nginx-v4-a0ae75eb5d47 4 10.32.0.0/12 2 2 false + NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DISABLE + weave-ippool-v4 4 10.32.0.0/12 2 2 false ``` To test connectivity, let's use inter-node communication between Pods as an example: diff --git a/docs/usage/ippool-affinity-namespace.md b/docs/usage/ippool-affinity-namespace.md index 6c1cb6279d..9a9e7d787b 100644 --- a/docs/usage/ippool-affinity-namespace.md +++ b/docs/usage/ippool-affinity-namespace.md @@ -2,11 +2,11 @@ *Spiderpool supports affinity between IP pools and Namespaces. It means only Pods running under these Namespaces can use the IP pools that have an affinity to these Namespaces.* ->*Namespace affinity should be regarded as a **filtering mechanism** rather than a [pool selection rule](TODO).* +> *Namespace affinity should be regarded as a **filtering mechanism** rather than a [pool selection rule](TODO).* ## Set up Spiderpool -If you have not deployed Spiderpool yet, follow the guide [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/install.md) for instructions on how to deploy and easily configure Spiderpool. +If you have not deployed Spiderpool yet, follow the guide [installation](./install/underlay/get-started-kind.md) for instructions on how to deploy and easily configure Spiderpool. ## Get started @@ -36,7 +36,7 @@ spec: kubernetes.io/metadata.name: test-ns ``` ->For convenience, this example uses a native Namespace label `kubernetes.io/metadata.name` as the matching condition of IPPool affinity. You can replace them with desired labels to match the corresponding Namespaces. +> For convenience, this example uses a native Namespace label `kubernetes.io/metadata.name` as the matching condition of IPPool affinity. You can replace them with desired labels to match the corresponding Namespaces. Next, create two Deployments under `test-ns` and `default` Namespaces respectively, and configure the Pods therein to get IP addresses from the IPPool above. @@ -74,7 +74,7 @@ Events: Obviously, this Pod has no permission to get IP addresses from IPPool `test-ns-ipv4-ippool`. ->You can specify a [default IP pool for a Namespace](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/ippool-namespace.md) and set the corresponding `namespaceAffinity` for the IPPool to achieve the effect of "a Namespace static IP pool". +> You can specify a [default IP pool for a Namespace](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/ippool-namespace.md) and set the corresponding `namespaceAffinity` for the IPPool to achieve the effect of "a Namespace static IP pool". ## Clean up diff --git a/docs/usage/ippool-affinity-node.md b/docs/usage/ippool-affinity-node.md index 58d8724062..c64c11eb59 100644 --- a/docs/usage/ippool-affinity-node.md +++ b/docs/usage/ippool-affinity-node.md @@ -2,11 +2,11 @@ *Spiderpool supports affinity between IP pools and Nodes. It means only Pods running on these Nodes can use the IP pools that have an affinity to these Nodes.* ->*Node affinity should be regarded as a **filtering mechanism** rather than a [pool selection rule](TODO).* +> *Node affinity should be regarded as a **filtering mechanism** rather than a [pool selection rule](TODO).* ## Set up Spiderpool -If you have not deployed Spiderpool yet, follow the guide [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/install.md) for instructions on how to deploy and easily configure Spiderpool. +If you have not deployed Spiderpool yet, follow the guide [installation](./install/underlay/get-started-kind.md) for instructions on how to deploy and easily configure Spiderpool. ## Get started @@ -74,7 +74,7 @@ spec: app: node-affinity-deploy template: metadata: - annotations: + annotations: ipam.spidernet.io/ippool: |- { "ipv4": ["master-ipv4-ippool", "worker-ipv4-ippool"] diff --git a/docs/usage/ippool-affinity-pod.md b/docs/usage/ippool-affinity-pod.md index f9ad28dec9..3440796b45 100644 --- a/docs/usage/ippool-affinity-pod.md +++ b/docs/usage/ippool-affinity-pod.md @@ -13,26 +13,7 @@ The example shows how `sepc.podAffinity` works. ### Set up Spiderpool -Follow the [installation guide](./install/install.md) to install Spiderpool. - -### Create SpiderSubnet - -Create a subnet to allocate IP addresses for the IPPool, from which both the Shared IPPool and the Occupied IPPool will receive their IP addresses. - -```bash -kubectl apply -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/static-ipv4-subnet.yaml -``` - -```yaml -apiVersion: spiderpool.spidernet.io/v2beta1 -kind: SpiderSubnet -metadata: - name: static-ipv4-subnet -spec: - subnet: 172.18.41.0/24 - ips: - - 172.18.41.40-172.18.41.47 -``` +Follow the [installation guide](./install/underlay/get-started-kind.md) to install Spiderpool. ### Shared IPPool @@ -215,7 +196,6 @@ kubectl delete \ -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/occupied-static-ippool-deploy.yaml \ -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/wrong-static-ippool-deploy.yaml \ -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/occupied-static-ipv4-ippool.yaml \ --f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/static-ipv4-subnet.yaml \ -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/shared-static-ippool-deploy.yaml \ -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/shared-static-ipv4-ippool.yaml \ --ignore-not-found=true diff --git a/docs/usage/ippool-multi.md b/docs/usage/ippool-multi.md index 8c2571946c..204356afc8 100644 --- a/docs/usage/ippool-multi.md +++ b/docs/usage/ippool-multi.md @@ -6,7 +6,7 @@ Multiple IP pools can be set for a Pod for the usage of backup IP resources. ### Set up Spiderpool -Follow the guide [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/install.md) to install Spiderpool. +Follow the guide [installation](./install/underlay/get-started-kind.md) to install Spiderpool. ### Backup IPPool effect diff --git a/docs/usage/ippool-namespace.md b/docs/usage/ippool-namespace.md index ee059829d5..eeb8a15b21 100644 --- a/docs/usage/ippool-namespace.md +++ b/docs/usage/ippool-namespace.md @@ -4,7 +4,7 @@ ## Set up Spiderpool -If you have not deployed Spiderpool yet, follow the guide [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/install.md) for instructions on how to deploy and easily configure Spiderpool. +If you have not deployed Spiderpool yet, follow the guide [installation](./install/underlay/get-started-kind.md) for instructions on how to deploy and easily configure Spiderpool. ## Get started diff --git a/docs/usage/ipv6.md b/docs/usage/ipv6.md index 65a7b5cf4d..63b3ac8104 100644 --- a/docs/usage/ipv6.md +++ b/docs/usage/ipv6.md @@ -20,7 +20,7 @@ Spiderpool supports: ### Set up Spiderpool -follow the guide [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/install.md) to install Spiderpool. +follow the guide [installation](./install/underlay/get-started-kind.md) to install Spiderpool. ### Create SpiderSubnet diff --git a/docs/usage/multi-interfaces-annotation.md b/docs/usage/multi-interfaces-annotation.md index 47f9a66326..da18f246d6 100644 --- a/docs/usage/multi-interfaces-annotation.md +++ b/docs/usage/multi-interfaces-annotation.md @@ -11,7 +11,7 @@ Then run a Pod with two NICs with IP in different subnets. ### Set up Spiderpool -Follow the guide [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/get-started-macvlan.md) to install Spiderpool. +Follow the guide [installation](./install/underlay/get-started-kind.md) to install Spiderpool. ### Set up Multus Configuration diff --git a/docs/usage/network-topology-zh_CN.md b/docs/usage/network-topology-zh_CN.md index e69de29bb2..f78967c085 100644 --- a/docs/usage/network-topology-zh_CN.md +++ b/docs/usage/network-topology-zh_CN.md @@ -0,0 +1,217 @@ +# 基于跨越网络区域的 IP 分配 + +**简体中文** | [**English**](./network-topology.md) + +## 介绍 + +随着数据中心私有云的不断普及,Underlay 网络作为数据中心网络架构的重要组成部分,已经被广泛应用于数据中心的网络架构中,以提供更高效的网络传输和更好的网络拓扑管理能力。由于具有低延迟、可靠、安全等特性,Underlay 在下列场景中得到广泛的应用: + +- 延时敏感的应用:某些特定行业或应用(如金融交易、实时视频传输等)对网络延迟非常敏感。在这种情况下,Underlay 网络可以提供更低的延迟,通过直接控制物理和链路层的连接来减少数据传输的时间。这种低延迟的特性使得 Underlay 网络成为满足这些应用需求的理想选择。 + +- 防火墙安全管控:在集群中,防火墙通常用于管理南北向通信,即集群内部和外部网络之间的通信。为了实现安全管控,防火墙需要对通信流量进行检查和过滤,并对出口通信进行限制。在这种情况下,通过 Underlay 网络的 IPAM 对应用固定出口 IP 地址,可以更好地管理和控制集群与外部网络之间的通信,提高网络的安全性。 + +在 Underlay 网络的集群,当它的节点分布在不同地区或数据中心,而一些节点的区域只能使用特定子网时,将对 IP 地址管理(IPAM)带来挑战,本文将介绍一种能实现跨越网络区域的 IP 分配的完整的 Underlay 网络解决方案。 + +![network-topology](../images/ip-allocation-across-networks-1.png) + +## 项目功能 + +Spiderpool 提供了节点拓扑的功能,能够帮助解决跨越网络区域的 IP 分配问题,它的实现原理如下。 + +- 一个集群,但集群的节点分布在不同地区或数据中心,一些节点的区域只能使用子网 10.6.1.0/24,一些节点的区域只能使用子网 172.16.2.0/24。 + +在上诉的场景下,当一个应用跨子网部署副本时,要求 IPAM 能够在不同的节点上,为同一个应用下的不同 Pod 分配出与子网匹配的 IP 地址,Spiderpool 的 CR:`SpiderIPPool` 提供了 nodeName 字段,实现 IP 池与节点之间的亲和性,让 Pod 被调度到某一节点时,能从节点所在的 Underlay 子网中获得 IP 地址,实现节点拓扑的功能, + +## 实施要求 + +1. 已安装 [Helm](https://helm.sh/docs/intro/install/)。 + +## 步骤 + +### 跨越网络区域的集群 + +准备一套跨越网络区域的集群,如节点 1 使用 `10.6.0.0/16`,节点 2 使用 `10.7.0.0/16` 子网,以下是所使用的集群信息以及网络拓扑图: + +```bash +~# kubectl get nodes -owide +NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP +controller-node-1 Ready control-plane 1h v1.25.3 10.6.168.71 +worker-node-1 Ready 1h v1.25.3 10.7.168.73 +``` + +![network-topology](../images/ip-allocation-across-networks-2.png) + +### 安装 Spiderpool + +- 通过 helm 安装 Spiderpool。 + +```bash +helm repo add spiderpool https://spidernet-io.github.io/spiderpool + +helm repo update spiderpool + +helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.defaultCniCRName="macvlan-conf" +``` + +> 如果您使用的是中国大陆的云厂商服务器,可以指定参数 `--set global.imageRegistryOverride=ghcr.m.daocloud.io` ,以帮助您更快的拉取镜像。 +> +> 通过 `multus.multusCNI.defaultCniCRName` 指定集群的 Multus clusterNetwork,clusterNetwork 是 Multus 插件的一个特定字段,用于指定 Pod 的默认网络接口。 + +- 检查安装完成 + +```bash +~# kubectll get po -n kube-sysem | grep spiderpool +NAME READY STATUS RESTARTS AGE +spiderpool-agent-7hhkz 1/1 Running 0 13m +spiderpool-agent-kxf27 1/1 Running 0 13m +spiderpool-controller-76798dbb68-xnktr 1/1 Running 0 13m +spiderpool-init 0/1 Completed 0 13m +spiderpool-multus-7vkm2 1/1 Running 0 13m +spiderpool-multus-rwzjn 1/1 Running 0 13m +``` + +### 安装 CNI 配置 + +Spiderpool 为简化书写 JSON 格式的 Multus CNI 配置,它提供了 SpiderMultusConfig CR 来自动管理 Multus NetworkAttachmentDefinition CR。如下是创建 IPvlan SpiderMultusConfig 配置的示例: + +- master:在此示例用接口 `eth0` 作为 master 的参数,此参数应与集群跨越网络区的节点上的接口名称匹配。 + +```shell +MACVLAN_MASTER_INTERFACE="eth0" +MACVLAN_MULTUS_NAME="macvlan-conf" + +cat < +test-app-nkq5h 1/1 Running 0 45s 10.7.168.61 worker-node-1 + +~# kubectl get spiderippool +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +test-ippool-6 4 10.6.0.0/16 1 10 false false +test-ippool-7 4 10.7.0.0/16 1 10 false false +``` + +跨网络区域的 Pod 与 Pod 之间的通讯情况 + +```bash +~# kubectl exec -ti test-app-j9ftl -- ping 10.7.168.61 -c 2 + +PING 10.7.168.61 (10.7.168.61) 56(84) bytes of data. +64 bytes from 10.7.168.61: icmp_seq=1 ttl=63 time=1.06 ms +64 bytes from 10.7.168.61: icmp_seq=2 ttl=63 time=0.515 ms + +--- 10.7.168.61 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1002ms +rtt min/avg/max/mdev = 0.515/0.789/1.063/0.274 ms +``` + +## 总结 + +不同网络区域的 Pod 能够正常通信,Spiderpool 可以很好的实现基于跨越网络区域的 IP 分配需求。 diff --git a/docs/usage/network-topology.md b/docs/usage/network-topology.md index b9e93e0fc3..5d979ca904 100644 --- a/docs/usage/network-topology.md +++ b/docs/usage/network-topology.md @@ -1,83 +1,222 @@ -# 基于节点网络区域的IP分配 +# Based on IP allocation across network zones -对于一些基础设施有特殊需求的用户,例如集群的节点是跨网段一个节点对应一个子网的场景,我们的SpiderPool也可以轻松应对。 +**English** | [**简体中文**](./network-topology-zh_CN.md) -![network-topology](../images/network-topology.png) +## Introduce -## Spiderpool相关功能介绍 +The rising popularity of private cloud data centers has made underlay networks essential components of data center network architecture by offering efficient network transmission and improved network topology management capabilities. Underlay is widely used in the following scenarios due to its low latency, reliability, and security: -### 多池备选 +- Latency-sensitive applications: applications in specific industries, such as financial trading and real-time video transmission, are highly sensitive to network latency. Underlay networks directly control physical and link-layer connections to reduce data transmission time, providing an ideal solution for these applications. -spiderpool在分配IP的时候,可支持多池备选功能,一个Pod不仅仅只能从某个具体的IPPool中分配出一个IP。该功能设计的意义是当使用某个池来为一组Pod分配IP时,若第一个IPPool的IP不够分,那么可顺序的从后续的备选IPPool中分出IP。 +- Firewall security control and management: firewalls are often used to manage north-south traffic, namely communication between internal and external networks, by checking, filtering, and restricting communication traffic. IP address management (IPAM) solutions of underlay networks that allocate fixed egress IP addresses for applications can provide better communication management and control between the cluster and external networks, further enhancing overall network security. -+ 使用annotation来指定IPPools,可给Pod打上 `ipam.spidernet.io/ippool` 或 `ipam.spidernet.io/ippools` 的annotation来指定IPPool,详情可见 [Pod Annotation](../reference/annotation.md) +In the cluster of the Underlay network, when its nodes are distributed in different regions or data centers, and some node regions can only use specific subnets, it will bring challenges to IP address management (IPAM). This article will introduce a method that can realize A complete underlay network solution for IP allocation across network regions. -+ 使用CNI配置文件来指定IPPools,可在 `default_ipv4_ippool` 和 `default_ipv6_ippool` 中设置期望使用的IPPools,详情可见 [configuration](../reference/plugin-ipam.md) +![network-topology](../images/ip-allocation-across-networks-1.png) -+ 设置缺省IPPool, 可给 SpiderIPPool CR实例设置 `default`来指定一系列的缺省IP池,详情可见SpiderIPPool的CRD定义 [SpiderIPPool](../reference/crd-spiderippool.md) +## Project Functions -### IPPool亲和性设置 +Spiderpool provides the function of node topology, which can help solve the problem of IP allocation across network regions. Its implementation principle is as follows. -一个IP池可以根据亲和性绑定给某个Node,这意味着当一个Pod指定使用多个拥有nodeAffinity的IP池的时候,spiderpool只会使用与Pod当前所在节点亲和的IP池来分配IP。 详情可见 [IPPool-NodeAffinity](../usage/ippool-affinity-node.md) +- A cluster, but the nodes of the cluster are distributed in different regions or data centers, some nodes' regions can only use the subnet 10.6.1.0/24, and some nodes' regions can only use the subnet 172.16.2.0/24. -## 场景示例 +In the appeal scenario, when an application deploys copies across subnets, IPAM is required to assign IP addresses that match the subnet to different Pods under the same application on different nodes. Spiderpool's CR: `SpiderIPPool` The nodeName field is provided to realize the affinity between the IP pool and the node, so that when the Pod is scheduled to a certain node, it can obtain the IP address from the Underlay subnet where the node is located, and realize the node topology function. -例如在IPv4的单栈集群中拥有两个节点分别名为master和worker,并且限制每个节点仅仅只能使用对应的IPPool(pool-master,pool-worker)。在此场景下,可使用以上 "多池备选" 篇章中介绍的3种方案实现。 +## Implementation Requirements -第一步,先给Node以及对应的IPPool设置亲和绑定来强制限定某些池仅能使用于哪些节点。 +1. Installed [Helm](https://helm.sh/docs/intro/install/). -第二步,选择一个方案来指定多池备选。 +## Steps -+ 例如给Pod指定Annotation +### Clusters spanning network regions -```text -ipam.spidernet.io/ippool: |- - { - "ipv4": ["pool-master", "pool-worker"], - } +Prepare a set of clusters that span the network area. For example, node 1 uses `10.6.0.0/16` and node 2 uses `10.7.0.0/16` subnet. The following is the cluster information and network topology used: + +```bash +~# kubectl get nodes -owide +NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP +controller-node-1 Ready control-plane 1h v1.25.3 10.6.168.71 +worker-node-1 Ready 1h v1.25.3 10.7.168.73 + +~# kubectl get nodes --show-labels +NAME STATUS ROLES AGE VERSION LABELS +controller-node-1 Ready control-plane,master 1h v1.25.3 node-subnet=subnet-6, ... +worker-node-1 Ready 1h v1.25.3 node-subnet=subnet-7, ... +``` + +![network-topology](../images/ip-allocation-across-networks-2.png) + +### Install Spiderpool + +Install Spiderpool via helm. + +```bash +helm repo add spiderpool https://spidernet-io.github.io/spiderpool + +helm repo update spiderpool + +helm install spiderpool spiderpool/spiderpool --namespace kube-system --set multus.multusCNI.defaultCniCRName="macvlan-conf" ``` -+ 例如设置好CNI配置文件,此场景下就无需为Pod打上Annotation - -```text -{ - "cniVersion": "0.3.1", - "name": "mynet", - "type": "macvlan", - "master": "eth0", - "ipam":{ - "type":"spiderpool", - "default_ipv4_ippool": ["pool-master","pool-worker"], - } -} +> If you are mainland user who is not available to access ghcr.io,You can specify the parameter `-set global.imageRegistryOverride=ghcr.m.daocloud.io` to avoid image pulling failures for Spiderpool. +> +> Specify the Multus clusterNetwork of the cluster through `multus.multusCNI.defaultCniCRName`, clusterNetwork is a specific field of the Multus plugin, which is used to specify the default network interface of the Pod. + +Verify the installation: + +```bash +~# kubectll get po -n kube-sysem | grep spiderpool +NAME READY STATUS RESTARTS AGE +spiderpool-agent-7hhkz 1/1 Running 0 13m +spiderpool-agent-kxf27 1/1 Running 0 13m +spiderpool-controller-76798dbb68-xnktr 1/1 Running 0 13m +spiderpool-init 0/1 Completed 0 13m +spiderpool-multus-7vkm2 1/1 Running 0 13m +spiderpool-multus-rwzjn 1/1 Running 0 13m ``` -+ 例如给IPPool的CR实例设置default字段作为缺省池使用,此场景下就无需为Pod打上Annotation或者去修改CNI配置文件 +### Install CNI configuration + +To simplify writing Multus CNI configuration in JSON format, Spiderpool provides SpiderMultusConfig CR to automatically manage Multus NetworkAttachmentDefinition CR. Here is an example of creating an IPvlan SpiderMultusConfig configuration: + +- master: In this example the interface `eth0` is used as the parameter for master, this parameter should match the interface name on the nodes where the cluster spans network zones. + +```shell +MACVLAN_MASTER_INTERFACE="eth0" +MACVLAN_MULTUS_NAME="macvlan-conf" -```text +cat < +test-app-nkq5h 1/1 Running 0 45s 10.7.168.61 worker-node-1 + +~# kubectl get spiderippool +NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT DISABLE +test-ippool-6 4 10.6.0.0/16 1 10 false false +test-ippool-7 4 10.7.0.0/16 1 10 false false +``` + +Communication between Pods across network zones: + +```bash +~# kubectl exec -ti test-app-j9ftl -- ping 10.7.168.61 -c 2 + +PING 10.7.168.61 (10.7.168.61) 56(84) bytes of data. +64 bytes from 10.7.168.61: icmp_seq=1 ttl=63 time=1.06 ms +64 bytes from 10.7.168.61: icmp_seq=2 ttl=63 time=0.515 ms + +--- 10.7.168.61 ping statistics --- +2 packets transmitted, 2 received, 0% packet loss, time 1002ms +rtt min/avg/max/mdev = 0.515/0.789/1.063/0.274 ms +``` + +## Summarize + +Pods in different network areas can communicate normally, and Spiderpool can well meet the IP allocation requirements based on cross-network areas. diff --git a/docs/usage/reserved-ip.md b/docs/usage/reserved-ip.md index 7105cb93b9..c9cfacdc04 100644 --- a/docs/usage/reserved-ip.md +++ b/docs/usage/reserved-ip.md @@ -117,7 +117,7 @@ After a while, only one of these Pods using IP `172.18.42.50` can run successful ```bash kubectl get po -l app=reservedip-deploy -o wide -NAME READY STATUS RESTARTS AGE IP NODE +NAME READY STATUS RESTARTS AGE IP NODE reservedip-deploy-6cf9858886-cm7bp 0/1 ContainerCreating 0 35s spider-worker reservedip-deploy-6cf9858886-lb7cr 0/1 ContainerCreating 0 35s spider-worker reservedip-deploy-6cf9858886-pkcfl 1/1 Running 0 35s 172.18.42.50 spider-worker diff --git a/docs/usage/route.md b/docs/usage/route.md index 3e84ccd5f6..8aad8228df 100644 --- a/docs/usage/route.md +++ b/docs/usage/route.md @@ -8,7 +8,7 @@ Spiderpool supports the configuration of routing information. ### Set up Spiderpool -follow the guide [installation](./install/underlay/get-started-macvlan.md) to install Spiderpool. +follow the guide [installation](./install/underlay/get-started-kind.md) to install Spiderpool. ### Create Subnet @@ -102,8 +102,8 @@ After the created Pod has obtained an IP from the automatic IPPool, the route se ```bash ~# kubectl exec -it route-test-app-bdc84f8f5-2bxbr -- ip r -172.18.41.0/24 dev eth0 scope link src 172.18.41.41 -172.18.42.0/24 via 172.18.41.1 dev eth0 +172.18.41.0/24 dev eth0 scope link src 172.18.41.41 +172.18.42.0/24 via 172.18.41.1 dev eth0 ``` ### Create IPPool @@ -130,7 +130,7 @@ spec: ### Create Deployment By IPPool -Create a Deployment whose Pods sets the Pod annotation `ipam.spidernet.io/ippool` to explicitly specify the IPPool. +Create a Deployment whose Pods sets the Pod annotation `ipam.spidernet.io/ippool` to explicitly specify the IPPool. ```bash kubectl apply -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/ippool-route-deploy.yaml @@ -175,19 +175,19 @@ After the created Pod has obtained an IP from IPPool, the route set in IPPool is ```bash ~# kubectl exec -it ippool-test-app-66fd47d895-pthx5 -- ip r -172.18.41.0/24 dev eth0 scope link src 172.18.41.53 -172.18.42.0/24 via 172.18.41.1 dev eth0 +172.18.41.0/24 dev eth0 scope link src 172.18.41.53 +172.18.42.0/24 via 172.18.41.1 dev eth0 ``` ### Clean up Clean the relevant resources so that you can run this tutorial again - ```bash - kubectl delete \ - -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/subnet-route.yaml \ - -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/subnet-route-deploy.yaml \ - -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/ippool-route.yaml \ - -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/ippool-route-deploy.yaml \ - --ignore-not-found=true - ``` +```bash +kubectl delete \ +-f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/subnet-route.yaml \ +-f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/subnet-route-deploy.yaml \ +-f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/ippool-route.yaml \ +-f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/route/ippool-route-deploy.yaml \ +--ignore-not-found=true +``` diff --git a/docs/usage/spider-subnet.md b/docs/usage/spider-subnet.md index 2dcc8d4033..d411a74511 100644 --- a/docs/usage/spider-subnet.md +++ b/docs/usage/spider-subnet.md @@ -4,12 +4,12 @@ The Spiderpool owns a CRD SpiderSubnet, which can help applications (such as Dep Here are some annotations that you should write down on the application template Pod annotation: -| Annotation | Description | Example | -|------------------------------------|------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| Annotation | Description | Example | +| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | ipam.spidernet.io/subnet | Choose one SpiderSubnet V4 and V6 CR to use | {"interface":"eth0", "ipv4":["subnet-demo-v4"], "ipv6":["subnet-demo-v6"]} | -| ipam.spidernet.io/subnets | Choose multiple SpiderSubnet V4 and V6 CR to use (the current version only supports to use the first one) | [{"interface":"eth0", "ipv4":["v4-subnet1"], "ipv6":["v6-subnet1"]}] | -| ipam.spidernet.io/ippool-ip-number | The IP numbers of the corresponding SpiderIPPool (fixed and flexible mode, optional and default '+1') | +2 | -| ipam.spidernet.io/ippool-reclaim | Specify the corresponding SpiderIPPool to delete or not once the application was deleted (optional and default 'true') | true | +| ipam.spidernet.io/subnets | Choose multiple SpiderSubnet V4 and V6 CR to use (the current version only supports to use the first one) | [{"interface":"eth0", "ipv4":["v4-subnet1"], "ipv6":["v6-subnet1"]}] | +| ipam.spidernet.io/ippool-ip-number | The IP numbers of the corresponding SpiderIPPool (fixed and flexible mode, optional and default '+1') | +2 | +| ipam.spidernet.io/ippool-reclaim | Specify the corresponding SpiderIPPool to delete or not once the application was deleted (optional and default 'true') | true | ## Notice @@ -29,7 +29,7 @@ Here are some annotations that you should write down on the application template ### Enable SpiderSubnet feature -Firstly, please ensure you have installed the Spiderpool and configure the CNI file, refer to [install](./install/install.md) for details. +Firstly, please ensure you have installed the Spiderpool and configure the CNI file, refer to [install](./install/underlay/get-started-kind.md) for details. Check configmap `spiderpool-conf` property `enableSpiderSubnet` whether is already set to `true` or not. @@ -114,7 +114,7 @@ status: allocatedIPs: '{"172.16.41.1":{"interface":"eth0","pod":"default/demo-deploy-subnet-778786474b-kls7s","podUid":"cc310a87-8c5a-4bff-9a84-0c4975bd5921"}}' totalIPCount: 3 -$ kubectl get po -o wide +$ kubectl get po -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES demo-deploy-subnet-778786474b-kls7s 1/1 Running 0 3m10s 172.16.41.1 spider-worker ``` @@ -203,7 +203,7 @@ Make sure the interface name and use `ipam.spidernet.io/subnets` annotation just annotations: k8s.v1.cni.cncf.io/networks: kube-system/macvlan-cni2 ipam.spidernet.io/subnets: |- - [{"interface": "eth0", "ipv4": ["subnet-demo-v4-1"], "ipv6": ["subnet-demo-v6-1"]}, + [{"interface": "eth0", "ipv4": ["subnet-demo-v4-1"], "ipv6": ["subnet-demo-v6-1"]}, {"interface": "net2", "ipv4": ["subnet-demo-v4-2"], "ipv6": ["subnet-demo-v6-2"]}] ``` diff --git a/docs/usage/third-party-controller.md b/docs/usage/third-party-controller.md index c44b8f426b..c61cc0a931 100644 --- a/docs/usage/third-party-controller.md +++ b/docs/usage/third-party-controller.md @@ -31,7 +31,7 @@ It will use [OpenKruise](https://openkruise.io/zh/docs/) to demonstrate how Spid ### Set up Spiderpool -See [installation](https://github.com/spidernet-io/spiderpool/blob/main/docs/usage/install.md) for more details. +See [installation](./install/underlay/get-started-kind.md) for more details. ### Set up OpenKruise diff --git a/test/Makefile.defs b/test/Makefile.defs index 8db731d78e..afbd4910c4 100644 --- a/test/Makefile.defs +++ b/test/Makefile.defs @@ -66,7 +66,7 @@ E2E_TIMEOUT ?= 60m E2E_GINKGO_PROCS ?= 4 -E2E_SPIDERPOOL_ENABLE_SUBNET ?= true +E2E_SPIDERPOOL_ENABLE_SUBNET ?= false # consistent with open source, closed by default E2E_SPIDERPOOL_ENABLE_COORDINATOR ?= true E2E_SPIDERPOOL_ENABLE_MULTUSCONFIG ?= true