1 准备

# go 代码中
go mod init go-k8s-namespace
# 添加指定版本
go get k8s.io/client-go@v0.23.17
go get k8s.io/api@v0.23.17
go get k8s.io/apimachinery@v0.23.17

# 找到client-go的例子, 这里我们用out-of-cluster,因为我是在自己的主机上连接虚拟机里的k8s集群
client-go/examples/out-of-cluster-client-configuration

2 样例

package main

import (
    "context"
    "flag"
    "fmt"
    "path/filepath"

    // corev1 "k8s.io/api/core/v1"

    // corev1 "k8s.io/api/core/v1"

    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    // storagev1 "k8s.io/api/storage/v1"
    // storagev1 "k8s.io/api/storage/v1"
    // storagev1 "k8s.io/api/storage/v1"
    //
    // Uncomment to load all auth plugins
    // _ "k8s.io/client-go/plugin/pkg/client/auth"
    //
    // Or uncomment to load specific auth plugins
    // _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
    // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
    // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
    // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
)

func main() {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        // ~/.kube/config 确保你家目录下有k8s的配置文件
        // 你本地可以用kubectl get po 进行查询.
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    // 使用指定的kubeconfig文件创建一个Config对象
    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    // 创建一个新的Kubernetes客户端
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    // k get po -A
    pods, err := clientset.
        CoreV1().
        Pods(""). // Pods(namespace) "" 表示所有命名空间
        List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        panic(err.Error())
    }
    fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))

    // 错误处理
    namespace := "default"
    podName := "pod-vol-empty-dir"
    pod, err := clientset.
        CoreV1().
        Pods(namespace). // 传递命名空间
        Get(context.TODO(), podName, metav1.GetOptions{})

    if errors.IsNotFound(err) { // 使用k8s apimachinery的errors包 ,这里表示 没有找到 这个pod
        fmt.Printf("Pod %s in namespace %s not found\n", podName, namespace)
    } else if statusError, isStatus := err.(*errors.StatusError); isStatus {
        fmt.Printf("Error getting pod %s in namespace %s: %v\n",
            podName, namespace, statusError.ErrStatus.Message)
    } else if err != nil {
        panic(err.Error())
    } else {
        fmt.Printf("Found pod %s in namespace %s\n", podName, namespace)
        fmt.Println(pod.TypeMeta)
        fmt.Println(pod.ObjectMeta.Name)
        fmt.Println(pod.Spec.NodeName)
        fmt.Println(pod.Status.PodIP)
    }

}

3 pod

pods, err := clientset.
    CoreV1().
    Pods(""). // Pods(namespace) "" 表示所有命名空间
    List(context.TODO(), metav1.ListOptions{})
fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
使用ResourceVersion
pods, err := clientset.
    CoreV1().
    Pods("default").
    List(context.TODO(),
        metav1.ListOptions{
            ResourceVersion: "2802779",
            // 注意使用limit 和去掉的效果
            Limit:           50,
        })
if err != nil {
    panic(err.Error())
}
for _, item := range pods.Items {
    fmt.Println(item.Labels)
}

配合文档 resourceVersion #### detail

namespace := "default"
podName := "pod-vol-empty-dir"
pod, err := clientset.
    CoreV1().
    Pods(namespace). // 传递命名空间
    Get(context.TODO(), podName, metav1.GetOptions{})
fmt.Println(pod.TypeMeta)
fmt.Println(pod.ObjectMeta.Name)
fmt.Println(pod.Spec.NodeName)
fmt.Println(pod.Status.PodIP)
Tip

可是在创建的使用先用DryRun ,看是否有错误.
实际工作中, 先判断是否有这个pod等等.

import (
    corev1 "k8s.io/api/core/v1"
)
//.....
// 创建一个Pod对象
pod1 := &corev1.Pod{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "my-pod",
        Namespace: "default",
    },
    Spec: corev1.PodSpec{
        Containers: []corev1.Container{
            {
                Name:  "my-container",
                Image: "nginx:1.14.2",
                // Lifecycle: &corev1.Lifecycle{
                //     PreStop: &corev1.LifecycleHandler{
                //         Exec: &corev1.ExecAction{
                //             Command: []string{
                //                 "/bin/sh",
                //                 "-c",
                //                 "sleep 20",
                //             },
                //         },
                //     },
                // },
            },
        },
    },
}

