要实现一个 Kubernetes 控制器,它在 DaemonSet 容器中运行,并侦听自定义资源创建事件,然后基于自定义资源的 spec.nodeSelector 判断当前节点是否匹配,你可以根据以下步骤实现:

第 1 步:获取当前节点的标签

首先,你需要获取当前节点上的标签。这可以通过访问 Kubernetes API 来完成。

package main

import (
    "context"
    "fmt"
    "os"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
)

// getNodeLabels 返回当前节点的标签。
func getNodeLabels(nodeName string) (map[string]string, error) {
    config, err := rest.InClusterConfig()
    if err != nil {
        return nil, fmt.Errorf("获取 in-cluster config 失败: %v", err)
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return nil, fmt.Errorf("创建 clientset 失败: %v", err)
    }

    node, err := clientset.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{})
    if err != nil {
        return nil, fmt.Errorf("获取节点 %s 失败: %v", nodeName, err)
    }

    return node.Labels, nil
}

第 2 步:判断节点是否满足 nodeSelector

接下来,你需要一种方法来比较这些标签和自定义资源的 spec.nodeSelector,以判断当前节点是否满足条件。

// isNodeSelected 判断给定的 nodeSelector 是否选择了具有给定标签的节点。
func isNodeSelected(nodeLabels map[string]string, nodeSelector map[string]string) bool {
    for key, value := range nodeSelector {
        if val, ok := nodeLabels[key]; !ok || val != value {
            return false
        }
    }
    return true
}

完整示例

将这两部分结合,偏设你已有逻辑在适当的时间监听到自定义资源的创建,并从该资源中提取 nodeSelector。以下是如何将这些组合来判断当前节点是否被选中:

package main

import (
    "fmt"
    "os"
)

func main() {
    // 模拟接收到的 nodeSelector,实际情况你会从自定义资源中提取这个信息
    // 例如: spec.nodeSelector
    receivedNodeSelector := map[string]string{
        "disktype": "ssd",
        "gpu":      "true",
    }

    // 假设当前节点的名称通过环境变量获得
    nodeName := os.Getenv("MY_NODE_NAME")
    if nodeName == "" {
        fmt.Println("节点名称未设置")
        return
    }

    nodeLabels, err := getNodeLabels(nodeName)
    if err != nil {
        fmt.Printf("获取节点标签失败: %v\n", err)
        return
    }

    isSelected := isNodeSelected(nodeLabels, receivedNodeSelector)
    if isSelected {
        fmt.Println("当前节点被选择")
    } else {
        fmt.Println("当前节点未被选择")
    }
}

注意:MY_NODE_NAME 环境变量应该在你的 DaemonSet 定义中设置,确保它能够获取到当前节点的名称。一种常见的做法是使用 Downward API 来将节点名称作为环境变量传递给容器:

env:
- name: MY_NODE_NAME
  valueFrom:
    fieldRef:
      fieldPath: spec.nodeName

在实际使用中,receivedNodeSelector 应由监听到的自定义资源事件提供。这里只是简化了这部分逻辑,以便集中展示如何使用节点的标签和 nodeSelector 进行匹配。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