SpiderSubnet
简体中文 | English
介绍
SpiderSubnet 资源代表 IP 地址的集合,当需要为应用分配固定的 IP 地址时,应用管理员需要平台管理员告知可用的 IP 地址和路由属性等,但双方分属两个不同的运营部门,这使得每一个应用创建的工作流程繁琐,借助于 Spiderpool 的 SpiderSubnet 功能,它能自动从中子网分配 IP 给 SpiderIPPool,并且还能为应用固定 IP 地址,极大的减少了运维的成本。
SpiderSubnet 功能
启用 Subnet 功能时,每一个 IPPool 实例都归属于子网号相同的 Subnet 实例,IPPool 实例中的 IP 地址必须是 Subnet 实例中 IP 地址的子集,IPPool 实例之间不出现重叠 IP 地址,创建 IPPool 实例时的各种路由属性,默认继承 Subnet 实例中的设置。
在为应用分配固定的 IP 地址时,带来了如下两种实践手段,从而完成应用管理员和网络管理员的职责解耦:
-
手动创建 IPPool : 应用管理员手动创建 IPPool 实例时,可基于对应的 Subnet 实例中的 IP 地址约束,来获知可使用哪些 IP 地址。
-
自动创建 IPPool : 应用管理员可在 Pod annotation 中注明使用的 Subnet 实例名,在应用创建时,Spiderpool 会自动根据 Subnet 实例中的可用 IP 地址来创建固定 IP 的 IPPool 实例,从中分配 IP 地址给 Pod。并且 Spiderpool 能够自动监控应用的扩缩容和删除事件,自动完成 IPPool 中的 IP 地址扩缩容和删除。
SpiderSubnet 功能还支持众多的控制器,如:ReplicaSet、Deployment、Statefulset、Daemonset、Job、Cronjob,第三方控制器等。对于第三方控制器,您可以参考示例。
该功能并不支持自主式 Pod。
注意:在 v0.7.0 版本之前,在启动 SpiderSubnet 功能下你必须得先创建一个 SpiderSubnet 资源才可以创建 SpiderIPPool 资源。在v0.7.0版本开始,支持创建一个独立的 SpiderIPPool 资源而不依赖于 SpiderSubnet 资源。
实施要求
-
一套 Kubernetes 集群。
-
已安装 Helm。
步骤
安装 Spiderpool
可参考 安装 安装 Spiderpool. 其中,务必确保 helm 安装选项 ipam.enableSpiderSubnet=true
安装 CNI 配置
Spiderpool 为简化书写 JSON 格式的 Multus CNI 配置,它提供了 SpiderMultusConfig CR 来自动管理 Multus NetworkAttachmentDefinition CR。如下是创建 Macvlan SpiderMultusConfig 配置的示例:
- master:在此示例用接口
ens192
和ens224
作为 master 的参数。
MACVLAN_MASTER_INTERFACE0="ens192"
MACVLAN_MULTUS_NAME0="macvlan-$MACVLAN_MASTER_INTERFACE0"
MACVLAN_MASTER_INTERFACE1="ens224"
MACVLAN_MULTUS_NAME1="macvlan-$MACVLAN_MASTER_INTERFACE1"
cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
name: ${MACVLAN_MULTUS_NAME0}
namespace: kube-system
spec:
cniType: macvlan
enableCoordinator: true
macvlan:
master:
- ${MACVLAN_MASTER_INTERFACE0}
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
name: ${MACVLAN_MULTUS_NAME1}
namespace: kube-system
spec:
cniType: macvlan
enableCoordinator: true
macvlan:
master:
- ${MACVLAN_MASTER_INTERFACE1}
EOF
在本文示例中,使用如上配置,创建如下的两个 Macvlan SpiderMultusConfig,将基于它们自动生成的 Multus NetworkAttachmentDefinition CR,它对应了宿主机的 ens192
与 ens224
网卡。
~# kubectl get spidermultusconfigs.spiderpool.spidernet.io -n kube-system
NAME AGE
macvlan-ens192 26m
macvlan-ens224 26m
~# kubectl get network-attachment-definitions.k8s.cni.cncf.io -n kube-system
NAME AGE
macvlan-ens192 27m
macvlan-ens224 27m
创建 Subnet
~# cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderSubnet
metadata:
name: subnet-6
spec:
subnet: 10.6.0.0/16
gateway: 10.6.0.1
ips:
- 10.6.168.101-10.6.168.110
routes:
- dst: 10.7.0.0/16
gw: 10.6.0.1
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderSubnet
metadata:
name: subnet-7
spec:
subnet: 10.7.0.0/16
gateway: 10.7.0.1
ips:
- 10.7.168.101-10.7.168.110
routes:
- dst: 10.6.0.0/16
gw: 10.7.0.1
EOF
使用如上的 Yaml,创建 2 个 SpiderSubnet,并分别为其配置网关与路由信息。
~# kubectl get spidersubnet
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT
subnet-6 4 10.6.0.0/16 0 10
subnet-7 4 10.7.0.0/16 0 10
~# kubectl get spidersubnet subnet-6 -o jsonpath='{.spec}' | jq
{
"gateway": "10.6.0.1",
"ipVersion": 4,
"ips": [
"10.6.168.101-10.6.168.110"
],
"routes": [
{
"dst": "10.7.0.0/16",
"gw": "10.6.0.1"
}
],
"subnet": "10.6.0.0/16",
"vlan": 0
}
~# kubectl get spidersubnet subnet-7 -o jsonpath='{.spec}' | jq
{
"gateway": "10.7.0.1",
"ipVersion": 4,
"ips": [
"10.7.168.101-10.7.168.110"
],
"routes": [
{
"dst": "10.6.0.0/16",
"gw": "10.7.0.1"
}
],
"subnet": "10.7.0.0/16",
"vlan": 0
}
自动固定单网卡 IP
以下的示例 Yaml 中, 会创建 2 个副本的 Deployment 应用 ,其中:
-
ipam.spidernet.io/subnet
:用于指定 Spiderpool 的子网,Spiderpool 会自动在该子网中随机选择一些 IP 来创建固定 IP 池,与本应用绑定,实现 IP 固定的效果。在本示例中该注解会为 Pod 创建 1 个对应子网的固定 IP 池。 -
ipam.spidernet.io/ippool-ip-number
:用于指定创建 IP 池 中 的 IP 数量。该 annotation 的写法支持两种方式:一种是数字的方式指定 IP 池的固定数量,例如ipam.spidernet.io/ippool-ip-number:1
;另一种方式是使用加号和数字指定 IP 池的相对数量,例如ipam.spidernet.io/ippool-ip-number:+1
,即表示 IP 池中的数量会自动实时保持在应用的副本数的基础上多 1 个 IP,以解决应用在弹性扩缩容的时有临时的 IP 可用。 -
ipam.spidernet.io/ippool-reclaim
: 其表示自动创建的固定 IP 池是否随着应用的删除而被回收。 -
v1.multus-cni.io/default-network
:为应用创建一张默认网卡。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app-1
spec:
replicas: 2
selector:
matchLabels:
app: test-app-1
template:
metadata:
annotations:
ipam.spidernet.io/subnet: |-
{
"ipv4": ["subnet-6"]
}
ipam.spidernet.io/ippool-ip-number: '+1'
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
ipam.spidernet.io/ippool-reclaim: "false"
labels:
app: test-app-1
spec:
containers:
- name: test-app-1
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
EOF
最终, 在应用被创建时,Spiderpool 会从指定子网中随机选择一些 IP 来创建出固定 IP 池 与 Pod 的网卡形成绑定,同时自动池会自动继承子网的网关、路由属性。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
auto4-test-app-1-eth0-a5bd3 4 10.6.0.0/16 2 3 false
~# kubectl get po -l app=test-app-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-app-1-74cbbf654-2ndzl 1/1 Running 0 46s 10.6.168.101 controller-node-1 <none> <none>
test-app-1-74cbbf654-4f2w2 1/1 Running 0 46s 10.6.168.103 worker-node-1 <none> <none>
~# kubectl get spiderippool auto4-test-app-1-eth0-a5bd3 -ojsonpath={.spec} | jq
{
"default": false,
"disable": false,
"gateway": "10.6.0.1",
"ipVersion": 4,
"ips": [
"10.6.168.101-10.6.168.103"
],
"podAffinity": {
"matchLabels": {
"ipam.spidernet.io/app-api-group": "apps",
"ipam.spidernet.io/app-api-version": "v1",
"ipam.spidernet.io/app-kind": "Deployment",
"ipam.spidernet.io/app-name": "test-app-1",
"ipam.spidernet.io/app-namespace": "default"
}
},
"routes": [
{
"dst": "10.7.0.0/16",
"gw": "10.6.0.1"
}
],
"subnet": "10.6.0.0/16",
"vlan": 0
}
为实现固定 IP 池效果,Spiderpool 会给自动池补充如下的一些特殊的内建 Label 和 PodAffinity,它们用于指向应用,与应用形成绑定关系,明确该池只服务于指定的应用。当 ipam.spidernet.io/ippool-reclaim: false
时,删除应用后,IP会被回收,但自动池不会被回收。如果期望该池能被其他应用所使用,需要手动摘除这些内建 Label 和 PodAffinity。
Additional Labels:
ipam.spidernet.io/owner-application-gv
ipam.spidernet.io/owner-application-kind
ipam.spidernet.io/owner-application-namespace
ipam.spidernet.io/owner-application-name
ipam.spidernet.io/owner-application-uid
Additional PodAffinity:
ipam.spidernet.io/app-api-group
ipam.spidernet.io/app-api-version
ipam.spidernet.io/app-kind
ipam.spidernet.io/app-namespace
ipam.spidernet.io/app-name
经过多次测试,不断重启 Pod,其 Pod 的 IP 都被固定在 IP 池范围内:
~# kubectl delete po -l app=test-app-1
~# kubectl get po -l app=test-app-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-app-1-74cbbf654-7v54p 1/1 Running 0 7s 10.6.168.101 worker-node-1 <none> <none>
test-app-1-74cbbf654-qzxp7 1/1 Running 0 7s 10.6.168.102 controller-node-1 <none> <none>
固定 IP 池 IP 数量的动态扩缩容
创建应用时指定了注解 ipam.spidernet.io/ippool-ip-number
: '+1',其表示应用分配到的固定 IP 数量比应用的副本数多 1 个,在应用滚动更新时,能够避免旧 Pod 未删除,新 Pod 没有可用 IP 的问题。
以下演示了扩容场景,将应用的副本数从 2 扩容到 3,应用对应的两个固定 IP 池会自动从 3 个 IP 扩容到 4 个 IP,一直保持一个冗余 IP,符合预期。
~# kubectl scale deploy test-app-1 --replicas 3
deployment.apps/test-app-1 scaled
~# kubectl get po -l app=test-app-1 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-app-1-74cbbf654-7v54p 1/1 Running 0 54s 10.6.168.101 worker-node-1 <none> <none>
test-app-1-74cbbf654-9w8gd 1/1 Running 0 19s 10.6.168.103 worker-node-1 <none> <none>
test-app-1-74cbbf654-qzxp7 1/1 Running 0 54s 10.6.168.102 controller-node-1 <none> <none>
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
auto4-test-app-1-eth0-a5bd3 4 10.6.0.0/16 3 4 false
通过上述,Spiderpool 对于应用扩缩容的场景,只需要修改应用的副本数即可。
自动回收 IP 池
创建应用时指定了注解 ipam.spidernet.io/ippool-reclaim
,该注解默认值为 true
,为 true 时,随着应用的删除,将自动删除对应的自动池。在本文中设置为 false
,其表示删除应用时,自动创建的固定 IP 池会回收其中被分配的 IP ,但池不会被回收,并且当使用相同配置再次创建同名应用时,会自动继承该 IP 池。
~# kubectl delete deploy test-app-1
deployment.apps "test-app-1" deleted
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
auto4-test-app-1-eth0-a5bd3 4 10.6.0.0/16 0 4 false
使用上述所示的应用 Yaml,再次创建同名应用,可以观察到不会再次创建新的 IP 池,将自动复用旧 IP 池,并且其副本数和 IP 池的 IP 分配情况与实际相同。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
auto4-test-app-1-eth0-a5bd3 4 10.6.0.0/16 2 3 false
自动固定多网卡 IP
如果您希望为 Pod 实现多网卡 IP 的固定,参考本章节。在以下的示例 Yaml 中, 会创建 2 个副本的 Deployment,每个副本拥有多张网卡,其中:
-
ipam.spidernet.io/subnets
:用于指定 Spiderpool 的子网,Spiderpool 会自动在该子网中随机选择一些 IP 来创建固定 IP 池,与本应用绑定,实现 IP 固定的效果。在本示例中该注解会为 Pod 创建 2 个属于不同 Underlay 子网的固定 IP 池。 -
v1.multus-cni.io/default-network
:为应用创建一张默认网卡。 -
k8s.v1.cni.cncf.io/networks
:为应用创建另一张网卡。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app-2
spec:
replicas: 2
selector:
matchLabels:
app: test-app-2
template:
metadata:
annotations:
ipam.spidernet.io/subnets: |-
[
{
"interface": "eth0",
"ipv4": ["subnet-6"]
},{
"interface": "net1",
"ipv4": ["subnet-7"]
}
]
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
k8s.v1.cni.cncf.io/networks: kube-system/macvlan-ens224
labels:
app: test-app-2
spec:
containers:
- name: test-app-2
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
EOF
最终, 在应用创建时,Spiderpool 会从指定 2 个 Underlay 子网中随机选择一些 IP 来创建出对应的固定 IP 池,并与应用 Pod 的两张网卡分别形成绑定。每张网卡对应的固定池都将会自动继承其所归属子网的网关、路由等属性。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
auto4-test-app-2-eth0-44037 4 10.6.0.0/16 2 3 false
auto4-test-app-2-net1-44037 4 10.7.0.0/16 2 3 false
~# kubectl get po -l app=test-app-2 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-app-2-f5d6b8d6c-8hxvw 1/1 Running 0 6m22s 10.6.168.101 controller-node-1 <none> <none>
test-app-2-f5d6b8d6c-rvx55 1/1 Running 0 6m22s 10.6.168.105 worker-node-1 <none> <none>
~# kubectl get spiderippool auto4-test-app-2-eth0-44037 -ojsonpath={.spec} | jq
{
"default": false,
"disable": false,
"gateway": "10.6.0.1",
"ipVersion": 4,
"ips": [
"10.6.168.101",
"10.6.168.105-10.6.168.106"
],
"podAffinity": {
"matchLabels": {
"ipam.spidernet.io/app-api-group": "apps",
"ipam.spidernet.io/app-api-version": "v1",
"ipam.spidernet.io/app-kind": "Deployment",
"ipam.spidernet.io/app-name": "test-app-2",
"ipam.spidernet.io/app-namespace": "default"
}
},
"routes": [
{
"dst": "10.7.0.0/16",
"gw": "10.6.0.1"
}
],
"subnet": "10.6.0.0/16",
"vlan": 0
}
~# kubectl get spiderippool auto4-test-app-2-net1-44037 -ojsonpath={.spec} | jq
{
"default": false,
"disable": false,
"gateway": "10.7.0.1",
"ipVersion": 4,
"ips": [
"10.7.168.101-10.7.168.103"
],
"podAffinity": {
"matchLabels": {
"ipam.spidernet.io/app-api-group": "apps",
"ipam.spidernet.io/app-api-version": "v1",
"ipam.spidernet.io/app-kind": "Deployment",
"ipam.spidernet.io/app-name": "test-app-2",
"ipam.spidernet.io/app-namespace": "default"
}
},
"routes": [
{
"dst": "10.6.0.0/16",
"gw": "10.7.0.1"
}
],
"subnet": "10.7.0.0/16",
"vlan": 0
}
SpiderSubnet 也支持多网卡的动态 IP 扩缩容、自动回收 IP 池等功能。
手动创建 IPPool 实例继承子网属性
如下是一个归属于子网 subnet-6
,子网号为:10.6.0.0/16
的 IPPool 实例示例。该 IPPool 实例的可用 IP 范围必须是子网 subnet-6.spec.ips
的子集。
~# cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: ippool-test
spec:
ips:
- 10.6.168.108-10.6.168.110
subnet: 10.6.0.0/16
EOF
使用上述 Yaml,手动创建 IPPool 实例,可以看到它归属于子网号相同的子网,同时继承了对应子网的网关、路由等属性。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
ippool-test 4 10.6.0.0/16 0 3 false
~# kubectl get spidersubnet
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT
subnet-6 4 10.6.0.0/16 3 10
subnet-7 4 10.7.0.0/16 0 10
~# kubectl get spiderippool ippool-test -o jsonpath='{.spec}' | jq
{
"default": false,
"disable": false,
"gateway": "10.6.0.1",
"ipVersion": 4,
"ips": [
"10.6.168.108-10.6.168.110"
],
"routes": [
{
"dst": "10.7.0.0/16",
"gw": "10.6.0.1"
}
],
"subnet": "10.6.0.0/16",
"vlan": 0
}
总结
SpiderSubnet 功能可以帮助将基础设施管理员和应用程序管理员的责任分开,支持自动创建和动态扩展固定 IPPool 到每个需要静态 IP 的应用程序。