Pod 网卡热插拔

文章介绍了KubernetesPod支持网卡热插拔的需求背景,特别是对于运行Libvirt虚拟机的场景。文中详细讲解了动态网络控制器dynamic-networks-controller的部署,包括针对CRI-O和containerd两种runtime的配置,并提到了MultusCNI的安装和使用。此外,文章还阐述了该控制器的工作原理,通过对比Pod的网络状态来决定网络接口的增删,并分析了关键代码流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
<think>我们正在讨论热插拔技术,用户要求理解热插拔的概念及其在计算机领域中的应用。根据提供的引用,我们可以整合信息如下: 引用[1]提到了Java中的热插拔技术,通过Java Agent和字节码操作实现运行时代码的动态修改和扩展。 引用[2]和[4]详细介绍了PCIe设备的热插拔,包括电源管理和热插拔控制模块的工作原理。 引用[3]则从电子系统角度解释了热插拔技术的原理,包括瞬态控制、限流保护等。 因此,回答将围绕热插拔的定义、原理(包括电子层面和计算机系统层面)以及应用场景展开。 回答结构: 1. 热插拔的定义 2. 热插拔技术原理(电子层面和计算机系统层面) 3. 应用场景 4. 相关问题 注意:引用标记要自然地添加在相应内容的末尾。</think>### 热插拔技术原理与应用场景详解 #### 一、热插拔技术原理 1. **核心概念** 热插拔(Hot Plug)指在**系统不断电运行状态下**动态添加/移除硬件设备或软件模块的能力。其技术本质是通过多层保护机制实现物理连接与逻辑控制的解耦: $$ \text{热插拔} = \text{电气隔离} + \text{状态监控} + \text{动态资源分配} $$ 2. **硬件层实现机制**(以PCIe为例) - **电气保护**:专用热插拔芯片提供浪涌抑制和限流保护,防止插拔瞬间产生$10^3 \text{V}$级电压冲击[^3] - **状态检测**:通过Slot Status Register实时监控连接器状态(如PRSNT#引脚电平变化)[^4] - **协议层处理**: ```mermaid graph LR A[设备插入] --> B{检测电压稳定} B -->|是| C[发送Beacon信号] C --> D[链路训练] D --> E[配置空间枚举] ``` 3. **软件层实现机制** - **操作系统支持**:ACPI规范定义热插拔事件处理流程 - **动态加载技术**(如Java): ```java // Java热部署示例(使用类加载器) ClassLoader cl = new URLClassLoader(jarUrls); Class<?> pluginClass = cl.loadClass("com.example.Plugin"); Plugin plugin = (Plugin) pluginClass.newInstance(); // 动态加载新模块[^1] ``` #### 二、关键技术挑战与解决方案 | 挑战 | 解决方案 | 作用原理 | |---------------------|-----------------------------------|------------------------------| | **电弧干扰** | 热插拔控制器芯片 | 限制$di/dt$(电流变化率)[^3]| | **数据损坏** | 事务原子性保证 | PCIe的MRM(Message Routing)| | **系统崩溃** | 资源隔离池 | 预留内存/中断号资源[^4] | | **服务中断** | 冗余设计 | 双控制器热备切换 | #### 三、典型应用场景 1. **硬件扩展领域** - **服务器运维**:更换故障硬盘(RAID阵列支持热插拔- **工业控制**:PLC模块在线更换(满足IEC 61131标准) - **网络设备**:交换机光模块热更换(如SFP+接口) 2. **软件系统领域** - **微服务架构**:动态加载服务模块(Kubernetes Pod热更新) - **开发调试**:Java IDE的热部署(IntelliJ IDEA的JRebel)[^1] - **插件系统**: ```python # Python动态加载插件 import importlib plugin = importlib.import_module("new_plugin") # 运行时加载新功能 ``` 3. **特殊场景** - **航空航天**:卫星载荷模块在轨更换 - **医疗设备**:手术机器人器械热切换 - **汽车电子**:车载信息娱乐系统外设扩展 #### 四、技术演进趋势 1. **硬件层面** - PCIe 6.0引入**FLIT模式**,提升热插拔链路训练速度40%[^2] - 新型控制器支持$10 \text{kV}$静电防护(符合IEC 61000-4-2) 2. **软件层面** - 云原生场景下**无状态服务热迁移** - WebAssembly实现浏览器端模块热更新 > **设计警示**:热插拔系统需通过$HALT \text{(Highly Accelerated Life Test)}$测试,验证$10^4$次插拔寿命[^3] --- ### 相关问题延伸 1. **PCIe热插拔与USB热插拔的协议层差异是什么?** 2. **如何设计Java Agent实现方法级热替换?** [^1] 3. **热插拔控制器芯片的选型要考虑哪些电气参数?** [^3] 4. **Kubernetes如何实现零停机热更新?** 5. **热插拔场景下的数据一致性如何保证?** [^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值