go, k8s

client-go 基本操作

基本操作包括Create创建,Update更新,Delete删除,List and Watch查询监听。下面分别介绍每个操作的代码实现。

环境:k8s 1.24.16,go 1.20,本地。
目录结构:

file

连接apiserver

这里使用Clientset作为客户端,把这个封装成一个文件。如果你要在服务器上测试,需要使用环境变量。

clientSet.go

package pvc

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

func GetClient() (*kubernetes.Clientset, error) {
    var kubeConfig = "E:\\client-go\\config"
    //kubeconfig := filepath.Join(
    //  os.Getenv("HOME"), ".kube", "config",
    //)
    config, err := clientcmd.BuildConfigFromFlags("", kubeConfig)
    if err != nil {
        log.Fatal(err)
    }
    clientSet, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Fatal(err)
    }
    return clientSet, nil
}

Create

部署带有pvc的nginx测试服务。

nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:stable-alpine
          volumeMounts:
            - name: nginx-storage
              mountPath: /usr/share/nginx/html
      volumes:
        - name: nginx-storage
          persistentVolumeClaim:
            claimName: nginx-pvc

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

这里不能写在一起,因为clientSet的CoreV1()方法不同,一个是Deployments,一个是PersistentVolumeClaims。

deploy.go

package pvc

import (
    "context"
    _ "embed"
    appsv1 "k8s.io/api/apps/v1"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/util/yaml"
    "k8s.io/client-go/kubernetes"
    "log"
    "os"
    "strings"
)

func CreatePVC(c *kubernetes.Clientset) {
    var pvcYaml = "E:\\client-go\\pvc\\deploy\\pvc.yaml"
    bytes, err := os.ReadFile(pvcYaml)
    if err != nil {
        log.Fatal(err)
    }
    pvc := corev1.PersistentVolumeClaim{}
    err = yaml.Unmarshal(bytes, &pvc)
    if err != nil {
        log.Fatal(err)
    }
    _, err = c.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), &pvc, metav1.CreateOptions{})
    if err != nil {
        log.Fatal(err)
    }
    log.Println("create pvc success")
}

//go:embed nginx.yaml
var nginxYaml string

func CreateDeploy(c *kubernetes.Clientset) {
    decode := yaml.NewYAMLOrJSONDecoder(strings.NewReader(nginxYaml), 100)
    deplyment := appsv1.Deployment{}
    err := decode.Decode(&deplyment)
    if err != nil {
        log.Fatal(err)
    }

    _, err = c.AppsV1().Deployments("default").Create(context.TODO(), &deplyment, metav1.CreateOptions{})
    if err != nil {
        log.Fatal(err)
    }
    log.Println("create deployment success")
}

通过//go:embed,可以方便地将文件内容嵌入到Go代码中,而无需在运行时读取外部文件。适用于go 1.16+。

这里使用了两种解析yaml文件的方法:一种是使用yaml.Unmarshal函数,另一种是使用yaml.NewYAMLOrJSONDecoder结合Decode方法。

  • yaml.Unmarshal函数:

    • 可以直接将YAML文件的内容解析为指定的结构体对象。
    • 适用于将整个YAML文件内容解析为单个结构体对象的情况。
    • 一次性将整个YAML文件内容解析为结构体对象,不支持逐行或逐段解析。
  • yaml.NewYAMLOrJSONDecoder结合Decode方法:

    • 可以逐行或逐段地解析YAML文件内容。
    • 可以更灵活地控制解析过程,适用于需要逐行或逐段处理YAML文件内容的情况。
    • 可以通过多次调用Decode方法来逐步解析YAML文件内容,而不是一次性解析整个文件。

根据具体的需求和场景,你可以选择使用适合的方法来解析YAML文件。如果只需要一次性将整个文件内容解析为结构体对象,可以使用yaml.Unmarshal函数;如果需要逐行或逐段地处理YAML文件内容,可以使用yaml.NewYAMLOrJSONDecoder结合Decode方法。

运行代码,输出如下:

file

file

List

查询pvc,使用ListOptions指定label,field,namespace selectors 来缩小pvc列表的范围,这个结果的返回类型是v1.PeristentVolumeClaimList。并使用模板输出。

给nginx deployment添加app=nginx的label。

