使用Spiderpool为Pod添加Underlay网卡

2024-01-16 10:14:39 浏览数 (1)

前言

本文介绍在一个 Calico 作为缺省 CNI 的集群,通过 Spiderpool 这一完整的 Underlay 网络解决方案,通过 Multus 为 Pod 额外附加一张由 Macvlan 创建的网卡,为集群提供Underlay数据面。

1 环境介绍

  • 集群环境:3个宿主机节点,已经使用Calico作为CNI,CIDR是197.166.0.0/16,k8s版本v1.23.6。
  • Spiderpool 版本:v0.8.3
  • Multus-CNI 版本:v3.9.3
  • 预留的 Underlay IP:100.10.22.210~100.10.22.218

2 安装步骤

由于集群在一个内网环境,所以无法按照官网的指导进行操作。只能把helm的charts和依赖镜像下载到本地操作。

2.1 下载 cni charts 和镜像

  • CNI 因为需要用到macvlan的CNI插件,所以要手动下载,这里下载的是v1.3.0
  • Spiderpool charts 在 github spidernet-io/spiderpool 的 github_pages 这个分支,在 docs/charts/ 下找到对应版本——spiderpool-0.8.3.tgz。
  • Spiderpool-controller 镜像 docker pull ghcr.io/spidernet-io/spiderpool/spiderpool-controller:v0.8.3
  • Spiderpool-agent 镜像 docker pull ghcr.io/spidernet-io/spiderpool/spiderpool-agent:v0.8.3
  • Multus-cni 镜像 docker pull ghcr.io//k8snetworkplumbingwg/multus-cni:v3.9.3

下载完成后将镜像使用docker save -o xxx.tar保存成文件,和spiderpool-0.8.3.tgz一并拷贝到环境的宿主机上(集群所有宿主机都要有),并使用docker load -i xxx.tar加载好镜像(注意加载后要恢复docker tag)。CNI解压后把macvlan的二进制放到集群所有宿主机的/opt/cni/bin下面。

2.2 检查 kube-system/kubeadm-config ConfigMap

spiderpool 默认从 kubeadm-config 中获取 service 的子网信息,如果没有这个ConfigMap需要手动创建一个,简单的文件(kubeadm-config.yaml)如下:

代码语言:yaml复制
networking:
  podSubnet: 197.166.0.0/16
  serviceSubnet: 169.169.0.0/16

注意里面的子网信息要和集群创建时的保持一致。

使用如下命令创建:

代码语言:bash复制
kubectl create configmap kubeadm-config -n kube-system --from-file=./kubeadm-config.yaml

PS:目前 spiderpool v0.8.3 的版本还有这个依赖,已经给社区提了issue,后续版本可能会解除这个依赖。

2.3 安装

需要确保环境宿主机上已经有了helm。

  • 解压缩 charts 并使用 Helm 更新依赖tar -xvf spiderpool-0.8.3.tgz
代码语言:bash复制
helm dep update ./spiderpool
  • 安装Spiderpool
代码语言:bash复制
helm install spiderpool ./spiderpool --namespace kube-system  --set coordinator.mode=overlay --wait

参数介绍

参数

作用

coordinator.mode

这里指定overlay才是作为第二个网卡

multus.multusCNI.defaultCniCRName

指定 multus 默认使用的 CNI 的 NetworkAttachmentDefinition(NAD) 实例名。如果参数选项不为空,则安装后会自动生成一个数据为空的 NAD 对应实例。如果参数选项为空,会尝试通过 /etc/cni/net.d 目录下的第一个 CNI 配置来创建对应的 NAD 实例,否则会自动生成一个名为 default 的 NAD 实例

multus.install

默认是自动安装multus,如果已经安装multus,先要显式设置为false

  • 安装完成后,查看 Spiderpool 组件状态
代码语言:bash复制
~# kubectl get pod -n kube-system | grep spiderpool
spiderpool-agent-9ffcc                                 1/1     Running            0                  64s
spiderpool-agent-jq6sq                                 1/1     Running            0                  64s
spiderpool-agent-kz8m4                                 1/1     Running            0                  64s
spiderpool-controller-59bcd9985b-hz42m                 1/1     Running            0                  86s
spiderpool-init                                        1/1     Running            0                  86s
  • 检查 Spidercoordinator.status 中的 Phase 是否为 Synced, 并且 overlayPodCIDR 是否与集群中 Calico 的子网保持一致
