Skip to content

Clientset — 类型化客户端

概述

Clientset 是 client-go 中最常用的客户端,为每种 K8s 资源提供类型安全的 CRUD 操作。

初始化

go
import (
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
)

// 集群内(Pod 中运行)
config, err := rest.InClusterConfig()

// 集群外(本地开发)
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG"))

// 自定义配置
config := &rest.Config{
    Host:        "https://192.168.1.100:6443",
    BearerToken: "your-token",
    TLSClientConfig: rest.TLSClientConfig{
        CAFile: "/etc/kubernetes/pki/ca.crt",
    },
    QPS:   100,   // 每秒请求数限制
    Burst: 200,   // 突发请求数
}

clientset, err := kubernetes.NewForConfig(config)

CRUD 操作

go
ctx := context.Background()

// ===== Pod 操作 =====

// 列出 Pod
pods, err := clientset.CoreV1().Pods("default").List(ctx, metav1.ListOptions{
    LabelSelector: "app=nginx,env=prod",
    FieldSelector: "status.phase=Running",
    Limit:         100,
})

// 获取单个 Pod
pod, err := clientset.CoreV1().Pods("default").Get(ctx, "my-pod", metav1.GetOptions{})

// 创建 Pod
newPod := &corev1.Pod{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "my-pod",
        Namespace: "default",
        Labels:    map[string]string{"app": "my-app"},
    },
    Spec: corev1.PodSpec{
        Containers: []corev1.Container{
            {
                Name:  "app",
                Image: "nginx:1.25",
                Ports: []corev1.ContainerPort{{ContainerPort: 80}},
            },
        },
    },
}
createdPod, err := clientset.CoreV1().Pods("default").Create(ctx, newPod, metav1.CreateOptions{})

// 更新 Pod(需要先 Get,修改后 Update)
pod.Labels["version"] = "v2"
updatedPod, err := clientset.CoreV1().Pods("default").Update(ctx, pod, metav1.UpdateOptions{})

// Patch(局部更新,推荐)
patch := []byte(`{"metadata":{"labels":{"version":"v2"}}}`)
patchedPod, err := clientset.CoreV1().Pods("default").Patch(
    ctx, "my-pod",
    types.MergePatchType,
    patch,
    metav1.PatchOptions{},
)

// 删除 Pod
err = clientset.CoreV1().Pods("default").Delete(ctx, "my-pod", metav1.DeleteOptions{
    GracePeriodSeconds: pointer.Int64(0),  // 立即删除
})

// ===== Deployment 操作 =====

// 更新副本数(Scale)
scale, err := clientset.AppsV1().Deployments("default").GetScale(ctx, "my-app", metav1.GetOptions{})
scale.Spec.Replicas = 5
_, err = clientset.AppsV1().Deployments("default").UpdateScale(ctx, "my-app", scale, metav1.UpdateOptions{})

// 更新镜像(Strategic Merge Patch)
patch := `{"spec":{"template":{"spec":{"containers":[{"name":"app","image":"my-app:v2"}]}}}}`
_, err = clientset.AppsV1().Deployments("default").Patch(
    ctx, "my-app",
    types.StrategicMergePatchType,
    []byte(patch),
    metav1.PatchOptions{},
)

// ===== 子资源操作 =====

// 获取 Pod 日志
req := clientset.CoreV1().Pods("default").GetLogs("my-pod", &corev1.PodLogOptions{
    Container: "app",
    Follow:    false,
    TailLines: pointer.Int64(100),
})
stream, err := req.Stream(ctx)
defer stream.Close()
io.Copy(os.Stdout, stream)

// 执行命令(Exec)
req := clientset.CoreV1().RESTClient().Post().
    Resource("pods").
    Name("my-pod").
    Namespace("default").
    SubResource("exec").
    VersionedParams(&corev1.PodExecOptions{
        Command:   []string{"sh", "-c", "ls /"},
        Container: "app",
        Stdin:     false,
        Stdout:    true,
        Stderr:    true,
        TTY:       false,
    }, scheme.ParameterCodec)

exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
exec.StreamWithContext(ctx, remotecommand.StreamOptions{
    Stdout: os.Stdout,
    Stderr: os.Stderr,
})

分页列表

go
// 大量资源时使用分页,避免内存溢出
var continueToken string
for {
    pods, err := clientset.CoreV1().Pods("").List(ctx, metav1.ListOptions{
        Limit:    500,
        Continue: continueToken,
    })
    if err != nil {
        break
    }
    for _, pod := range pods.Items {
        // 处理 pod
    }
    if pods.Continue == "" {
        break
    }
    continueToken = pods.Continue
}

乐观锁更新

go
// 使用 ResourceVersion 防止并发冲突
for {
    deploy, err := clientset.AppsV1().Deployments("default").Get(ctx, "my-app", metav1.GetOptions{})
    if err != nil {
        return err
    }
    deploy.Spec.Replicas = pointer.Int32(5)
    _, err = clientset.AppsV1().Deployments("default").Update(ctx, deploy, metav1.UpdateOptions{})
    if errors.IsConflict(err) {
        continue  // 冲突则重试
    }
    return err
}

本站内容由 褚成志 整理编写,仅供学习参考