// 使用客户端创建Pod
createdPod, err := clientset.
    CoreV1().
    Pods("default").
    Create(context.TODO(),
        pod1,
        metav1.CreateOptions{
            DryRun: []string{metav1.DryRunAll}, // 相当于命令行执行 带上--dry-run=client
        })
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Created Pod: %s\n", createdPod.Name)
Warning

update操作只能更新一些属性, 你提交了很多属性要修改, 会报错.
可以先删除,再创建

pod1 := &corev1.Pod{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "my-pod",
        Namespace: "default",
    },
    Spec: corev1.PodSpec{
        Containers: []corev1.Container{
            {
                Name:  "my-container",
                Image: "nginx:1.14.2",
                Lifecycle: &corev1.Lifecycle{
                    PreStop: &corev1.LifecycleHandler{
                        Exec: &corev1.ExecAction{
                            Command: []string{
                                "/bin/sh",
                                "-c",
                                "sleep 20",
                            },
                        },
                    },
                },
            },
        },
    },
}

_, err = clientset.CoreV1().Pods("default").Update(
        context.TODO(),
        pod1,
        metav1.UpdateOptions{})
if err != nil {
    //pod updates may not change fields other than `spec.containers[*].image`, `spec.initContainers[*].image`, `spec.activeDeadlineSeconds`, `spec.tolerations` (only additions to existing tolerations) or `spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)
    log.Fatal(err) 
}
几种类型的区别

todo

StrategicMergePatchType
patchBytes := []byte(`{"metadata":{"labels":{"app":"nginx2","run":"test"}}}`)
// patch := make(map[string]interface{})
// patch["metadata"] = map[string]interface{}{
//  "labels": map[string]interface{}{
//      "app": "nginx",
//      "run": "test",
//  },
// }
// patchBytes, err := json.Marshal(patch)
_, err = clientset.CoreV1().Pods("default").Patch(
    context.TODO(),
    "my-pod",
    // 属性相同 就更新, 没有的当然是增加
    types.StrategicMergePatchType,
    patchBytes,
    metav1.PatchOptions{})
err = clientset.
        CoreV1().
        Pods("default").
        Delete(context.TODO(), "my-pod", metav1.DeleteOptions{})
curl localhost:8001/api/v1/namespaces/default/pods?watch

看看etcd的版本监听

package main

import (
    "context"
    "flag"
    "fmt"
    "log"
    "path/filepath"
    "time"

    corev1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/watch"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    //
    // Uncomment to load all auth plugins
    // _ "k8s.io/client-go/plugin/pkg/client/auth"
    //
    // Or uncomment to load specific auth plugins
    // _ "k8s.io/client-go/plugin/pkg/client/auth/azure"
    // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
    // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
    // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack"
)

