【SRIOV】SR-IOV Network Operator 1.6.0 Part 9 — SriovOperatorConfig 控制器深度分析

09 — SriovOperatorConfig 控制器深度分析

一、模块定位

SriovOperatorConfigReconciler 是 SR-IOV Network Operator 的全局配置控制器。它负责管理 Operator 的所有基础设施组件:

  1. Webhook 配置同步(Mutating Webhook + Validating Webhook)
  2. Config Daemon DaemonSet 同步(SR-IOV Network Config Daemon)
  3. Device Plugin DaemonSet 同步(通过 helper.go 的 syncPluginDaemonObjs
  4. Metrics Exporter 同步
  5. OpenShift systemd 服务同步(通过 MachineConfig)
  6. Feature Gate 初始化
  7. 日志级别设置
  8. Finalizer 管理(确保删除时清理 Webhook)

二、模块整体结构

2.1 类图

依赖

依赖

调用 syncPluginDaemonObjs 等

SriovOperatorConfigReconciler

+Client client.Client

+Scheme *runtime.Scheme

+PlatformHelper platforms.Interface

+FeatureGate featuregate.FeatureGate

+UncachedAPIReader client.Reader

+Reconcile(ctx, req)(ctrl.Result, error)

+SetupWithManager(mgr) : error

-syncWebhookObjs(ctx, dc) : error

-syncConfigDaemonSet(ctx, dc) : error

-syncMetricsExporter(ctx, dc) : error

-syncOpenShiftSystemdService(ctx, dc) : error

-syncOperatorConfigFinalizers(ctx, dc, logger) : error

-handleSriovOperatorConfigDeletion(ctx, dc, logger)(ctrl.Result, error)

-syncK8sResource(ctx, cr, in) : error

-deleteK8sResource(ctx, in) : error

-deleteK8sResources(ctx, objs) : error

-deleteWebhookObject(ctx, obj) : error

-deleteAllWebhooks(ctx) : error

-setLabelInsideObject(ctx, cr, objs) : error

«interface»

PlatformHelper

+IsOpenshiftCluster() : bool

+IsHypershift() : bool

«interface»

FeatureGate

+Init(featureGates)

+IsEnabled(name) : bool

+String() : string

helperFuncs

2.2 Reconcile 整体流程图

NotFound

错误

找到

Reconcile 被触发

获取默认 SriovOperatorConfig

存在?

等待创建
不重新排队

返回错误

设置日志级别
snolog.SetLogLevel

DeletionTimestamp
不为零?

handleSriovOperatorConfigDeletion

syncOperatorConfigFinalizers
确保 Finalizer 存在

初始化 FeatureGates
r.FeatureGate.Init

日志输出启用的 FeatureGates

EnableInjector?

日志: Injector 已禁用

继续

EnableOperatorWebhook?

日志: Webhook 已禁用

继续

列出所有 Policy
按优先级排序

syncWebhookObjs
同步 Webhook

syncConfigDaemonSet
同步 Config Daemon

syncPluginDaemonObjs
同步 Device Plugin

syncMetricsExporter
同步 Metrics Exporter

ClusterType
== Openshift?

IsHypershift?

错误: systemd 不支持 hypershift

syncOpenShiftSystemdService
同步 systemd MachineConfig

完成

返回错误

RequeueAfter
ResyncPeriod

结束


三、核心业务逻辑深度解析

3.1 Reconcile 方法(逐行)

func (r *SriovOperatorConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    logger := log.FromContext(ctx).WithValues("sriovoperatorconfig", req.NamespacedName)
    logger.Info("Reconciling SriovOperatorConfig")
    // 获取默认的 SriovOperatorConfig 对象
    // 注意:在 SetupWithManager 中通过 defaultConfigPredicate() 过滤
    // 只处理名为 DefaultConfigName 且在 vars.Namespace 命名空间中的对象
    defaultConfig := &sriovnetworkv1.SriovOperatorConfig{}
    err := r.Get(ctx, req.NamespacedName, defaultConfig)
    if err != nil {
        if apierrors.IsNotFound(err) {
            // 默认配置不存在,等待创建
            // 不重新排队,因为对象创建事件会自动触发 Reconcile
            logger.Info("default SriovOperatorConfig object not found. waiting for creation.")
            return reconcile.Result{}, nil
        }
        logger.Error(err, "Failed to get default SriovOperatorConfig object")
        return reconcile.Result{}, err
    }
    // 设置全局日志级别
    // 根据 SriovOperatorConfig.Spec.LogLevel 配置
    snolog.SetLogLevel(defaultConfig.Spec.LogLevel)
    // 检查对象是否正在被删除
    if !defaultConfig.ObjectMeta.DeletionTimestamp.IsZero() {
        // 对象正在被删除,执行清理逻辑
        return r.handleSriovOperatorConfigDeletion(ctx, defaultConfig, logger)
    }
    // 确保 Finalizer 存在
    // Finalizer 确保删除时会先清理 Webhook 等外部资源
    if err = r.syncOperatorConfigFinalizers(ctx, defaultConfig, logger); err != nil {
        return reconcile.Result{}, err
    }
    // 初始化 Feature Gates
    // 从 SriovOperatorConfig.Spec.FeatureGates 读取配置
    r.FeatureGate.Init(defaultConfig.Spec.FeatureGates)
    logger.Info("enabled featureGates", "featureGates", r.FeatureGate.String())

Feature Gates 是 Operator 的功能开关机制。通过 SriovOperatorConfig.Spec.FeatureGates map 启用/禁用特定功能(如 ParallelNicConfig、ManageSoftwareBridges、MetricsExporter 等)。

    // 记录 Injector 和 Webhook 的启用状态
    if !defaultConfig.Spec.EnableInjector {
        logger.Info("SR-IOV Network Resource Injector is disabled.")
    }
    if !defaultConfig.Spec.EnableOperatorWebhook {
        logger.Info("SR-IOV Network Operator Webhook is disabled.")
    }
    // 获取 Policy 列表并按优先级排序
    // 虽然此控制器不直接应用 Policy,但排序后的列表
    // 在某些场景下需要保持一致的顺序
    policyList := &sriovnetworkv1.SriovNetworkNodePolicyList{}
    err = r.List(ctx, policyList, &client.ListOptions{})
    if err != nil {
        return reconcile.Result{}, err
    }
    sort.Sort(sriovnetworkv1.ByPriority(policyList.Items))
    // 1. 同步 Webhook 对象(Injector + Operator Webhook)
    if err = r.syncWebhookObjs(ctx, defaultConfig); err != nil {
        return reconcile.Result{}, err
    }

    // 2. 同步 Config Daemon DaemonSet
    if err = r.syncConfigDaemonSet(ctx, defaultConfig); err != nil {
        return reconcile.Result{}, err
    }

    // 3. 同步 Device Plugin DaemonSet(通过 helper.go)
    if err = syncPluginDaemonObjs(ctx, r.Client, r.Scheme, defaultConfig); err != nil {
        return reconcile.Result{}, err
    }

    // 4. 同步 Metrics Exporter
    if err = r.syncMetricsExporter(ctx, defaultConfig); err != nil {
        return reconcile.Result{}, err
    }
    // 5. OpenShift 特定:创建 systemd 服务的 MachineConfig
    if vars.ClusterType == consts.ClusterTypeOpenshift {
        if r.PlatformHelper.IsHypershift() {
            // Hypershift 没有 MCO(Machine Config Operator)
            return ctrl.Result{}, fmt.Errorf("systemd mode is not supported on hypershift")
        }
        if err = r.syncOpenShiftSystemdService(ctx, defaultConfig); err != nil {
            return reconcile.Result{}, err
        }
    }

    logger.Info("Reconcile SriovOperatorConfig completed successfully")
    return reconcile.Result{RequeueAfter: consts.ResyncPeriod}, nil
}

3.2 SetupWithManager — 监听配置

func (r *SriovOperatorConfigReconciler) SetupWithManager(mgr ctrl.Manager) error {
    return ctrl.NewControllerManagedBy(mgr).
        For(&sriovnetworkv1.SriovOperatorConfig{},
            ctrl_builder.WithPredicates(defaultConfigPredicate())).  // 只处理默认配置
        Owns(&appsv1.DaemonSet{}).    // 监听拥有的 DaemonSet 变更
        Owns(&corev1.ConfigMap{}).    // 监听拥有的 ConfigMap 变更
        Complete(r)
}
// defaultConfigPredicate 只允许默认配置对象通过过滤
func defaultConfigPredicate() predicate.Predicate {
    return predicate.NewPredicateFuncs(func(object client.Object) bool {
        if object.GetName() == consts.DefaultConfigName && object.GetNamespace() == vars.Namespace {
            return true
        }
        return false
    })
}

设计要点:只监听默认 SriovOperatorConfig(名为 default,在 Operator 命名空间中)。非默认配置对象被忽略。Owns 确保 DaemonSet 和 ConfigMap 变更也能触发 Reconcile。

3.3 syncWebhookObjs — 同步 Webhook

Injector 且
EnableInjector=false

Operator 且
EnableOperatorWebhook=false

启用

syncWebhookObjs

遍历 webhooks map

创建渲染数据
Namespace, WebhookName
镜像地址, 集群类型
DevMode, ImagePullSecrets
CertManager 配置
证书信息

IsOpenshift
&& IsHypershift?

ExternalControlPlane = true

ExternalControlPlane = false

设置 ResourceInjectorMatchCondition
FeatureGate 状态

渲染 manifests 目录

启用?

删除 Injector Webhook 对象

删除 Operator Webhook 对象

同步 Webhook 对象

下一个 Webhook?

完成

func (r *SriovOperatorConfigReconciler) syncWebhookObjs(
    ctx context.Context,
    dc *sriovnetworkv1.SriovOperatorConfig,
) error {
    // webhooks map 包含两个 webhook:
    // - InjectorWebHookName → InjectorWebHookPath (网络资源注入器)
    // - OperatorWebHookName → OperatorWebHookPath (Operator 验证 webhook)
    for name, path := range webhooks {
        // 准备渲染数据
        data := render.MakeRenderData()
        data.Data["Namespace"] = vars.Namespace
        data.Data["SRIOVMutatingWebhookName"] = name
        data.Data["NetworkResourcesInjectorImage"] = os.Getenv("NETWORK_RESOURCES_INJECTOR_IMAGE")
        data.Data["SriovNetworkWebhookImage"] = os.Getenv("SRIOV_NETWORK_WEBHOOK_IMAGE")
        data.Data["ReleaseVersion"] = os.Getenv("RELEASEVERSION")
        data.Data["ClusterType"] = vars.ClusterType
        data.Data["DevMode"] = os.Getenv("DEV_MODE")
        data.Data["ImagePullSecrets"] = GetImagePullSecrets()

        // 证书管理配置
        data.Data["CertManagerEnabled"] = strings.ToLower(
            os.Getenv("ADMISSION_CONTROLLERS_CERTIFICATES_CERT_MANAGER_ENABLED")) == trueString
        data.Data["OperatorWebhookSecretName"] = os.Getenv("ADMISSION_CONTROLLERS_CERTIFICATES_OPERATOR_SECRET_NAME")
        data.Data["OperatorWebhookCA"] = os.Getenv("ADMISSION_CONTROLLERS_CERTIFICATES_OPERATOR_CA_CRT")
        data.Data["InjectorWebhookSecretName"] = os.Getenv("ADMISSION_CONTROLLERS_CERTIFICATES_INJECTOR_SECRET_NAME")
        data.Data["InjectorWebhookCA"] = os.Getenv("ADMISSION_CONTROLLERS_CERTIFICATES_INJECTOR_CA_CRT")

        // Hypershift 外部控制平面标志
        data.Data["ExternalControlPlane"] = false
        if r.PlatformHelper.IsOpenshiftCluster() {
            external := r.PlatformHelper.IsHypershift()
            data.Data["ExternalControlPlane"] = external
        }

        // ResourceInjectorMatchCondition Feature Gate
        data.Data[consts.ResourceInjectorMatchConditionFeatureGate] =
            r.FeatureGate.IsEnabled(consts.ResourceInjectorMatchConditionFeatureGate)

        // 渲染 manifests
        objs, err := render.RenderDir(path, &data)
        if err != nil {
            return err
        }

        // 如果 Injector 被禁用,删除相关对象
        if !dc.Spec.EnableInjector && path == consts.InjectorWebHookPath {
            for _, obj := range objs {
                err = r.deleteWebhookObject(ctx, obj)
                if err != nil {
                    return err
                }
            }
            continue  // 跳过同步,继续下一个 webhook
        }

        // 如果 Operator Webhook 被禁用,删除相关对象
        if !dc.Spec.EnableOperatorWebhook && path == consts.OperatorWebHookPath {
            for _, obj := range objs {
                err = r.deleteWebhookObject(ctx, obj)
                if err != nil {
                    return err
                }
            }
            continue
        }

        // 同步 Webhook 对象
        for _, obj := range objs {
            err = r.syncK8sResource(ctx, dc, obj)
            if err != nil {
                return err
            }
        }
    }
    return nil
}

Webhook 动态启用/禁用:用户可以通过 SriovOperatorConfig.Spec.EnableInjectorSpec.EnableOperatorWebhook 来控制 Webhook 的启停。禁用时不仅停止 Webhook 服务,还会删除所有相关的 Kubernetes 对象。

3.4 syncConfigDaemonSet — 同步 Config Daemon

Systemd

DaemonSet

syncConfigDaemonSet

创建渲染数据

设置镜像:
- SRIOV_NETWORK_CONFIG_DAEMON_IMAGE
- SRIOV_CNI_IMAGE
- SRIOV_INFINIBAND_CNI_IMAGE
- OVS_CNI_IMAGE
- RDMA_CNI_IMAGE

设置环境变量
Namespace, ReleaseVersion
ClusterType, DevMode
ImagePullSecrets

ConfigurationMode?
Systemd vs DaemonSet

UsedSystemdMode = true

UsedSystemdMode = false

设置 FeatureGates:
ParallelNicConfig
ManageSoftwareBridges

设置 CNI 二进制路径
默认: /var/lib/cni/bin
可通过 SRIOV_CNI_BIN_PATH 覆盖

Spec.DisablePlugins
非空?

DisablePlugins = 逗号分隔列表

渲染 ConfigDaemon manifests

遍历渲染对象

Kind == DaemonSet?

updateDaemonsetNodeSelector
设置节点选择器

syncK8sResource

还有对象?

完成

func (r *SriovOperatorConfigReconciler) syncConfigDaemonSet(
    ctx context.Context,
    dc *sriovnetworkv1.SriovOperatorConfig,
) error {
    data := render.MakeRenderData()

    // 镜像配置(通过环境变量注入)
    data.Data["Image"] = os.Getenv("SRIOV_NETWORK_CONFIG_DAEMON_IMAGE")
    data.Data["Namespace"] = vars.Namespace
    data.Data["SRIOVCNIImage"] = os.Getenv("SRIOV_CNI_IMAGE")
    data.Data["SRIOVInfiniBandCNIImage"] = os.Getenv("SRIOV_INFINIBAND_CNI_IMAGE")
    data.Data["OVSCNIImage"] = os.Getenv("OVS_CNI_IMAGE")
    data.Data["RDMACNIImage"] = os.Getenv("RDMA_CNI_IMAGE")
    data.Data["ReleaseVersion"] = os.Getenv("RELEASEVERSION")
    data.Data["ClusterType"] = vars.ClusterType
    data.Data["DevMode"] = os.Getenv("DEV_MODE")
    data.Data["ImagePullSecrets"] = GetImagePullSecrets()

    // 配置模式:Systemd vs DaemonSet
    if dc.Spec.ConfigurationMode == sriovnetworkv1.SystemdConfigurationMode {
        data.Data["UsedSystemdMode"] = true
    } else {
        data.Data["UsedSystemdMode"] = false
    }

    // Feature Gate 状态
    data.Data["ParallelNicConfig"] = r.FeatureGate.IsEnabled(consts.ParallelNicConfigFeatureGate)
    data.Data["ManageSoftwareBridges"] = r.FeatureGate.IsEnabled(consts.ManageSoftwareBridgesFeatureGate)

    // CNI 二进制路径
    envCniBinPath := os.Getenv("SRIOV_CNI_BIN_PATH")
    if envCniBinPath == "" {
        data.Data["CNIBinPath"] = "/var/lib/cni/bin"  // 默认路径
    } else {
        data.Data["CNIBinPath"] = envCniBinPath
    }

    // 禁用的插件列表
    if len(dc.Spec.DisablePlugins) > 0 {
        data.Data["DisablePlugins"] = strings.Join(dc.Spec.DisablePlugins.ToStringSlice(), ",")
    }

    // 渲染 manifests
    objs, err := render.RenderDir(consts.ConfigDaemonPath, &data)
    if err != nil {
        return err
    }

    // 同步每个对象
    for _, obj := range objs {
        if obj.GetKind() == "DaemonSet" {
            // 为 DaemonSet 设置节点选择器
            err = updateDaemonsetNodeSelector(obj, dc.Spec.ConfigDaemonNodeSelector)
            if err != nil {
                return err
            }
        }
        err = r.syncK8sResource(ctx, dc, obj)
        if err != nil {
            return err
        }
    }
    return nil
}

配置模式:Operator 支持两种配置模式:

  • DaemonSet 模式(默认):Config Daemon 作为 DaemonSet 运行,直接配置节点
  • Systemd 模式:通过 systemd 服务运行(OpenShift 上通过 MachineConfig 部署)

3.5 syncMetricsExporter — 同步 Metrics Exporter

func (r *SriovOperatorConfigReconciler) syncMetricsExporter(
    ctx context.Context,
    dc *sriovnetworkv1.SriovOperatorConfig,
) error {
    data := render.MakeRenderData()
    data.Data["Image"] = os.Getenv("METRICS_EXPORTER_IMAGE")
    data.Data["Namespace"] = vars.Namespace
    data.Data["ImagePullSecrets"] = GetImagePullSecrets()
    data.Data["MetricsExporterSecretName"] = os.Getenv("METRICS_EXPORTER_SECRET_NAME")
    data.Data["MetricsExporterPort"] = os.Getenv("METRICS_EXPORTER_PORT")
    data.Data["MetricsExporterKubeRbacProxyImage"] = os.Getenv("METRICS_EXPORTER_KUBE_RBAC_PROXY_IMAGE")
    data.Data["IsOpenshift"] = r.PlatformHelper.IsOpenshiftCluster()

    // Prometheus Operator 集成
    data.Data["IsPrometheusOperatorInstalled"] = strings.ToLower(
        os.Getenv("METRICS_EXPORTER_PROMETHEUS_OPERATOR_ENABLED")) == trueString
    data.Data["PrometheusOperatorDeployRules"] = strings.ToLower(
        os.Getenv("METRICS_EXPORTER_PROMETHEUS_DEPLOY_RULES")) == trueString
    data.Data["PrometheusOperatorServiceAccount"] = os.Getenv("METRICS_EXPORTER_PROMETHEUS_OPERATOR_SERVICE_ACCOUNT")
    data.Data["PrometheusOperatorNamespace"] = os.Getenv("METRICS_EXPORTER_PROMETHEUS_OPERATOR_NAMESPACE")

    // 节点选择器
    data.Data["NodeSelectorField"] = GetDefaultNodeSelector()
    if dc.Spec.ConfigDaemonNodeSelector != nil {
        data.Data["NodeSelectorField"] = dc.Spec.ConfigDaemonNodeSelector
    }

    objs, err := render.RenderDir(consts.MetricsExporterPath, &data)
    if err != nil {
        return err
    }

    // 根据 FeatureGate 决定创建还是删除
    if r.FeatureGate.IsEnabled(consts.MetricsExporterFeatureGate) {
        // 启用:创建/更新资源
        for _, obj := range objs {
            err = r.syncK8sResource(ctx, dc, obj)
            if err != nil {
                return err
            }
        }
    } else {
        // 禁用:删除所有资源
        err = r.deleteK8sResources(ctx, objs)
        if err != nil {
            return err
        }
    }
    return nil
}

Metrics Exporter 是通过 FeatureGate 控制的可选组件。禁用时不仅停止部署,还会主动删除之前创建的资源。

3.6 syncOpenShiftSystemdService — OpenShift systemd 服务

存在

NotFound

错误

syncOpenShiftSystemdService

ConfigurationMode
== Systemd?

获取现有 MachineConfig

删除 MachineConfig
切换回 DaemonSet 模式

返回 nil

返回错误

渲染 systemd manifests

setLabelInsideObject
设置 MachineConfig 标签

完成

返回错误

func (r *SriovOperatorConfigReconciler) syncOpenShiftSystemdService(
    ctx context.Context,
    cr *sriovnetworkv1.SriovOperatorConfig,
) error {
    if cr.Spec.ConfigurationMode != sriovnetworkv1.SystemdConfigurationMode {
        // 非 systemd 模式:如果之前部署了 MachineConfig,需要删除
        obj := &machinev1.MachineConfig{}
        // 使用 UncachedAPIReader 减少内存占用
        err := r.UncachedAPIReader.Get(ctx, types.NamespacedName{Name: consts.SystemdServiceOcpMachineConfigName}, obj)
        if err != nil {
            if apierrors.IsNotFound(err) {
                return nil  // 不存在,无需清理
            }
            return err
        }
        // 存在 MachineConfig 但已切换到 DaemonSet 模式,删除
        logger.Info("Systemd service was deployed but the operator is now operating on daemonset mode, removing the machine config")
        err = r.Delete(ctx, obj)
        return err
    }

    // Systemd 模式:创建/更新 MachineConfig
    data := render.MakeRenderData()
    data.Data["LogLevel"] = cr.Spec.LogLevel
    objs, err := render.RenderDir(consts.SystemdServiceOcpPath, &data)
    if err != nil {
        return err
    }

    return r.setLabelInsideObject(ctx, cr, objs)
}

UncachedAPIReader:使用非缓存的 API reader 读取 MachineConfig,避免大型 MachineConfig 对象占用 controller-runtime 缓存内存。

3.7 syncOperatorConfigFinalizers — Finalizer 管理

func (r SriovOperatorConfigReconciler) syncOperatorConfigFinalizers(
    ctx context.Context,
    defaultConfig *sriovnetworkv1.SriovOperatorConfig,
    logger logr.Logger,
) error {
    // 如果已有 Finalizer,无需添加
    if sriovnetworkv1.StringInArray(sriovnetworkv1.OPERATORCONFIGFINALIZERNAME, defaultConfig.ObjectMeta.Finalizers) {
        return nil
    }

    // 添加 Finalizer
    newObj := defaultConfig.DeepCopyObject().(client.Object)
    newObj.SetFinalizers(
        append(newObj.GetFinalizers(), sriovnetworkv1.OPERATORCONFIGFINALIZERNAME),
    )

    // 使用 Merge Patch 更新(避免覆盖其他字段)
    patch := client.MergeFrom(defaultConfig)
    err := r.Patch(ctx, newObj, patch)
    if err != nil {
        return fmt.Errorf("can't patch SriovOperatorConfig to add finalizer [%s]: %w",
            sriovnetworkv1.OPERATORCONFIGFINALIZERNAME, err)
    }

    // 刷新对象以获取最新版本
    return r.Get(ctx, types.NamespacedName{
        Namespace: defaultConfig.Namespace,
        Name:      defaultConfig.Name,
    }, defaultConfig)
}

3.8 handleSriovOperatorConfigDeletion — 删除处理

失败

成功

handleSriovOperatorConfigDeletion

有 Finalizer?

返回空 Result

日志: 删除 SriovOperatorConfig

deleteAllWebhooks
删除所有 Webhook 配置

成功?

返回错误

从 Finalizers 列表
移除 OPERATORCONFIGFINALIZERNAME

更新对象

返回空 Result

func (r *SriovOperatorConfigReconciler) handleSriovOperatorConfigDeletion(
    ctx context.Context,
    defaultConfig *sriovnetworkv1.SriovOperatorConfig,
    logger logr.Logger,
) (ctrl.Result, error) {
    var err error
    if sriovnetworkv1.StringInArray(sriovnetworkv1.OPERATORCONFIGFINALIZERNAME, defaultConfig.ObjectMeta.Finalizers) {
        logger.Info("delete SriovOperatorConfig CR", "Namespace", defaultConfig.Namespace, "Name", defaultConfig.Name)

        // 删除所有 Webhook 配置
        err = r.deleteAllWebhooks(ctx)
        if err != nil {
            return reconcile.Result{}, err
        }

        // 移除 Finalizer,允许对象被最终删除
        defaultConfig.ObjectMeta.Finalizers, _ = sriovnetworkv1.RemoveString(
            sriovnetworkv1.OPERATORCONFIGFINALIZERNAME, defaultConfig.ObjectMeta.Finalizers)
        if err := r.Update(ctx, defaultConfig); err != nil {
            return reconcile.Result{}, err
        }
    }
    return reconcile.Result{}, err
}

3.9 deleteAllWebhooks — 删除所有 Webhook

func (r SriovOperatorConfigReconciler) deleteAllWebhooks(ctx context.Context) error {
    var err error
    obj := &uns.Unstructured{}

    // 删除 Operator MutatingWebhookConfiguration
    obj.SetGroupVersionKind(schema.GroupVersionKind{
        Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration", Version: "v1"})
    obj.SetName(consts.OperatorWebHookName)
    err = errors.Join(err, r.deleteWebhookObject(ctx, obj))

    // 删除 Operator ValidatingWebhookConfiguration
    obj = &uns.Unstructured{}
    obj.SetGroupVersionKind(schema.GroupVersionKind{
        Group: "admissionregistration.k8s.io", Kind: "ValidatingWebhookConfiguration", Version: "v1"})
    obj.SetName(consts.OperatorWebHookName)
    err = errors.Join(err, r.deleteWebhookObject(ctx, obj))

    // 删除 Injector MutatingWebhookConfiguration
    obj = &uns.Unstructured{}
    obj.SetGroupVersionKind(schema.GroupVersionKind{
        Group: "admissionregistration.k8s.io", Kind: "MutatingWebhookConfiguration", Version: "v1"})
    obj.SetName(consts.InjectorWebHookName)
    err = errors.Join(err, r.deleteWebhookObject(ctx, obj))

    return err
}

errors.Join:Go 1.20+ 的错误拼接功能,将多个删除操作的错误合并为一个。即使某个删除失败,也会继续尝试删除其他 Webhook。

3.10 syncK8sResource — 通用资源同步

func (r *SriovOperatorConfigReconciler) syncK8sResource(
    ctx context.Context,
    cr *sriovnetworkv1.SriovOperatorConfig,
    in *uns.Unstructured,
) error {
    switch in.GetKind() {
    case clusterRoleResourceName,            // ClusterRole
        clusterRoleBindingResourceName,      // ClusterRoleBinding
        mutatingWebhookConfigurationCRDName, // MutatingWebhookConfiguration
        validatingWebhookConfigurationCRDName, // ValidatingWebhookConfiguration
        machineConfigCRDName:                // MachineConfig
        // 集群级别资源不设置 OwnerReference
        // 因为 OwnerReference 只能指向同命名空间或集群级别的所有者
    default:
        // 命名空间级别资源设置 OwnerReference
        if err := controllerutil.SetControllerReference(cr, in, r.Scheme); err != nil {
            return err
        }
    }
    // 使用 apply.ApplyObject 进行 server-side apply
    if err := apply.ApplyObject(ctx, r.Client, in); err != nil {
        return fmt.Errorf("failed to apply object %v with err: %v", in, err)
    }
    return nil
}

OwnerReference 策略

  • 命名空间级别资源(ServiceAccount、Service、Deployment 等):设置 OwnerReference
  • 集群级别资源(ClusterRole、ClusterRoleBinding、WebhookConfiguration、MachineConfig):不设置 OwnerReference(K8s 不允许命名空间级别的 Owner 拥有集群级别的资源)

四、组件同步全景图

Systemd 子组件 (OpenShift)

Metrics Exporter 子组件

Device Plugin 子组件

Config Daemon 子组件

Webhook 子组件

SriovOperatorConfigReconciler 管理的组件

Webhook 组件
syncWebhookObjs

Config Daemon
syncConfigDaemonSet

Device Plugin
syncPluginDaemonObjs

Metrics Exporter
syncMetricsExporter

Systemd Service
syncOpenShiftSystemdService

Injector MutatingWebhook
网络资源注入器

Operator Webhook
Mutating + Validating

Config Daemon DaemonSet
在节点上配置 SR-IOV

CNI 二进制文件
SRIOV-CNI, IB-CNI, OVS-CNI, RDMA-CNI

Device Plugin DaemonSet
暴露 VF 资源

ServiceAccount/Role/RoleBinding

Metrics Exporter DaemonSet

kube-rbac-proxy

Service/Monitor

MachineConfig
switchdev-config


五、Webhook 启停序列图

Webhook ResourcesOperatorConfigReconcilerKubernetes API用户Webhook ResourcesOperatorConfigReconcilerKubernetes API用户loop[遍历 Injector Webhook 对象]loop[遍历 Injector Webhook 对象]设置 EnableInjector=false触发 ReconcilesyncWebhookObjs检测 EnableInjector=falsedeleteWebhookObject删除 Deployment/Service/WebhookConfiguration跳过同步,继续 Operator Webhook设置 EnableInjector=true触发 ReconcilesyncWebhookObjs检测 EnableInjector=truesyncK8sResource (apply)创建/更新 Deployment/Service/WebhookConfiguration

六、Finalizer 生命周期

CR 刚创建

syncOperatorConfigFinalizers
添加 OPERATORCONFIGFINALIZERNAME

正常 Reconcile 循环

用户执行 kubectl delete

DeletionTimestamp 不为零

deleteAllWebhooks 成功

移除 Finalizer

CR 被 GC 删除

NoFinalizer

HasFinalizer

Deleting

WebhooksDeleted

FinalizerRemoved


七、Feature Gates 初始化流程

各处使用

FeatureGate.Init

输入

SriovOperatorConfig
Spec.FeatureGates
map[string]bool

解析 FeatureGates map

设置内部标志位

NodePolicyReconciler
ManageSoftwareBridges

ConfigDaemon
ParallelNicConfig
ManageSoftwareBridges

MetricsExporter
MetricsExporterFeatureGate

Webhook
ResourceInjectorMatchCondition


八、环境变量依赖总览

环境变量用途使用位置
SRIOV_NETWORK_CONFIG_DAEMON_IMAGEConfig Daemon 镜像syncConfigDaemonSet
SRIOV_CNI_IMAGESR-IOV CNI 镜像syncConfigDaemonSet
SRIOV_INFINIBAND_CNI_IMAGEIB CNI 镜像syncConfigDaemonSet
OVS_CNI_IMAGEOVS CNI 镜像syncConfigDaemonSet
RDMA_CNI_IMAGERDMA CNI 镜像syncConfigDaemonSet
NETWORK_RESOURCES_INJECTOR_IMAGEInjector 镜像syncWebhookObjs
SRIOV_NETWORK_WEBHOOK_IMAGEWebhook 镜像syncWebhookObjs
SRIOV_DEVICE_PLUGIN_IMAGEDevice Plugin 镜像syncPluginDaemonObjs
METRICS_EXPORTER_IMAGEMetrics Exporter 镜像syncMetricsExporter
METRICS_EXPORTER_KUBE_RBAC_PROXY_IMAGEkube-rbac-proxy 镜像syncMetricsExporter
RELEASEVERSION发布版本多处
DEV_MODE开发模式syncWebhookObjs, syncConfigDaemonSet
IMAGE_PULL_SECRETS镜像拉取密钥GetImagePullSecrets
SRIOV_CNI_BIN_PATHCNI 二进制路径syncConfigDaemonSet
ADMISSION_CONTROLLERS_CERTIFICATES_*Webhook 证书配置syncWebhookObjs
METRICS_EXPORTER_PROMETHEUS_*Prometheus 集成配置syncMetricsExporter

九、关键设计模式总结

9.1 单例配置模式

  • 只处理名为 default 的 SriovOperatorConfig
  • 通过 defaultConfigPredicate() 过滤
  • 确保全局只有一个有效的配置对象

9.2 声明式资源同步

  • 使用 apply.ApplyObject 进行 Server-Side Apply
  • 对比期望状态与实际状态,只更新有变化的资源
  • DeepDerivative 避免默认值导致的不必要更新

9.3 Finalizer 保护模式

  • 添加 Finalizer 防止过早删除
  • 删除时先清理 Webhook 等外部资源
  • 清理完成后才移除 Finalizer

9.4 模板渲染 + 同步模式

  • 所有组件通过 render.RenderDir 渲染 manifests 模板
  • 模板中包含镜像、命名空间、配置等变量
  • 渲染后通过 syncK8sResourcesyncDaemonSet 同步到集群

9.5 平台感知模式

  • 通过 PlatformHelper 检测运行平台
  • OpenShift:支持 MachineConfig、systemd 模式
  • Hypershift:不支持 systemd 模式
  • 标准 Kubernetes:仅 DaemonSet 模式

9.6 动态启停模式

  • Webhook 通过 EnableInjector / EnableOperatorWebhook 控制
  • Metrics Exporter 通过 FeatureGate 控制
  • 禁用时主动删除资源,启用时重新创建
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值