代码语言:bash复制
~# calicoctl get ippools
NAME                  CIDR                  SELECTOR   
default-ipv4-ippool   197.166.0.0/16        all()      
default-ipv6-ippool   fd97:6fea:542f::/48   all() 

~# kubectl  get spidercoordinators.spiderpool.spidernet.io default -o yaml
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderCoordinator
metadata:
  creationTimestamp: "2023-12-26T06:04:24Z"
  finalizers:
  - spiderpool.spidernet.io
  generation: 1
  name: default
  resourceVersion: "4407909"
  selfLink: /apis/spiderpool.spidernet.io/v2beta1/spidercoordinators/default
  uid: 64822833-357d-4f41-af81-262d22380a3b
spec:
  detectGateway: false
  detectIPConflict: false
  hijackCIDR:
  - 169.254.0.0/16
  hostRPFilter: 0
  hostRuleTable: 500
  mode: overlay
  podCIDRType: auto
  podDefaultRouteNIC: ""
  podMACPrefix: ""
  tunePodRoutes: true
status:
  overlayPodCIDR:
  - 197.166.0.0/16
  - fd97:6fea:542f::/48
  phase: Synced
  serviceCIDR:
  - 169.169.0.0/16

(如果 phase 不为 Synced, 那么将会阻止 Pod 被创建,如果 overlayPodCIDR 不正常, 可能会导致通信问题)

  • 创建 SpiderIPPool Underlay 的网卡 enp1s0 所在子网为 100.10.22.0/24,以该子网创建 SpiderIPPool:
代码语言:bash复制
cat << EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
  name: underlay-pool
spec:
  disable: false
  gateway: 100.10.22.134
  ips:
  - 100.10.22.210-100.10.22.218
  subnet: 100.10.22.0/24
EOF

subnet 应该与节点网卡 enp1s0 的子网保持一致,并且 ips 不与现有任何 IP 冲突。

  • 创建 SpiderMultusConfig 通过 Spidermultusconfig 创建 Multus 的 NAD 实例:
代码语言:bash复制
cat << EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: macvlan-enp1s0
spec:
  cniType: macvlan
  macvlan:
    master:
    - enp1s0
    ippools:
      ipv4:
      - underlay-pool
    vlanID: 0
EOF

spec.macvlan.master 设置为 enp1s0, enp1s0 必须存在于主机上。并且 spec.macvlan.spiderpoolConfigPools.IPv4IPPool设置的子网和 enp1s0 保持一致。

创建成功后, 查看 Multus NAD 是否成功创建:

代码语言:bash复制
kubectl  get network-attachment-definitions.k8s.cni.cncf.io  macvlan-enp1s0 -o yaml
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"spiderpool.spidernet.io/v2beta1","kind":"SpiderMultusConfig","metadata":{"annotations":{},"name":"macvlan-enp1s0","namespace":"default"},"spec":{"cniType":"macvlan","macvlan":{"ippools":{"ipv4":["underlay-pool"]},"master":["enp1s0"],"vlanID":0}}}
  creationTimestamp: "2023-12-27T02:21:40Z"
  generation: 1
  name: macvlan-enp1s0
  namespace: default
  ownerReferences:
  - apiVersion: spiderpool.spidernet.io/v2beta1
    blockOwnerDeletion: true
    controller: true
    kind: SpiderMultusConfig
    name: macvlan-enp1s0
    uid: daa7e75e-cf40-4112-a7a3-307ce2f94b52
  resourceVersion: "4409741"
  selfLink: /apis/k8s.cni.cncf.io/v1/namespaces/default/network-attachment-definitions/macvlan-enp1s0
  uid: 20c156d0-c326-474c-86bb-21e7de0fdc5f
spec:
  config: '{"cniVersion":"0.3.1","name":"macvlan-enp1s0","plugins":[{"type":"macvlan","master":"enp1s0","mode":"bridge","ipam":{"type":"spiderpool","default_ipv4_ippool":["underlay-pool"]}},{"detectIPConflict":false,"detectGateway":false,"mode":"auto","type":"coordinator"}]}'

3 创建一个带 Underlay 网卡的应用