func main() {
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    // 使用指定的kubeconfig文件创建一个Config对象
    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    // 创建一个新的Kubernetes客户端
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    // 创建一个Pod对象
    pod1 := &corev1.Pod{
        ObjectMeta: metav1.ObjectMeta{
            Name:      "my-pod",
            Namespace: "default",
            Labels: map[string]string{
                "app": "pod-vol",
                "run": "test",
            },
        },
        Spec: corev1.PodSpec{
            Containers: []corev1.Container{
                {
                    Name:  "my-container",
                    Image: "nginx:1.14.2",
                    Lifecycle: &corev1.Lifecycle{
                        PreStop: &corev1.LifecycleHandler{
                            Exec: &corev1.ExecAction{
                                Command: []string{
                                    "/bin/sh",
                                    "-c",
                                    "sleep 20",
                                },
                            },
                        },
                    },
                },
            },
        },
    }
    // 使用客户端创建Pod
    createdPod, err := clientset.
        CoreV1().
        Pods("default").
        Create(context.TODO(),
            pod1,
            metav1.CreateOptions{
                // DryRun: []string{metav1.DryRunAll}, // 相当于命令行执行 带上--dry-run=client
            })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("ok: %s\n", createdPod.Name)
    // 等待一会,不急着做删除操作, 命令行 k get po 看看
    time.Sleep(10 * time.Second)

    err = clientset.
        CoreV1().
        Pods("default").Delete(context.TODO(), "my-pod", metav1.DeleteOptions{
        // DryRun: []string{metav1.DryRunAll},
    })
    if err != nil {
        log.Fatal(err)
    }

    // 该Watcher将监听指定命名空间中的所有Pod对象的事件。
    // 如果创建Watcher成功,它将返回一个watch.Interface对象和一个错误。
    watcher, err := clientset.CoreV1().Pods("default").Watch(context.TODO(), metav1.ListOptions{
        LabelSelector: "app=pod-vol,run=test",
    })
    if err != nil {
        log.Fatal(err)
    }

    started := time.Now()
Loop:
    for {
        select {
            //watcher.ResultChan() 通道将传递Watcher接收到的事件
        case event := <-watcher.ResultChan():
            pod, ok := event.Object.(*corev1.Pod)
            if !ok {
                fmt.Println("xxxx::", pod)
                continue
            }
            // 我们获取watcher 用的是labels 选择器, 可能有不同的pod
            // 这里可以增加判断看是不是你想要处理的那个pod
            fmt.Println(pod.Name)
            if pod.Name != "my-pod" {
                continue
            }
            switch event.Type {
            case watch.Added:
                fmt.Printf("Pod added: %s\n", event.Object)
                // 处理Pod添加事件
            case watch.Modified:
                fmt.Printf("Pod modified: %s\n", event.Object)
                // 处理Pod修改事件
            case watch.Deleted:
                fmt.Printf("Pod deleted: %s\n", pod.Name)
                // 差不多20s,因为我们容器preStop sleep 20s
                fmt.Println("duration:", time.Since(started))
                // 处理Pod删除事件
                // 如果想在这里 (逻辑是 看删除了, 然后创建pod) ,那么你应该在前面增加一次判断,
                // 查询pod看是否这个pod 已经不存在了. 因为有可能你执行watch 时 ,pod 已经删除了, 那么你永远都不会走到这了.

            }
        case <-time.After(60 * time.Second):
            fmt.Println(9999)
            break Loop
        }
    }

    // DryRun: []string{metav1.DryRunAll}, // 相当于命令行执行 带上--dry-run=client

}

4 namespace

list, err := clientset.
    CoreV1().
    Namespaces().
    List(context.TODO(), metav1.ListOptions{})
for _, item := range list.Items {
    fmt.Println(item.Name)
    fmt.Println(item.CreationTimestamp)
    fmt.Println(string(item.Status.Phase))
}

5 scheduler

list, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
if err != nil {
    panic(err.Error())
}
for _, item := range list.Items {
    fmt.Println(item.ObjectMeta.Name)
    fmt.Println(item.ObjectMeta.Labels)
    fmt.Println(item.TypeMeta)
    // fmt.Println(item.Spec.Taints)
    for _, v := range item.Spec.Taints {
        fmt.Println(v.Key, "=", v.Value, ":", v.Effect)
    }
    // node 状态
    for _, v := range item.Status.Conditions {
        fmt.Println(v.Type, v.Status, v.Reason)
    }
}
detail, err := clientset.CoreV1().Nodes().Get(context.TODO(), "node1", metav1.GetOptions{})
if err != nil {
    panic(err.Error())
}
fmt.Println(detail.ObjectMeta.Name)
fmt.Println(detail.ObjectMeta.Labels)
fmt.Println(detail.TypeMeta)
for _, v := range detail.Spec.Taints {
    fmt.Println(v.Key, "=", v.Value, ":", v.Effect)
}
for _, v := range detail.Status.Conditions {
    fmt.Println(v.Type, v.Status, v.Reason)
}
Tip

可以先获取node的label 然后有update的方式来更新.

patchData := []byte(`{"metadata":{"labels":{"app":"test"}}}`)

// 执行Patch操作, 有则更新, 无则添加
_, err := clientset.
    CoreV1().
    Nodes().
    Patch(context.TODO(), "node1", types.MergePatchType, patchData, metav1.PatchOptions{})
if err != nil {
    panic(err.Error())
}
// null 没有引号, 当然我们应该用map ,然后 json.Marshal来...
patchData := []byte(`{"metadata":{"labels":{"app1":null}}}`)

// 执行Patch操作
updatedNode, err := clientset.
    CoreV1().
    Nodes().
    Patch(context.TODO(), "node1",
        types.StrategicMergePatchType,
        patchData, metav1.PatchOptions{})