kubectl patch deployment nginx -p '{"spec":{"template":{"metadata":{"labels":{"app":"nginx"}}}}}'

get.go

package pvc

import (
    "context"
    "flag"
    "fmt"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "log"
)

func GetDeploy(c *kubernetes.Clientset, ns string) {
    var labels string
    flag.StringVar(&labels, "labels", "app=nginx", "Label Selector")
    listOptions := metav1.ListOptions{
        LabelSelector: labels,
    }
    deploy, err := c.AppsV1().Deployments(ns).List(context.TODO(), listOptions)
    if err != nil {
        log.Fatal(err)
    }
    for _, deploy := range deploy.Items {
        fmt.Println(deploy.Name)
    }
}
func GetPVC(c *kubernetes.Clientset, ns string) {
    var label, field string
    flag.StringVar(&ns, "namespace", "default", "Namespace")
    flag.StringVar(&label, "label", "", "Label Selector")
    flag.StringVar(&field, "field", "", "Field Selector")

    listOptions := metav1.ListOptions{
        LabelSelector: label,
        FieldSelector: field,
    }
    pvc, err := c.CoreV1().PersistentVolumeClaims(ns).List(context.TODO(), listOptions)
    if err != nil {
        log.Fatal(err)
    }

    template := "%-16s%-8s%-8s\n"
    fmt.Printf(template, "NAME", "STATUS", "CAPACITY")
    for _, pvc := range pvc.Items {
        quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]
        fmt.Printf(template, pvc.Name, string(pvc.Status.Phase), quant.String())
    }
}

file

getPod.go

获取pod详细信息。

im

Delete

delete.go

package pvc

import (
    "context"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "log"
)

func DeleteDeploy(c *kubernetes.Clientset) {
    deployName := "nginx"
    err := c.AppsV1().Deployments("default").Delete(context.TODO(), deployName, metav1.DeleteOptions{})
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("delete deployment %s success\n", deployName)
}
func DeletePVC(c *kubernetes.Clientset) {
    pvcName := "nginx-pvc"
    err := c.CoreV1().PersistentVolumeClaims("default").Delete(context.TODO(), pvcName, metav1.DeleteOptions{})
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("delete pvc %s success\n", pvcName)
}

file

file

Update

修改deployment的副本数为2,并打印更新后的副本数。修改传递整数类型的值,通常会使用指针。

update.go

package pvc

import (
    "context"
    "fmt"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "log"
)

func Update(c *kubernetes.Clientset) {
    deployment, err := c.AppsV1().Deployments("default").Get(context.TODO(), "nginx", metav1.GetOptions{})
    if err != nil {
        log.Fatal(err)
    }

    replicas := int32(2)
    deployment.Spec.Replicas = &replicas
    updatedDeployment, err := c.AppsV1().Deployments("default").Update(context.TODO(), deployment, metav1.UpdateOptions{})
    if err != nil {
        log.Fatal(err)
    }
    log.Println("update deployment success")
    fmt.Printf("Nginx Deployment replicas updated to: %d\n", *updatedDeployment.Spec.Replicas)
}

file

file

Watch

创建一个监听器watcher,监听事件类型,处理pvc的添加,删除,更新事件,设置总的最大quota为20G,在触发对应事件后,代码做对应处理。使用watcher.ResultChan实现通道,在添加删除时加锁保证安全,pvc的结构体使用sync.map实现。

watch.go

package pvc

import (
    "context"
    "fmt"
    v1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/resource"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/watch"
    "k8s.io/client-go/kubernetes"
    "log"
    "sync"
)

var (
    totalQuota resource.Quantity
    maxQuota   = resource.MustParse("20Gi")
    lock       sync.RWMutex
    pvcMap     sync.Map
)

func Watch(c *kubernetes.Clientset) {
    watcher, err := c.CoreV1().PersistentVolumeClaims("default").Watch(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }
    defer watcher.Stop()

    for event := range watcher.ResultChan() {
        pvc, ok := event.Object.(*v1.PersistentVolumeClaim)
        if !ok {
            log.Fatal("unexpected type")
        }

        switch event.Type {
        case watch.Added:
            addHandler(pvc)
        case watch.Modified:
            modifyHandler(pvc)
        case watch.Deleted:
            deleteHandler(pvc)
        }
    }
}

