K8S使用CRD和控制器简单应用

1. 定义 CRD(声明"要加什么标签")

首先,我们定义一个名为 PodLabeler 的自定义资源。用户提交这个资源后,控制器就会按照里面的规则去给 Pod 打标签。

yaml

复制代码
# podlabeler-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: podlabelers.custom.k8s.io
spec:
  group: custom.k8s.io
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                labelKey:
                  type: string
                  description: "要添加的标签键 (Key)"
                labelValue:
                  type: string
                  description: "要添加的标签值 (Value)"
                selector:
                  type: object
                  description: "匹配 Pod 的标签选择器"
                  properties:
                    matchLabels:
                      type: object
                      additionalProperties:
                        type: string
  scope: Namespaced
  names:
    plural: podlabelers
    singular: podlabeler
    kind: PodLabeler
    shortNames:
      - pl

2. 编写自定义控制器(Go 代码)

这是控制器的核心逻辑。它会监听 PodLabeler 的创建,然后去查找匹配的 Pod,并调用 Kubernetes API 给它们打标签。

go

复制代码
// controllers/podlabeler_controller.go
package controllers

import (
	"context"
	"fmt"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"
)

// PodLabelerReconciler 调和器
type PodLabelerReconciler struct {
	client.Client
}

// Reconcile 核心业务逻辑
func (r *PodLabelerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	log := log.FromContext(ctx)

	// 1. 获取用户创建的 PodLabeler 资源
	var labeler PodLabeler // 假设这是由 Kubebuilder 生成的 CRD 结构体
	if err := r.Get(ctx, req.NamespacedName, &labeler); err != nil {
		if errors.IsNotFound(err) {
			return ctrl.Result{}, nil // 资源被删除,忽略
		}
		return ctrl.Result{}, err
	}

	// 2. 根据 CRD 中的 selector 查找匹配的 Pod
	selector := labels.SelectorFromSet(labeler.Spec.Selector.MatchLabels)
	var podList corev1.PodList
	if err := r.List(ctx, &podList, &client.ListOptions{
		LabelSelector: selector,
		Namespace:     req.Namespace,
	}); err != nil {
		return ctrl.Result{}, err
	}

	// 3. 遍历找到的 Pod,并给它们打上标签
	for _, pod := range podList.Items {
		// 如果 Pod 已经有这个标签且值相同,则跳过
		if pod.Labels[labeler.Spec.LabelKey] == labeler.Spec.LabelValue {
			continue
		}

		// 构造 Patch 请求更新标签
		patch := client.MergeFrom(pod.DeepCopy())
		if pod.Labels == nil {
			pod.Labels = make(map[string]string)
		}
		pod.Labels[labeler.Spec.LabelKey] = labeler.Spec.LabelValue

		if err := r.Patch(ctx, &pod, patch); err != nil {
			log.Error(err, fmt.Sprintf("Failed to patch pod %s", pod.Name))
			return ctrl.Result{}, err
		}
		log.Info(fmt.Sprintf("Successfully labeled pod %s with %s=%s", pod.Name, labeler.Spec.LabelKey, labeler.Spec.LabelValue))
	}

	return ctrl.Result{}, nil
}

// SetupWithManager 注册控制器
func (r *PodLabelerReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&PodLabeler{}). // 监听 PodLabeler 资源的变化
		Owns(&corev1.Pod{}). // 可选:如果只想监听特定 Pod
		Complete(r)
}

3. 如何触发控制器工作?

将上述 CRD 部署到集群后,你只需要提交一个普通的 YAML 文件,控制器就会自动干活:

yaml

复制代码
# my-label-rule.yaml
apiVersion: custom.k8s.io/v1
kind: PodLabeler
metadata:
  name: add-env-tag
  namespace: default
spec:
  labelKey: "environment"
  labelValue: "production"
  selector:
    matchLabels:
      app: my-web-app  # 控制器只会给带有 app=my-web-app 的 Pod 打标签

执行 kubectl apply -f my-label-rule.yaml 后,控制器会立刻找到 default 命名空间下所有 app=my-web-app 的 Pod,并给它们加上 environment: production 标签。

相关推荐
笑洋仟3 分钟前
k8s的Ingress配置问题
云原生·容器·kubernetes
垚垚学技术_聚焦云原生9 分钟前
K8s OpenEBS LVM 动态存储 PVC Pending 排查记
云原生·容器·kubernetes
m0_646429979 小时前
Docker 完整核心知识点总结(超通俗易懂版)
运维·docker·容器
我不是阵雨12 小时前
微服务幂等性深度解剖
微服务·云原生·架构
吴声子夜歌12 小时前
Docker入门与实战——实战案例(Web服务与应用)
docker·容器
a59865213 小时前
Docker云手机搭建挂机环境,外网远程访问完整实操
docker·容器·智能手机·云手机
郭老二14 小时前
【docker】使用阿里云的容器镜像服务(ACR)构建自己的容器仓库
阿里云·docker·容器
code_slave(码畜)15 小时前
微服务架构落地:消息队列架构设计(上篇)——异步解耦、削峰填谷,看懂业务事件流转本质
spring boot·spring cloud·微服务·云原生·架构
code_slave(码畜)18 小时前
微服务架构落地:消息队列架构设计(下篇)——消息堆积、死信治理与集群监控告警实战
spring boot·spring cloud·微服务·云原生·中间件·架构
灯澜忆梦19 小时前
【docker】#2 | 基础命令
docker·容器·eureka