if err != nil {
    panic(err.Error())
}
// 创建要设置的污点数据,
taints := []corev1.Taint{
    {
        Key:    "hello",
        Value:  "world",
        Effect: corev1.TaintEffectNoSchedule,
    },
}
// 如果想要在原来的污点上 增加, 可以先获取节点的污点,然后...
// k get no node1 -o yaml 可以看到节点的属性 spec.taints
patchData, _ := json.Marshal(map[string]interface{}{
    "spec": map[string]interface{}{
        "taints": taints, //  这样写会覆盖原来已有的污点
    },
})

// 执行Patch操作
_, err = clientset.
    CoreV1().
    Nodes().
    Patch(context.TODO(),
        "node1",
        types.MergePatchType,
        patchData,
        metav1.PatchOptions{})
if err != nil {
    panic(err.Error())
}

6 pv

pvList, err := clientset.
    CoreV1().
    PersistentVolumes().
    List(context.TODO(), metav1.ListOptions{})
if err != nil {
    panic(err.Error())
}

// 遍历 PV 列表
for _, pv := range pvList.Items {
    fmt.Println(pv.ObjectMeta.Name)
    fmt.Println(pv.Spec.StorageClassName)
    fmt.Println(pv.Status.Phase)
}
// 创建持久卷
// 仅作为pvc 选择pv 用
storageClassName := "abc-no-defined-name"
pv := &corev1.PersistentVolume{
    ObjectMeta: metav1.ObjectMeta{
        Name: "pv-client-go",
        // Labels: map[string]string{
        //  "run": "pv",
        // },
    },
    Spec: corev1.PersistentVolumeSpec{
        Capacity: corev1.ResourceList{
            corev1.ResourceStorage: resource.MustParse("300Mi"),
        },
        AccessModes: []corev1.PersistentVolumeAccessMode{
            corev1.ReadWriteOnce,
        },
        PersistentVolumeReclaimPolicy: corev1.PersistentVolumeReclaimRetain,
        StorageClassName:              storageClassName,
        // 这里我用NFS
        PersistentVolumeSource: corev1.PersistentVolumeSource{
            NFS: &corev1.NFSVolumeSource{
                Server:   "102.168.66.110",
                Path:     "/data/nfs",
                ReadOnly: false,
            },
        },
    },
}
_, err = clientset.
    CoreV1().
    PersistentVolumes(). //pv 没有namespace概念
    Create(context.TODO(), pv, metav1.CreateOptions{})
if err != nil {
    panic(err.Error())
}

7 PVC

// 获取 PVC 列表
pvcList, err := clientset.
    CoreV1().
    PersistentVolumeClaims("default").
    List(context.TODO(), metav1.ListOptions{})
if err != nil {
    panic(err.Error())
}

// 遍历 PVC 列表
for _, pvc := range pvcList.Items {
    fmt.Println(pvc.ObjectMeta.Name)
    fmt.Println(pvc.Spec.VolumeName)
    fmt.Println(pvc.Status.Phase)
}
// 创建pvc
storageClassName := "abc-no-defined-name"
pvc := &corev1.PersistentVolumeClaim{
    ObjectMeta: metav1.ObjectMeta{
        Name: "pvc-client-go",
    },
    Spec: corev1.PersistentVolumeClaimSpec{
        AccessModes: []corev1.PersistentVolumeAccessMode{
            corev1.ReadWriteOnce,
        },
        Resources: corev1.ResourceRequirements{
            Requests: corev1.ResourceList{
                corev1.ResourceStorage: resource.MustParse("220Mi"),
            },
        },
        StorageClassName: &storageClassName,
        // Selector: &metav1.LabelSelector{
        //  MatchLabels: map[string]string{
        //      "run": "pv",
        //  },
        // },
    },
}
_, err = clientset.
    CoreV1().
    PersistentVolumeClaims("default").
    Create(context.TODO(), pvc, metav1.CreateOptions{})
if err != nil {
    panic(err.Error())
}

8 SC

import (
    "k8s.io/utils/pointer"

    storagev1 "k8s.io/api/storage/v1"
    // ....
)

volumeBindingImmediate := storagev1.VolumeBindingImmediate
sc := &storagev1.StorageClass{
    ObjectMeta: metav1.ObjectMeta{
        Name: "sc-01-tmp",
    },
    Provisioner:          "example-nfs2", // 替换为你的存储提供商的 Provisioner
    VolumeBindingMode:    &volumeBindingImmediate,
    AllowVolumeExpansion: pointer.BoolPtr(true),
}

