Pod 网卡热插拔

3 篇文章 0 订阅
2 篇文章 0 订阅

Pod 网卡热插拔

Pod 是 kubernetes 环境中最小的负载单元,设计之初应该从未想到现在对 pod 的要求越来越大,如现在的 kubevirt 等 vm in pod 的形式,需要在 pod 内部运行 libvirt 虚拟机;
Libvirt 虚拟机是支持网卡热插拔的,那么对 pod 提出的要求就是 pod 能够先进行网卡热插拔到 pod 内交付给 libvirt 进行使用。

如 dynamic-networks-controller项目(https://github.com/k8snetworkplumbingwg/multus-dynamic-networks-controller)就是为了实现 pod 网卡热插拔功能。

部署

当前该项目支持 crio 和 containerd 两种 runtime 实现;在部署时请选择对应的 yaml
manifests/dynamic-networks-controller.yaml (containerd)或 manifests/crio-dynamic-networks-controller.yaml (crio)

该项目依赖 multus cni
Multus cni 安装

git clone https://github.com/k8snetworkplumbingwg/multus-cni.git && cd multus-cni
cat ./deployments/multus-daemonset-thick.yml | kubectl apply -f -

创建 一个 nad

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: net1
  namespace: default
spec:
  config: '{
    "cniVersion": "0.3.1",
    "name": "kube-ovn",
    "plugins":[
        {
            "type":"kube-ovn",       // 调哪个 cni 去处理
            "server_socket":"/run/openvswitch/kube-ovn-daemon.sock",
            "provider": "net1.default.ovn"
        },
        {
            "type":"portmap",
            "capabilities":{
                "portMappings":true
            }
        }
    ]
}'

dynamic-networks-controller 安装

git clone https://github.com/k8snetworkplumbingwg/multus-dynamic-networks-controller.git
cd multus-dynamic-networks-controller
kubectl apply -f manifests/dynamic-networks-controller.yaml

kubectl apply -f manifests/crio-dynamic-networks-controller.yaml (cri-o)

区别在于两者的配置不同,criSocketPath 分别指向宿主机的 /run/containerd/containerd.sock 或 /run/crio/crio.sock;

daemonset controller

kube-system   dynamic-networks-controller-ds-2gtjm   1/1     Running   0          4h24m   10.16.0.2   node1   <none>           <none>
kube-system   dynamic-networks-controller-ds-hn44p   1/1     Running   0          4h24m   10.16.0.8   node2   <none>           <none>

原理

通过 watch pod 变化,annotation 中 k8s.v1.cni.cncf.io/networks 和 k8s.v1.cni.cncf.io/network-status 的比较进行热插拔动作。
在这里插入图片描述
图片来自 kubevirt 社区

代码分析

  1. 初始化 controller 和 workqueue
    podNetworksController, err := controller.NewPodNetworksController(
        podInformerFactory,                  // pod Informer
        nadInformerFactory,                  // network-attachment-definition Informer
        eventBroadcaster,
        newEventRecorder(eventBroadcaster),
        k8sClient,                           // k8sClient
        nadClientSet,                        // nadClient
        containerRuntime,                    // runtime 根据选择 runtime 使用 socket 生成对应的 client
        multuscni.NewClient(configuration.MultusSocketPath))   // multus client
        workqueue: workqueue.NewNamedRateLimitingQueue(
            workqueue.DefaultControllerRateLimiter(),
            AdvertisedName),
  1. Controller 启动后,过滤一遍已有的 pod ,将非 hostnetwork pod 加到 workqueue 里
func (pnc *PodNetworksController) reconcileOnStartup() error {
    pods, err := pnc.podsLister.List(labels.Everything())
    if err != nil {
        return fmt.Errorf("failed to list pods on current node: %v", err)
    }
    for _, pod := range pods {
        if pnc.ignoreHostNetworkedPods(pod) {
            continue
        }
        namespacedName := annotations.NamespacedName(pod.GetNamespace(), pod.GetName())
        klog.V(logging.Debug).Infof("pod [%s] added to reconcile on startup", namespacedName)
        pnc.workqueue.Add(&namespacedName)
    }
    return nil
}
  1. workQueue 处理初始化加到 queue 的 obj 和 watch 到的 obj
    通过 annotation 获取 nad 信息。
    indexedNetworkSelectionElements := annotations.IndexPodNetworkSelectionElements(pod)
    indexedNetworkStatus := annotations.IndexNetworkStatusIgnoringDefaultNetwork(pod)
  • indexedNetworkSelectionElements map[string]nadv1.NetworkSelectionElement,解析 k8s.v1.cni.cncf.io/networks 而来,key 是 “default/net1” 或者 “default/net1/eth0” value 是 nad 资源
  • indexedNetworkStatus 则是通过 k8s.v1.cni.cncf.io/network-status 获取当前已绑定的 nad 信息;key 也是 “default/net1” 或者 “default/net1/eth0”,value 是网卡信息,包括 ip,mac,dns 等。
    就是根据两者的比较来判断,indexedNetworkSelectionElements 多余 indexedNetworkStatus 的部分就是需要热插的,少于 indexedNetworkStatus 的部分就是热拔的。
  1. 获取 netns
func (pnc *PodNetworksController) netnsPath(pod *corev1.Pod) (string, error) {
    if containerID := podContainerID(pod); containerID != "" {
        netns, err := pnc.containerRuntime.NetNS(containerID)
        if err != nil {
            return "", fmt.Errorf("failed to get netns for container [%s]: %w", containerID, err)
        }
        return netns, nil
    }
    return "", nil
}

通过 pod 的 containerId 通过 runtime 去查询 netns

  1. 请求 add or del network
        err = pnc.handleDynamicInterfaceRequest(
            &DynamicAttachmentRequest{
                Pod:         pod,
                Attachments: attachmentsToAdd,
                Type:        add,
                PodNetNS:    netnsPath,
            })
  1. 调 multus 代理添加网卡
    for i := range dynamicAttachmentRequest.Attachments {
        netToAdd := dynamicAttachmentRequest.Attachments[i]
        klog.Infof("network to add: %v", netToAdd)

        netAttachDef, err := pnc.netAttachDefLister.NetworkAttachmentDefinitions(netToAdd.Namespace).Get(netToAdd.Name)
        if err != nil {
            klog.Errorf("failed to access the networkattachmentdefinition %s/%s: %v", netToAdd.Namespace, netToAdd.Name, err)
            return err
        }
        netAttachDefWithDefaults, err := serializeNetAttachDefWithDefaults(netAttachDef)
        if err != nil {
            return err
        }
        response, err := pnc.multusClient.InvokeDelegate(
            multusapi.CreateDelegateRequest(
                multuscni.CmdAdd,
                podContainerID(pod),
                dynamicAttachmentRequest.PodNetNS,
                netToAdd.InterfaceRequest,
                pod.GetNamespace(),
                pod.GetName(),
                string(pod.UID),
                netAttachDefWithDefaults,
                interfaceAttributes(netToAdd),
            ))
  • 先通过 nad 的 name namespace 拿到完整的 nad 信息
  • 通过 multusClient 去使用 nad 里的 plugin 去创建和删除网络
  1. 完成后更新状态 k8s.v1.cni.cncf.io/network-status
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值