1 准备
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
配合文档 resourceVersion #### detail
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{})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
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的方式来更新.
// 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
// 创建持久卷
// 仅作为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())
}
}
}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)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)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)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)