createdSC, err := clientset.
    StorageV1().
    StorageClasses().
    Create(context.TODO(), sc, metav1.CreateOptions{})
if err != nil {
    panic(err.Error())
}
fmt.Printf("OK: %s\n", createdSC.Name)
//  获取 StorageClass 列表
storageClasses, _ := clientset.
    StorageV1().
    StorageClasses().
    List(context.TODO(), metav1.ListOptions{})

// 遍历 StorageClass 列表
for _, sc := range storageClasses.Items {
    fmt.Println(sc.Name)
    fmt.Println(sc.Provisioner)
    fmt.Println(sc.Parameters)
    fmt.Println(*sc.ReclaimPolicy)
    fmt.Println("is-default-class: ", sc.Annotations["storageclass.kubernetes.io/is-default-class"] == "true")
}
serverVersion, err := clientset.Discovery().ServerVersion()
if err != nil {
    panic(err)
}
majorVersion, _ := strconv.Atoi(serverVersion.Major)
minorVersion, _ := strconv.Atoi(serverVersion.Minor)
if majorVersion < 1 || (majorVersion == 1 && minorVersion < 14) {
    fmt.Println("这个版本不支持设置默认StorageClass")
    return
}

storageClasses, _ := clientset.
    StorageV1().
    StorageClasses().
    List(context.TODO(), metav1.ListOptions{})
// 想要设置成默认的 StorageClass
targetStorageClassName := "sc-01-tmp"
defaultStorageAnnotation := "storageclass.kubernetes.io/is-default-class"
for _, sc := range storageClasses.Items {
    fmt.Println(sc.Name)
    fmt.Println(sc.Annotations)
    if sc.Annotations[defaultStorageAnnotation] == "true" {
        // 删除 default Storage Annotation key
        delete(sc.Annotations, defaultStorageAnnotation)
        // 更新 StorageClass
        _, err = clientset.
            StorageV1().
            StorageClasses().
            Update(context.TODO(), &sc, metav1.UpdateOptions{})
        if err != nil {
            panic(err.Error())
        }
    }
    if sc.Name == targetStorageClassName &&
        sc.Annotations[defaultStorageAnnotation] != "true" {
        if sc.Annotations == nil {
            sc.Annotations = make(map[string]string)
        }
        sc.Annotations[defaultStorageAnnotation] = "true"
        // 更新 StorageClass
        _, err = clientset.
            StorageV1().
            StorageClasses().
            Update(context.TODO(), &sc, metav1.UpdateOptions{})
        if err != nil {
            panic(err.Error())
        }
    }

}
err = clientset.
    StorageV1().
    StorageClasses().
    Delete(context.TODO(), "example-nfs", metav1.DeleteOptions{})
if err != nil {
    panic(err)
}

9 configmap

list, err := clientset.
    CoreV1().
    ConfigMaps("default").
    List(context.TODO(), metav1.ListOptions{})
if err != nil {
    panic(err.Error())
}
for _, item := range list.Items {
    fmt.Println("name:", item.ObjectMeta.Name)
    fmt.Println("type:", item.TypeMeta)
    fmt.Println("immutable:", *item.Immutable)
    fmt.Println("data:", item.Data)
    fmt.Println("BinaryData:", item.BinaryData)
}
item, err := clientset.CoreV1().ConfigMaps("default").Get(context.TODO(), "mysql-config2", metav1.GetOptions{})
if err != nil {
    // 找不到该configmap ,会报错
    panic(err.Error())
}
fmt.Println("name:", item.ObjectMeta.Name)
fmt.Println("type:", item.TypeMeta)
fmt.Println("immutable:", *item.Immutable)
fmt.Println("data:", item.Data)
fmt.Println("BinaryData:", item.BinaryData)
import (
    "context"
    "flag"
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"

    corev1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
)
//......
nginxConfigData, err := ioutil.ReadFile("nginx.conf")
if err != nil {
    fmt.Printf("err: %v\n", err)
    return
}
configMap := &corev1.ConfigMap{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "mysql-config22",
        Namespace: "default",
    },
    Data: map[string]string{
        "user":       "root",
        "password":   "123",
        "nginx.conf": string(nginxConfigData),
    },
}
// 在 Kubernetes 中创建 ConfigMap
createdConfigMap, err := clientset.
    CoreV1().
    ConfigMaps("default").
    Create(context.TODO(), configMap, metav1.CreateOptions{})