func addHandler(pvc *v1.PersistentVolumeClaim) {
    lock.Lock()
    defer lock.Unlock()

    quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]
    totalQuota.Add(quant)

    if totalQuota.Cmp(maxQuota) == 1 {
        log.Printf("Cannot add PVC: %s, would exceed quota %s\n", pvc.Name, maxQuota.String())
    } else {
        log.Printf("PVC %s added, totalQuota: %s\n", pvc.Name, totalQuota.String())
    }
    pvcMap.Store(pvc.Name, pvc)
}

func modifyHandler(pvc *v1.PersistentVolumeClaim) {
    fmt.Printf("PVC %s modified\n", pvc.Name)
}

func deleteHandler(pvc *v1.PersistentVolumeClaim) {
    lock.Lock()
    defer lock.Unlock()

    if _, ok := pvcMap.Load(pvc.Name); ok {
        quant := pvc.Spec.Resources.Requests[v1.ResourceStorage]
        totalQuota.Sub(quant)
        pvcMap.Delete(pvc.Name)
        log.Printf("PVC %s deleted, totalQuota: %s\n", pvc.Name, totalQuota.String())
    }
}

代码运行结果如下:

file

file

为什么使用sync.Map

请参考这里

Cmp

CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the quantity is greater than y.

x.Cmp(y),如果x < y,返回-1,如果x = y,返回0,如果x > y,返回1。

Informer

下面的代码是一个使用Informer实现的PVC存储配额管理示例。

package pvc

import (
    "context"
    "fmt"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/informers"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/cache"
    "log"
    "sync"
    "time"
)

var (
// 存储PVC的总存储量,key为"total",value为int64类型。
    PVCMap sync.Map
    rwLock sync.RWMutex
)

const maxQuotaGB = 20 // 20Gi

func CreateInformer(c *kubernetes.Clientset) {
    // 在启动informer之前计算已有PVCs的总存储量
    getPVCStorageUsage(c)
    // 创建SharedInformerFactory
    factory := informers.NewSharedInformerFactoryWithOptions(c, 0, informers.WithNamespace("default"))
    pvcInformer := factory.Core().V1().PersistentVolumeClaims().Informer()
    informerStartTime := metav1.NewTime(time.Now())

    // 设置事件处理器
    _, err := pvcInformer.AddEventHandler(
        cache.ResourceEventHandlerFuncs{
            AddFunc: func(obj interface{}) {
                pvc := obj.(*v1.PersistentVolumeClaim)
                // 去掉创建时间早于informer启动时间的PVC,即只有informer启动后的ADD事件才触发
                if pvc.CreationTimestamp.Before(&informerStartTime) {
                    return
                }
                StorageUsage(pvc, true)
                //fmt.Println("PVC added")
            },
            UpdateFunc: func(oldObj, newObj interface{}) {
                oldPvc := oldObj.(*v1.PersistentVolumeClaim)
                newPvc := newObj.(*v1.PersistentVolumeClaim)
                updatetorageUsage(oldPvc, newPvc)
            },
            DeleteFunc: func(obj interface{}) {
                pvc := obj.(*v1.PersistentVolumeClaim)
                StorageUsage(pvc, false)
                //fmt.Println("PVC deleted")
            },
        },
    )
    if err != nil {
        log.Fatal(err)
    }

    // 启动informer
    stopCh := make(chan struct{})
    defer close(stopCh)
    factory.Start(stopCh)
    //factory.WaitForCacheSync(stopCh)
    // 等待Informer同步。这个函数会阻塞,直到所有的Informer都同步完成,或者stopCh被关闭。
    if !cache.WaitForCacheSync(stopCh, pvcInformer.HasSynced) {
        log.Fatal("Timed out waiting for caches to sync")
    }

    // 保持主goroutine运行
    select {}
}

// getPVCStorageUsage 用于计算已有PVC的存储量,并将其存储在PVCMap中。
func getPVCStorageUsage(c *kubernetes.Clientset) {
    pvcs, err := c.CoreV1().PersistentVolumeClaims("default").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }

    var total int64
    for _, pvc := range pvcs.Items {
        quantity := pvc.Spec.Resources.Requests[v1.ResourceStorage]
        quantityGB, _ := quantity.AsInt64()
        total += quantityGB
    }

    PVCMap.Store("total", total)
    fmt.Printf("Initial total storage usage: %d GiB\n", total/1024/1024/1024)
}

