SpiderIPPool Affinity
简体中文 | English
介绍
SpiderIPPool 资源代表 IP 地址的集合,一个 Subnet 中的不同 IP 地址,可分别存储到不同的 IPPool 实例中(Spiderpool 会校验 IPPool 之间的地址集合不重叠)。因此,依据需求,SpiderIPPool 中的 IP 集合可大可小。能很好的应对 underlay 网络的 IP 地址资源有限情况,且这种设计特点,能够通过各种亲和性规则让不同的应用、租户来绑定不同的 SpiderIPPool,也能分享相同的 SpiderIPPool,既能够让所有应用共享使用同一个子网,又能够实现 "微隔离"。
快速入门
在 SpiderIPPool CRD 里,我们有定义很多的字段来搭配亲和性使用,如:
spec.podAffinity
字段可控制该池是否可被 Pod 使用。spec.namespaceName
和spec.namespaceAffinity
字段会校验是否与 Pod 的Namespace相匹配,若不匹配则不可使用。(namespaceName
优先级高于namespaceAffinity
)spec.nodeName
和spec.nodeAffinity
字段会校验是否与 Pod 所在的节点相匹配,若不匹配则不可使用。(nodeName
优先级高于nodeAffinity
)multusName
字段会判断当前网卡是否与 multus 的 net-attach-def 资源使用的 CNI 配置相匹配,若不匹配则不可使用。
这些字段不仅起到**过滤**的作用,同时也会起到一个**排序**的效果,若匹配的字段越多,越优先使用该 IP 池。
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-pod-ippool
spec:
subnet: 10.6.0.0/16
ips:
- 10.6.168.151-10.6.168.160
podAffinity:
matchLabels:
app: test-app-3
nodeName:
- master
- worker1
namespaceName:
- kube-system
- default
multusName:
- kube-system/macvlan-vlan0
应用亲和性
在集群中,防火墙通常用于管理南北向通信,即集群内部和外部网络之间的通信。为了实现安全管控,防火墙需要对通信流量进行检查和过滤,并对出口通信进行限制。由于防火墙安全管控,一组 Deployment 它的所有 Pod 期望能够在一个固定的 IP 地址范围内轮滚分配 IP 地址,以配合防火墙的放行策略,从而实现 Underlay 网络下的南北通信。
在社区现有方案中,是通过在 Deployment 上写关于 IP 地址的注解来实现。但这种方式存在一些缺点,如:
-
随着应用的扩容,需要人为手动的修改应用的 annotaiton ,重新规划 IP 地址。
-
annotaiton 方式的 IP 管理,脱钩于它们自身的 IPPool CR 机制,形成管理上的空白,无法获知哪些 IP 可用。
-
不同应用间极其容易分配了冲突的 IP 地址,从而导致应用创建失败。
对此,Spiderpool 借助于 IPPool 的 IP 集合可大可小的特点,并结合设置 IPPool 的 podAffinity
,可实现同一组或者多组应用的亲和绑定,既保证了 IP 管理方式的统一,又解耦 "应用扩容" 和 "IP 地址扩容",也固定了应用的 IP 使用范围。
创建应用亲和性的 IPPool
SpiderIPPool 提供了 podAffinity
字段,当应用创建时,尝试从 SpiderIPPool 分配 IP 时,若 Pod 的 selector.matchLabels
符合该 podAffinity 设置,则能从该 SpiderIPPool 中成功分配出 IP,否则无法从该 SpiderIPPool 中分配出IP。
依据如上所述,使用如下的 Yaml,创建如下具备应用亲和的 SpiderIPPool,它将为 app: test-app-3
Pod 符合条件的 selector.matchLabel
提供 IP 地址。
~# cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-pod-ippool
spec:
subnet: 10.6.0.0/16
ips:
- 10.6.168.151-10.6.168.160
podAffinity:
matchLabels:
app: test-app-3
EOF
创建指定 matchLabels 的应用。以下的示例 Yaml 中, 会创建一组 Deployment 应用 ,其中:
-
ipam.spidernet.io/ippool
:Spiderpool 用于指定设置了应用亲和的 IP 池。 -
v1.multus-cni.io/default-network
:为应用创建一张默认网卡。 -
matchLabels
: 设置应用的 Label。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app-3
spec:
replicas: 1
selector:
matchLabels:
app: test-app-3
template:
metadata:
annotations:
ipam.spidernet.io/ippool: |-
{
"ipv4": ["test-pod-ippool"]
}
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
labels:
app: test-app-3
spec:
containers:
- name: test-app-3
image: nginx
imagePullPolicy: IfNotPresent
EOF
最终, 创建应用后,Pod 的 matchLabels
符合该 IPPool 的应用亲和设置,成功从该 IPPool 中获得 IP 地址分配。并且应用的 IP 固定在该 IP 池内。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
test-pod-ippool 4 10.6.0.0/16 1 10 false
~# kubectl get po -l app=test-app-3 -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-app-3-6994b9d5bb-qpf5p 1/1 Running 0 52s 10.6.168.154 node2 <none> <none>
创建另一个应用,并指定一个不符合 IPPool 应用亲和的 matchLabels
,Spiderpool 将会拒绝为其分配 IP 地址。
matchLabels
: 设置应用的 Label 为test-unmatch-labels
,不匹配 IPPool 亲和性。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-unmatch-labels
spec:
replicas: 1
selector:
matchLabels:
app: test-unmatch-labels
template:
metadata:
annotations:
ipam.spidernet.io/ippool: |-
{
"ipv4": ["test-pod-ippool"]
}
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
labels:
app: test-unmatch-labels
spec:
containers:
- name: test-unmatch-labels
image: nginx
imagePullPolicy: IfNotPresent
EOF
当 Pod 的 matchLabels 不符合该 IPPool 的应用亲和时,获得 IP 地址分配失败,符合预期。
kubectl get po -l app=test-unmatch-labels -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-unmatch-labels-699755574-9ncp7 0/1 ContainerCreating 0 16s <none> node1 <none> <none>
应用共享的 IPPool
-
创建应用共享的 IPPool
kubectl apply -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/shared-static-ipv4-ippool.yaml
apiVersion: spiderpool.spidernet.io/v2beta1 kind: SpiderIPPool metadata: name: shared-static-ipv4-ippool spec: subnet: 172.18.41.0/24 ips: - 172.18.41.44-172.18.41.47
-
创建两个 deployment,其 Pod 设置注释 “ipam.spidernet.io/ippool” 以显式指定池选择规则。它将成功获得IP地址
kubectl apply -f https://raw.githubusercontent.com/spidernet-io/spiderpool/main/docs/example/ippool-affinity-pod/shared-static-ippool-deploy.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: shared-static-ippool-deploy-1 spec: replicas: 2 selector: matchLabels: app: static template: metadata: annotations: ipam.spidernet.io/ippool: |- { "ipv4": ["shared-static-ipv4-ippool"] } labels: app: static spec: containers: - name: shared-static-ippool-deploy-1 image: busybox imagePullPolicy: IfNotPresent command: ["/bin/sh", "-c", "trap : TERM INT; sleep infinity & wait"] --- apiVersion: apps/v1 kind: Deployment metadata: name: shared-static-ippool-deploy-2 spec: replicas: 2 selector: matchLabels: app: static template: metadata: annotations: ipam.spidernet.io/ippool: |- { "ipv4": ["shared-static-ipv4-ippool"] } labels: app: static spec: containers: - name: shared-static-ippool-deploy-2 image: busybox imagePullPolicy: IfNotPresent command: ["/bin/sh", "-c", "trap : TERM INT; sleep infinity & wait"]
确认最终状态
kubectl get po -l app=static -o wide NAME READY STATUS RESTARTS AGE IP NODE shared-static-ippool-deploy-1-8588c887cb-gcbjb 1/1 Running 0 62s 172.18.41.45 spider-control-plane shared-static-ippool-deploy-1-8588c887cb-wfdvt 1/1 Running 0 62s 172.18.41.46 spider-control-plane shared-static-ippool-deploy-2-797c8df6cf-6vllv 1/1 Running 0 62s 172.18.41.44 spider-worker shared-static-ippool-deploy-2-797c8df6cf-ftk2d 1/1 Running 0 62s 172.18.41.47 spider-worker
节点亲和性
不同的 node 上,可用的 IP 范围也许并不相同,例如:
-
同一数据中心内,集群接入的 node 分属不同 subnet 。
-
单个集群中,node 跨越了不同的数据中心。
在以上场景中,当同一个应用的不同副本被调度到了不同的 node 上,需要分配不同 subnet 下的 underlay IP 地址。在当前社区现有方案,它们并不能满足这样的需求。
对此,Spiderpool 提供一种节点亲和的方式,能很好的解决上述问题。Spiderpool 的 SpiderIPPool CR 中,提供了 nodeAffinity
与 nodeName
字段,用于设置 node label selector,从而实现 IPPool 和 node 之间亲和性,当 Pod 被调度到某个 node 上后,IPAM 插件能够从亲和的 IPPool 中进行 IP 地址分配。
创建节点亲和的 IPPool
SpiderIPPool 提供了 nodeAffinity
字段,当 Pod 在某个节点上启动,尝试从 SpiderIPPool 分配 IP 时,若 Pod 所在节点符合该 nodeAffinity 设置,则能从该 SpiderIPPool 中成功分配出 IP,否则无法从该 SpiderIPPool 中分配出IP。
依据如上所述,使用如下的 Yaml,创建如下具备节点亲和的 SpiderIPPool,它将为在运行该节点上的 Pod 提供 IP 地址。
~# cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-node1-ippool
spec:
subnet: 10.6.0.0/16
ips:
- 10.6.168.101-10.6.168.110
nodeAffinity:
matchExpressions:
- {key: kubernetes.io/hostname, operator: In, values: [node1]}
EOF
SpiderIPPool 提供了另一种节点亲和性方式供选择:nodeName
,当 nodeName
不为空时,Pod 在某个节点上启动,并尝试从 SpiderIPPool 分配 IP 地址, 若 Pod 所在节点符合该 nodeName
,则能从该 SpiderIPPool 中成功分配出 IP,若 Pod 所在节点不符合 nodeName
,则无法从该 SpiderIPPool 中分配出 IP。当 nodeName 为空时,Spiderpool 对 Pod 不实施任何分配限制,参考如下:
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-node1-ippool
spec:
subnet: 10.6.0.0/16
ips:
- 10.6.168.101-10.6.168.110
nodeName:
- node1
创建应用。以下的示例 Yaml 中,会创建 1 组 DaemonSet 应用,其中:
-
ipam.spidernet.io/ippool
:Spiderpool 用于指定设置了节点亲和的 IP 池。 -
v1.multus-cni.io/default-network
:用于指定应用所使用的 IP 池。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: test-app-1
labels:
app: test-app-1
spec:
selector:
matchLabels:
app: test-app-1
template:
metadata:
labels:
app: test-app-1
annotations:
ipam.spidernet.io/ippool: |-
{
"ipv4": ["test-node1-ippool"]
}
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
spec:
containers:
- name: test-app
image: nginx
imagePullPolicy: IfNotPresent
EOF
创建应用后,可以发现,只有当 Pod 所在节点符合该 IPPool 的节点亲和设置,才能从该 IPPool 中获得 IP 地址分配。并且应用的 IP 固定在该 IP 池内。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
test-node1-ippool 4 10.6.0.0/16 1 10 false
~# kubectl get po -l app=test-app-1 -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-app-1-2cmnz 0/1 ContainerCreating 0 115s <none> node2 <none> <none>
test-app-1-br5gw 0/1 ContainerCreating 0 115s <none> master <none> <none>
test-app-1-dvhrx 1/1 Running 0 115s 10.6.168.108 node1 <none> <none>
租户亲和性
管理员往往会在集群划分多租户,能更好地隔离、管理和协作,同时也能提供更高的安全性、资源利用率和灵活性等。需要不同功能的应用部署在不同租户下,对此,期望实现一个 IPPool 能同一个或者多个 namespace 下的应用实现亲和,而拒绝不相干租户的应用创建,能帮助管理员减少运维负担。
当前社区中并没有解决上述场景的有效方案,Spiderpool 通过设置 SpiderIPPool CR 中的 namespaceAffinity
或 namespaceName
字段,实现同一个或者多个租户的亲和性,从而使得满足条件的应用才能够从 IPPool 中分配到 IP 地址。
创建租户亲和的 IPPool
创建租户
~# kubectl create ns test-ns1
namespace/test-ns1 created
~# kubectl create ns test-ns2
namespace/test-ns2 created
使用如下的 Yaml,创建租户亲和的 IPPool。
SpiderIPPool 提供了 namespaceAffinity
字段,当应用创建时,尝试从 SpiderIPPool 分配 IP 时,若 Pod 所在租户符合该 namespaceAffinity 设置,则能从该 SpiderIPPool 中成功分配出 IP,否则无法从该 SpiderIPPool 中分配出IP。
~# cat <<EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-ns1-ippool
spec:
subnet: 10.6.0.0/16
ips:
- 10.6.168.111-10.6.168.120
namespaceAffinity:
matchLabels:
kubernetes.io/metadata.name: test-ns1
EOF
SpiderIPPool 提供了另一种租户亲和性方式供选择:namespaceName
,当 namespaceName
不为空时,Pod 被创建时,并尝试从 SpiderIPPool 分配 IP 地址, 若 Pod 所在租户符合该 namespaceName
,则能从该 SpiderIPPool 中成功分配出 IP,若 Pod 所在租户不符合 namespaceName
,则无法从该 SpiderIPPool 中分配出 IP。当 namespaceName
为空时,Spiderpool 对 Pod 不实施任何分配限制,参考如下:
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-ns1-ippool
spec:
subnet: 10.6.0.0/16
ips:
- 10.6.168.111-10.6.168.120
namespaceName:
- test-ns1
创建指定租户的应用。以下的示例 Yaml 中, 会创建一组在租户 test-ns1
下的 Deployment 应用 ,其中:
-
ipam.spidernet.io/ippool
:Spiderpool 用于指定设置了租户亲和的 IP 池。 -
v1.multus-cni.io/default-network
:为应用创建一张默认网卡。 -
namespace
: 指定应用所在租户。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app-2
namespace: test-ns1
spec:
replicas: 1
selector:
matchLabels:
app: test-app-2
template:
metadata:
annotations:
ipam.spidernet.io/ippool: |-
{
"ipv4": ["test-ns1-ippool"]
}
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
labels:
app: test-app-2
spec:
containers:
- name: test-app-2
image: nginx
imagePullPolicy: IfNotPresent
EOF
最终, 创建应用后,在租户内的应用 Pod 成功从所亲和的 IPPool 中分配到了 IP 地址。
~# kubectl get spiderippool
NAME VERSION SUBNET ALLOCATED-IP-COUNT TOTAL-IP-COUNT DEFAULT
test-ns1-ippool 4 10.6.0.0/16 1 10 false
~# kubectl get po -l app=test-app-2 -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-ns1 test-app-2-975d9f-6bww2 1/1 Running 0 44s 10.6.168.111 node2 <none> <none>
创建一个不在上述 test-ns1
租户内的应用,Spiderpool 将会拒绝为其分配 IP 地址,自动拒绝不相干租户的应用使用该 IPPool。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-other-ns
namespace: test-ns2
spec:
replicas: 1
selector:
matchLabels:
app: test-other-ns
template:
metadata:
annotations:
ipam.spidernet.io/ippool: |-
{
"ipv4": ["test-ns1-ippool"]
}
v1.multus-cni.io/default-network: kube-system/macvlan-ens192
labels:
app: test-other-ns
spec:
containers:
- name: test-other-ns
image: nginx
imagePullPolicy: IfNotPresent
EOF
当 Pod 所属租户不符合该 IPPool 的租户亲和,获得 IP 地址分配失败,符合预期。
~# kubectl get po -l app=test-other-ns -A -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-ns2 test-other-ns-56cc9b7d95-hx4b5 0/1 ContainerCreating 0 6m3s <none> node2 <none> <none>
网卡配置亲和性
当为应用创建多网卡时候,我们可以为**集群级别缺省池**指定 multus 的 net-attach-def 实例亲和性。该方法相比于通过注解 ipam.spidernet.io/ippools
显式指定网卡与 IPPool 资源的绑定关系更为简单。
首先为 IPPool 资源配置好各类属性,其中:
-
spec.default
字段设置为true
, 以此减少为应用打上ipam.spidernet.io/ippool
或ipam.spidernet.io/ippools
注解,让体验更为简单。 -
spec.multusName
字段配置该 IPPool 对应的 multus 网卡配置。(若您未指定对应 multus 的 net-attach-def 实例的 namespace,我们会默认将其视为属于 spiderpool 安装时的命名空间)
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-ippool-eth0
spec:
default: true
subnet: 10.6.0.0/16
ips:
- 10.6.168.151-10.6.168.160
multusName:
- default/macvlan-vlan0-eth0
---
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
name: test-ippool-eth1
spec:
default: true
subnet: 10.7.0.0/16
ips:
- 10.7.168.151-10.7.168.160
multusName:
- kube-system/macvlan-vlan0-eth1
创建多网卡的应用。我们只需以下的示例 Yaml 中, 会创建有两张网卡的 Deployment 应用 ,其中:
-
v1.multus-cni.io/default-network
:为创建的应用选择默认网卡配置信息。(若不指定该注解而直接使用 multus 集群默认网卡配置信息,请在 helm 安装 spiderpool 时通过参数指定默认网卡配置信息--set multus.multusCNI.defaultCniCRName=default/macvlan-vlan0-eth0
) -
k8s.v1.cni.cncf.io/networks
:为创建的应用选择额外网卡的配置信息。
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: test-app
template:
metadata:
annotations:
v1.multus-cni.io/default-network: default/macvlan-vlan0-eth0
k8s.v1.cni.cncf.io/networks: kube-system/macvlan-vlan0-eth1
labels:
app: test-app
spec:
containers:
- name: test-app
image: nginx
imagePullPolicy: IfNotPresent
EOF
总结
SpiderIPPool 中的 IP 集合可大可小。能很好的应对 Underlay 网络的 IP 地址资源有限情况,且这种设计特点,能够通过各种亲和性规则让不同的应用、租户来绑定不同的 SpiderIPPool,也能分享相同的 SpiderIPPool,既能够让所有应用共享使用同一个 Subnet,又能够实现 "微隔离"。