if err != nil {
    fmt.Printf("%v\n", err)
    return
}

fmt.Printf("%s\n", createdConfigMap.Name)
err = clientset.
    CoreV1().
    ConfigMaps("default").
    Delete(context.TODO(), "mysql-config2", metav1.DeleteOptions{})
if err != nil {
    panic(err.Error())
}
pod1 := &corev1.Pod{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "my-pod",
        Namespace: "default",
        Labels: map[string]string{
            "app": "pod-vol",
            "run": "test",
        },
    },
    Spec: corev1.PodSpec{
        Containers: []corev1.Container{
            {
                Name:  "my-container",
                Image: "nginx:1.14.2",
                Env: []corev1.EnvVar{
                    {
                        Name: "MYSQL_USER",
                        ValueFrom: &corev1.EnvVarSource{
                            ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
                                LocalObjectReference: corev1.LocalObjectReference{
                                    Name: "mysql-config22",
                                },
                                Key: "user",
                            },
                        },
                    },
                    {
                        Name:  "hello",
                        Value: "world",
                    },
                },
            },
        },
    },
}
createdPod, err := clientset.
    CoreV1().
    Pods("default").
    Create(context.TODO(),
        pod1,
        metav1.CreateOptions{
        })
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%s\n", createdPod.Name)
k exec my-pod  -- env

10 secret

list, err := clientset.CoreV1().Secrets("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
    panic(err.Error())
}
for _, item := range list.Items {
    fmt.Println("name:", item.ObjectMeta.Name)
    fmt.Println("type:", item.TypeMeta)
    if item.Immutable != nil {
        fmt.Println("immutable:", *item.Immutable)
    }
    fmt.Println("data:", item.Data)
    fmt.Println("stringData:", item.StringData)
    fmt.Println("type:", item.Type)
}
item, err := clientset.CoreV1().Secrets("default").Get(context.TODO(), "mysql-root-password", metav1.GetOptions{})
if err != nil {
    panic(err.Error())
}
fmt.Println("name:", item.ObjectMeta.Name)
fmt.Println("type:", item.TypeMeta)
if item.Immutable != nil {
    fmt.Println("immutable:", *item.Immutable)
}
fmt.Println("data:", item.Data)
fmt.Println("stringData:", item.StringData)
fmt.Println("type:", item.Type)
secret := &corev1.Secret{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "secret-test",
        Namespace: "default",
    },
    StringData: map[string]string{
        "username": "root",
        "password": "123456",
    },
    Type: corev1.SecretTypeOpaque, // 不写默认就是这个类型
}
createdSecret, err := clientset.
    CoreV1().
    Secrets("default").
    Create(context.TODO(), secret, metav1.CreateOptions{})
if err != nil {
    fmt.Printf("err: %v\n", err)
    return
}

fmt.Printf("ok: %s\n", createdSecret.Name)
err = clientset.CoreV1().Secrets("default").Delete(context.TODO(), "secret-test", metav1.DeleteOptions{})
if err != nil {
    panic(err.Error())
}

11 svc

service := &corev1.Service{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "svc-test",
        Namespace: namespace,
    },
    Spec: corev1.ServiceSpec{
        Selector: map[string]string{
            "app": "pod-deploy-nginx2",
        },
        Ports: []corev1.ServicePort{
            {
                Protocol:   corev1.ProtocolTCP,
                Port:       8981,
                TargetPort: intstr.FromInt(int(80)),
            },
        },
    },
}

createdSVC, err := clientset.CoreV1().
    Services(namespace).
    Create(context.TODO(), service, metav1.CreateOptions{})
if err != nil {
    panic(err.Error())
}
fmt.Println(createdSVC.Name)
endpoint := &corev1.Endpoints{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "svc-test-2",
        Namespace: namespace,
    },
    Subsets: []corev1.EndpointSubset{
        {
            Addresses: []corev1.EndpointAddress{
                {
                    IP: "10.244.1.82",
                },
                {
                    IP: "10.244.2.81",
                },
            },
            Ports: []corev1.EndpointPort{
                {
                    Protocol: corev1.ProtocolTCP,
                    Port:     int32(80),
                },
            },
        },
    },
}

ep, err := clientset.
    CoreV1().
    Endpoints("default").
    Create(context.TODO(), endpoint, metav1.CreateOptions{})

if err != nil {
    panic(err.Error())
}
fmt.Println(ep.Name)
Back to top