// StorageUsage 用于更新PVC的存储使用情况。根据add参数判断是添加PVC还是删除PVC,然后根据PVC请求的存储大小来更新当前总使用量,并将其存储到PVCMap中。
func StorageUsage(pvc *v1.PersistentVolumeClaim, add bool) {
    rwLock.Lock()
    defer rwLock.Unlock()

    // 获取PVC请求的存储大小
    quota := pvc.Spec.Resources.Requests[v1.ResourceStorage]
    quotaGB, _ := quota.AsInt64()
    //fmt.Printf("quotaGB: %d GiB\n", quotaGB/1024/1024/1024)

    // 从sync.Map获取当前总使用量
    total, _ := PVCMap.LoadOrStore("total", 0)
    currentTotal := total.(int64)
    //fmt.Printf("current total storage usage: %d GiB\n", currentTotal/1024/1024/1024)

    if add {
    // 如果超出最大容量,打印告警日志
        if (currentTotal+quotaGB)/1024/1024/1024 > maxQuotaGB {
            currentTotal += quotaGB
            PVCMap.Store("total", currentTotal)
            fmt.Printf("PVC %s added, would exceed quota %d GiB, current total storage usage: %d GiB\n", pvc.Name, maxQuotaGB, currentTotal/1024/1024/1024)
        } else {
            currentTotal += quotaGB
            PVCMap.Store("total", currentTotal)
            fmt.Printf("PVC %s added, current total storage usage: %d GiB\n", pvc.Name, currentTotal/1024/1024/1024)
        }
    } else {
        currentTotal -= quotaGB
        PVCMap.Store("total", currentTotal)
        fmt.Printf("PVC %s deleted, current total storage usage: %d GiB\n", pvc.Name, currentTotal/1024/1024/1024)
    }

    fmt.Printf("current total storage usage: %d GiB\n", currentTotal/1024/1024/1024)
}

// updatetorageUsage 函数用于在PVC更新时更新存储使用情况。它会比较PVC的旧存储大小和新存储大小,如果不相等,则通过读写锁更新当前总使用量,并将其存储到PVCMap中。
func updatetorageUsage(oldPvc, newPvc *v1.PersistentVolumeClaim) {
    oldQuantity := oldPvc.Spec.Resources.Requests[v1.ResourceStorage]
    newQuantity := newPvc.Spec.Resources.Requests[v1.ResourceStorage]

    oldSizeInGiB, _ := oldQuantity.AsInt64()
    newSizeInGiB, _ := newQuantity.AsInt64()

    if oldSizeInGiB != newSizeInGiB {
        rwLock.Lock()
        defer rwLock.Unlock()

        total, _ := PVCMap.Load("total")
        totalGB := total.(int64)
        totalGB = totalGB - oldSizeInGiB + newSizeInGiB

        PVCMap.Store("total", totalGB)
        fmt.Printf("Updated total storage usage after PVC update: %d GiB\n", totalGB/1024/1024/1024)
    }
}

file

file

1.informer启动前已有的pvc会触发ADD事件
这个通过添加informer启动时间,判断pvc创建时间是否大于该时间解决。if pvc.CreationTimestamp.Before(&informerStartTime)
2.创建pvc后要控制台没有打印added日志
我在多次测试启动informer后,每次创建pvc时,都要等10秒左右,控制台才能打印出added日志,最开始我以为没有同步完成,我添加了cache.WaitForCacheSync,检测是否同步完成。但是添加之后问题依旧。上面已经判断了pvc的创建时间,pvc也已经创建成功了,并且是在default namespace下。最后对比本地电脑的时间和服务器时间,发现相差了10秒。问题解决....

Exec

execOne.go

进入单个pod执行命令。

package pvc

import (
    "context"
    v1 "k8s.io/api/core/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/kubernetes/scheme"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/tools/remotecommand"
    "log"
    "os"
)