我这里用go做了一个简单的http应用镜像,默认监听8080端口,收到请求后会返回所有IPv4地址。代码如下:

代码语言:go复制
package main

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
)

type Handler struct {
	str []string
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s, _ := json.Marshal(h.str)
	w.Write([]byte(s))
}

func main() {
	runtime.GOMAXPROCS(2)
	port, ok := os.LookupEnv("SERVER_PORT")
	if !ok {
		port = "8080"
	}

	addrs, err := net.InterfaceAddrs()
	if err != nil {
		fmt.Println(err)
		return
	}
	ips := []string{}
	for _, address := range addrs {
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				ips = append(ips, ipnet.IP.String())
			}
		}
	}

	http.Handle("/", &Handler{ips})
	if err = http.ListenAndServe(":" port, nil); err != nil {
		fmt.Println(err.Error())
	}
}

这里打包成一个httpd:0.0.1的镜像。

使用下面的命令创建测试应用 httpd:

代码语言:bash复制
cat << EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      annotations:
        k8s.v1.cni.cncf.io/networks: macvlan-enp1s0
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd:0.0.1
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
EOF

PS:k8s.v1.cni.cncf.io/networks: 该字段指定 Multus 使用 macvlan-enp1s0 为 Pod 附加一张网卡。

等Pod Running状态后查看:

代码语言:bash复制
kubectl describe pod httpd-85f96ddc76-7tjzt
中间省略...
Events:
  Type     Reason                  Age                 From               Message
  ----     ------                  ----                ----               -------
  Normal   Scheduled               16m                 default-scheduler  Successfully assigned default/httpd-85f96ddc76-7tjzt to 100.10.22.104
  Normal   AddedInterface          6m51s               multus             Add eth0 [197.166.25.41/32] from kube-system/k8s-pod-network
  Normal   AddedInterface          6m51s               multus             Add net1 [100.10.22.213/24] from default/macvlan-enp1s0

然后从同vlan其他主机访问Pod:

代码语言:bash复制
curl 100.10.22.213:8080
["197.166.25.41","100.10.22.213"]

4 补充 IPv6 双栈

4.1 创建一个 v6 的 IPPool

代码语言:bash复制
cat << EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderIPPool
metadata:
  name: underlay-pool-v6
spec:
  disable: false
  ips:
  - 2001:db8::a00:64ff:fe0a:1691-2001:db8::a00:64ff:fe0a:1699
  subnet: 2001:db8::/64
EOF

注意,这里没有加网关。

4.2 重新创建 Mutus 的 NAD 实例

代码语言:bash复制
cat << EOF | kubectl apply -f -
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: macvlan-enp1s0
spec:
  cniType: macvlan
  macvlan:
    master:
    - enp1s0
    ippools:
      ipv4:
      - underlay-pool
      ipv6:
      - underlay-pool-v6
    vlanID: 0
EOF

这里我们增加了 v6 的IPPool。

4.3 参考 3 重新部署下 http 应用

等Pod Running状态后查看:

代码语言:bash复制
kubectl describe pod httpd-85d54455d-6xdbw
中间省略...
Events:
  Type    Reason          Age   From               Message
  ----    ------          ----  ----               -------
  Normal  Scheduled       32s   default-scheduler  Successfully assigned default/httpd-85d54455d-6xdbw to 100.10.22.106
  Normal  AddedInterface  31s   multus             Add eth0 [197.166.54.137/32 fd00:c5a6::2a:609/128] from kube-system/k8s-pod-network
  Normal  AddedInterface  31s   multus             Add net1 [100.10.22.213/24 2001:db8::a00:64ff:fe0a:1691/64] from default/macvlan-enp1s0
  Normal  Pulled          31s   kubelet            Container image "http:1.0.0" already present on machine
  Normal  Created         30s   kubelet            Created container httpd
  Normal  Started         30s   kubelet            Started container httpd

可以看到Pod的网卡信息已经是双栈。

然后从同vlan其他主机访问Pod:

代码语言:bash复制
curl -6 http://[2001:db8::a00:64ff:fe0a:1691]:8080
["197.166.25.41","100.10.22.213"]

总结

整个安装过程还算比较顺利,中间遇到的问题,项目组的同学帮助也非常及时,在此表示感谢@郭奇峰

参考内容:

Calico Quick Start

0 人点赞