func ExceOne(c *kubernetes.Clientset) {
    cmd := []string{"ls", "-l", "/etc/nginx/nginx.conf"}

    request := c.CoreV1().RESTClient().Post().
        Resource("pods").
        Namespace("default").
        Name("nginx-6945b88ffd-wb2hz").
        SubResource("exec").
        VersionedParams(&v1.PodExecOptions{
            Container: "nginx",
            Command:   cmd,
            Stdin:     false,
            Stdout:    true,
            Stderr:    true,
            TTY:       false,
        }, scheme.ParameterCodec)

    var kubeConfig = "E:\\client-go\\config"

    config, err := clientcmd.BuildConfigFromFlags("", kubeConfig)
    if err != nil {
        log.Fatal(err)
    }

    exec, err := remotecommand.NewSPDYExecutor(config, "POST", request.URL())
    if err != nil {
        log.Fatal(err)
    }

    err = exec.StreamWithContext(context.TODO(), remotecommand.StreamOptions{
        //Stdin:  os.Stdin,
        Stdout: os.Stdout,
        Stderr: os.Stderr,
    })
    if err != nil {
        log.Fatal(err)
    }
}

涉及到的几个字段:

func (r *Request) VersionedParams(obj runtime.Object, codec runtime.ParameterCodec) *Request
# VersionedParams 将获取提供的对象,使用隐式 RESTClient API 版本和默认参数编解码器将其序列化为 map[string][]string,然后将它们作为参数添加到请求中。使用它来提供客户端库中的版本化查询参数。

var ParameterCodec runtime.ParameterCodec = runtime.NewParameterCodec(Scheme)
# scheme 是用来处理版本化的资源和API操作的。当你需要与apiserver交互,尤其是需要指定资源版本或执行特定版本的操作时,scheme 提供了必要的编解码器。scheme.ParameterCodec 用于编码 v1.PodExecOptions 到请求参数中。

func NewSPDYExecutor(config *restclient.Config, method string, url *url.URL) (Executor, error)
# NewSPDYExecutor 是用来创建一个执行器(Executor),该执行器能够通过 SPDY 协议与apiserver通信。SPDY 是一种由Google开发的网络传输协议,它被设计来传输Web内容,并优化性能。在Kubernetes中,SPDY 协议被用于支持如 exec、attach、port-forward 等操作的实时流。

func (Executor) StreamWithContext(ctx context.Context, options StreamOptions) error
# StreamWithContext 方法用于在给定的上下文中启动流式传输。这个方法允许你指定输入/输出流,以便可以实时地发送命令到Pod并接收输出。这对于执行需要实时交互的命令非常有用。

file

execMutli.go

进入多个pod执行命令。

package pvc

import (
    "context"
    "fmt"
    v1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/kubernetes/scheme"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/tools/remotecommand"
    "log"
    "os"
    "sync"
)

func ExceMulti(c *kubernetes.Clientset) {
    var kubeConfig = "E:\\client-go\\config"

    config, err := clientcmd.BuildConfigFromFlags("", kubeConfig)
    if err != nil {
        log.Fatal(err)
    }

    pods, err := c.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatal(err)
    }

    var wg sync.WaitGroup

    for _, pod := range pods.Items {
        wg.Add(1)
        go func(pod v1.Pod) {
            defer wg.Done()
            fmt.Printf("Executing command on pod: %s\n", pod.Name)
            cmd := []string{"hostname"}
            req := c.CoreV1().RESTClient().Post().
                Resource("pods").
                Namespace("default").
                Name(pod.Name).
                SubResource("exec").
                VersionedParams(&v1.PodExecOptions{
                    Command: cmd,
                    Stdin:   false,
                    Stdout:  true,
                    Stderr:  true,
                    TTY:     false,
                }, scheme.ParameterCodec)
            //fmt.Printf("req: %s\n", req.URL())

            exec, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
            if err != nil {
                log.Fatal(err)
            }
            err = exec.StreamWithContext(context.TODO(), remotecommand.StreamOptions{
                Stdout: os.Stdout,
                Stderr: os.Stderr,
            })
            if err != nil {
                log.Fatal(err)
            }
        }(pod)
    }

    wg.Wait()
}

其中request.URL()格式是:
https://ip:6443/api/v1/namespaces/default/pods/nginx-6945b88ffd-wb2hz/exec?command=echo&command=hello%2Cworld&stderr=true&stdout=true

file

main.go

package main

import (
    "fmt"
    client "pvc/client"
    exe "pvc/exec"
)

func main() {
    clientSet, err := client.GetClient()
    if err != nil {
        fmt.Printf("failed to get clientset: %v", err)
    }
    //dynamicClient, err := client.DynamicClient()
    //if err != nil {
    //  fmt.Printf("failed to get dynamic client: %v", err)
    //}
    //fmt.Println("Create PersistentVolumeClaim:")
    //deploy.CreatePVC(clientSet)
    //fmt.Println("Create Deployment:")
    //deploy.CreateDeploy(clientSet)
    //var ns = "default"
    //fmt.Println("List Deployments:")
    //get.GetDeploy(client, ns)
    //fmt.Println("List PersistentVolumeClaims:")
    //get.GetPVC(clientSet, ns)
    //get.GetPod(clientSet)
    //fmt.Println("Delete Deployment:")
    //delete.DeleteDeploy(clientSet)
    //fmt.Println("Delete PersistentVolumeClaim:")
    //delete.DeletePVC(clientSet)
    //fmt.Println("Update Deployment:")
    //update.Update(clientSet)
    //watch.Watch(clientSet)
    //watch.CreateInformer(clientSet)
    //exe.ExceOne(clientSet)
    exe.ExceMulti(clientSet)
}

常用api操作

pod

//声明pod对象
var pod *v1.Pod
//创建pod
pod, err := clientset.CoreV1().Pods(<namespace>).Create(<pod>)
//更新pod
pod, err := clientset.CoreV1().Pods(<namespace>).Update(<pod>)
//删除pod
err := clientset.CoreV1().Pods(<namespace>).Delete(<pod.Name>, &meta_v1.DeleteOptions{})
//查询pod
pod, err := clientset.CoreV1().Pods(<namespace>).Get(<pod.Name>, meta_v1.GetOptions{})
//列出pod
podList, err := clientset.CoreV1().Pods(<namespace>).List(&meta_v1.ListOptions{})
//watch pod
watchInterface, err := clientset.CoreV1().Pods(<namespace>).Watch(&meta_v1.ListOptions{})

svc

//声明service对象
var service *v1.Service
//构造service对象
//创建service
service, err := clientset.CoreV1().Services(<namespace>).Create(<service>)
//更新service
service, err := clientset.CoreV1().Services(<namespace>).Update(<service>)
//删除service
err := clientset.CoreV1().Services(<namespace>).Delete(<service.Name>, &meta_v1.DeleteOptions{})
//查询service
service, err := clientset.CoreV1().Services(<namespace>).Get(<service.Name>, meta_v1.GetOptions{})
//列出service
serviceList, err := clientset.CoreV1().Services(<namespace>).List(&meta_v1.ListOptions{})
//watch service
watchInterface, err := clientset.CoreV1().Services(<namespace>).Watch(&meta_v1.ListOptions{})

deployment

//声明deployment对象
var deployment *v1beta1.Deployment
//构造deployment对象
//创建deployment
deployment, err := clientset.AppsV1beta1().Deployments(<namespace>).Create(<deployment>)
//更新deployment
deployment, err := clientset.AppsV1beta1().Deployments(<namespace>).Update(<deployment>)
//删除deployment
err := clientset.AppsV1beta1().Deployments(<namespace>).Delete(<deployment.Name>, &meta_v1.DeleteOptions{})
//查询deployment
deployment, err := clientset.AppsV1beta1().Deployments(<namespace>).Get(<deployment.Name>, meta_v1.GetOptions{})
//列出deployment
deploymentList, err := clientset.AppsV1beta1().Deployments(<namespace>).List(&meta_v1.ListOptions{})
//watch deployment
watchInterface, err := clientset.AppsV1beta1().Deployments(<namespace>).Watch(&meta_v1.ListOptions{})
0 0 投票数
文章评分
订阅评论
提醒
guest

2 评论
最旧
最新 最多投票
内联反馈
查看所有评论
夏含xx
夏含xx
2 月 前

请问我在window上执行exec.StreamWithContext会有unable to upgrade connection: you must specify at least 1 of stdin, stdout, stderr报错是怎么回事

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x