原始
yaml
文件写法:
参见:k8s1.25 基本用法目录结构:
|—— client-go-demo/ // 根目录 ****|—— .kube/ ********|—— config // k8s 连接配置文件 ****|—— main.go // 主目录 ****|—— go.mod // go module 文件
编写 client-go-demo/go.mod:
module client-go-demo require ( k8s.io/api v0.25.9 k8s.io/client-go v0.25.9 k8s.io/apimachinery v0.25.9 )
下载相关依赖:
go get k8s.io/client-go@v0.25.9 go get k8s.io/apimachinery@v0.25.9 go get k8s.io/api@v0.25.9
编写 client-go-demo/main.go:
package main import ( "context" "errors" "fmt" appv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" storagev1 "k8s.io/api/storage/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" ) type K8sClient struct { *kubernetes.Clientset } // 判断 Namespace 是否存在,不存在则创建 func (k K8sClient) CreateNamespaceIfNotExists(ctx context.Context, name string) error { _, err := k.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, }, metav1.CreateOptions{}) if err != nil { return err } return nil } return errors.New("Namespace 已存在!") } // 判断 Namespace 是否存在,存在则删除 func (k K8sClient) DeleteNamespaceIfExists(ctx context.Context, name string) error { _, err := k.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().Namespaces().Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 ConfigMap func (k K8sClient) CreateOrUpdateConfigMap(ctx context.Context, namespace, name string, data map[string]string) error { configMapTemplate := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Data: data, } _, err := k.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().ConfigMaps(namespace).Create(ctx, configMapTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.CoreV1().ConfigMaps(namespace).Update(ctx, configMapTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 ConfigMap 是否存在,存在则删除 func (k K8sClient) DeleteConfigMapIfExists(ctx context.Context, namespace, name string) error { _, err := k.CoreV1().ConfigMaps(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().ConfigMaps(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 Secret func (k K8sClient) CreateOrUpdateSecret(ctx context.Context, namespace, name string, data map[string][]byte) error { secretTemplate := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Type: corev1.SecretTypeOpaque, Data: data, } _, err := k.CoreV1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().Secrets(namespace).Create(ctx, secretTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.CoreV1().Secrets(namespace).Update(ctx, secretTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 Secret 是否存在,存在则删除 func (k K8sClient) DeleteSecretIfExists(ctx context.Context, namespace, name string) error { _, err := k.CoreV1().Secrets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().Secrets(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 PV func (k K8sClient) CreateOrUpdatePV(ctx context.Context, name string, capacity float32, accessMode corev1.PersistentVolumeAccessMode, reclaimPolicy corev1.PersistentVolumeReclaimPolicy, source corev1.PersistentVolumeSource) error { pvTemplate := &corev1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: corev1.PersistentVolumeSpec{ Capacity: corev1.ResourceList{ corev1.ResourceStorage: *resource.NewQuantity(int64(capacity*1024*1024*1024), resource.BinarySI), // 单位: G }, AccessModes: []corev1.PersistentVolumeAccessMode{ accessMode, }, PersistentVolumeReclaimPolicy: reclaimPolicy, PersistentVolumeSource: source, }, } _, err := k.CoreV1().PersistentVolumes().Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().PersistentVolumes().Create(ctx, pvTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.CoreV1().PersistentVolumes().Update(ctx, pvTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 PV 是否存在,存在则删除 func (k K8sClient) DeletePVIfExists(ctx context.Context, name string) error { _, err := k.CoreV1().PersistentVolumes().Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().PersistentVolumes().Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 PVC func (k K8sClient) CreateOrUpdatePVC(ctx context.Context, namespace, name string, capacity float32, accessMode corev1.PersistentVolumeAccessMode, storageClassName string) error { pvcTemplate := &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: corev1.PersistentVolumeClaimSpec{ AccessModes: []corev1.PersistentVolumeAccessMode{ accessMode, }, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceStorage: *resource.NewQuantity(int64(capacity*1024*1024*1024), resource.BinarySI), // 单位: G }, }, }, } if storageClassName != "" { pvcTemplate.Spec.StorageClassName = &storageClassName // 使用 StorageClass } _, err := k.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().PersistentVolumeClaims(namespace).Create(ctx, pvcTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.CoreV1().PersistentVolumeClaims(namespace).Update(ctx, pvcTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 PVC 是否存在,存在则删除 func (k K8sClient) DeletePVCIfExists(ctx context.Context, namespace, name string) error { _, err := k.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().PersistentVolumeClaims(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 判断 Job 是否存在,不存在则创建 func (k K8sClient) CreateJobIfNotExists(ctx context.Context, namespace, name, podName, image string, env []corev1.EnvVar, command []string, volumeMount corev1.VolumeMount, volume corev1.Volume) error { _, err := k.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { jobTemplate := &batchv1.Job{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, Containers: []corev1.Container{ { Name: podName, Env: env, Command: command, Image: image, ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: []corev1.VolumeMount{ volumeMount, }, }, }, Volumes: []corev1.Volume{ volume, }, }, }, }, } _, err = k.BatchV1().Jobs(namespace).Create(ctx, jobTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } return errors.New("Job 已存在!") } // 判断 Job 是否存在,存在则删除 func (k K8sClient) DeleteJobIfExists(ctx context.Context, namespace, name string) error { _, err := k.BatchV1().Jobs(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.BatchV1().Jobs(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 CronJob func (k K8sClient) CreateOrUpdateCronJob(ctx context.Context, namespace, name, schedule, podName, image string, restartPolicy corev1.RestartPolicy, env []corev1.EnvVar, command []string, imagePullPolicy corev1.PullPolicy, volumeMount corev1.VolumeMount, volume corev1.Volume) error { cronJobTemplate := &batchv1.CronJob{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: batchv1.CronJobSpec{ Schedule: schedule, JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ RestartPolicy: restartPolicy, Containers: []corev1.Container{ { Name: podName, Env: env, Command: command, Image: image, ImagePullPolicy: imagePullPolicy, VolumeMounts: []corev1.VolumeMount{ volumeMount, }, }, }, Volumes: []corev1.Volume{ volume, }, }, }, }, }, }, } _, err := k.BatchV1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.BatchV1().CronJobs(namespace).Create(ctx, cronJobTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.BatchV1().CronJobs(namespace).Update(ctx, cronJobTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 CronJob 是否存在,存在则删除 func (k K8sClient) DeleteCronJobIfExists(ctx context.Context, namespace, name string) error { _, err := k.BatchV1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.BatchV1().CronJobs(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 Deployment func (k K8sClient) CreateOrUpdateDeployment(ctx context.Context, namespace, name string, labels map[string]string, replicas int, initContainers, containers []corev1.Container, nodeSelector map[string]string, volumes []corev1.Volume) error { replicasInt32 := int32(replicas) deployTemplate := &appv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: name, Labels: labels, }, Spec: appv1.DeploymentSpec{ Replicas: &replicasInt32, Selector: &metav1.LabelSelector{ MatchLabels: labels, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, }, Spec: corev1.PodSpec{ InitContainers: initContainers, Containers: containers, NodeSelector: nodeSelector, Volumes: volumes, }, }, }, } _, err := k.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.AppsV1().Deployments(namespace).Create(ctx, deployTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.AppsV1().Deployments(namespace).Update(ctx, deployTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 Deployment 是否存在,存在则删除 func (k K8sClient) DeleteDeploymentIfExists(ctx context.Context, namespace, name string) error { _, err := k.AppsV1().Deployments(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.AppsV1().Deployments(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 DaemonSet func (k K8sClient) CreateOrUpdateDaemonSet(ctx context.Context, namespace, name string, labels map[string]string, initContainers, containers []corev1.Container, volumes []corev1.Volume) error { dsTemplate := &appv1.DaemonSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Labels: labels, }, Spec: appv1.DaemonSetSpec{ Selector: &metav1.LabelSelector{ MatchLabels: labels, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, }, Spec: corev1.PodSpec{ InitContainers: initContainers, Containers: containers, Volumes: volumes, }, }, }, } _, err := k.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.AppsV1().DaemonSets(namespace).Create(ctx, dsTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.AppsV1().DaemonSets(namespace).Update(ctx, dsTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 DaemonSet 是否存在,存在则删除 func (k K8sClient) DeleteDaemonSetIfExists(ctx context.Context, namespace, name string) error { _, err := k.AppsV1().DaemonSets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.AppsV1().DaemonSets(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 Service func (k K8sClient) CreateOrUpdateService(ctx context.Context, namespace, name string, isHeadLess bool, selector map[string]string, svcType corev1.ServiceType, ports []corev1.ServicePort, nodePort int) error { svcTemplate := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: corev1.ServiceSpec{ Selector: selector, Type: svcType, Ports: ports, }, } if isHeadLess { svcTemplate.Spec.ClusterIP = "None" // headless-无头服务 } if svcType == corev1.ServiceTypeNodePort { svcTemplate.Spec.Ports[0].NodePort = int32(nodePort) // 当 Type为 NodePort 时设置端口号:30000-32767 } _, err := k.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().Services(namespace).Create(ctx, svcTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.CoreV1().Services(namespace).Update(ctx, svcTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 Service 是否存在,存在则删除 func (k K8sClient) DeleteServiceIfExists(ctx context.Context, namespace, name string) error { _, err := k.CoreV1().Services(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().Services(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 StorageClass func (k K8sClient) CreateOrUpdateStorageClass(ctx context.Context, name, provisionerName string) error { scTemplate := &storagev1.StorageClass{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Provisioner: provisionerName, } _, err := k.StorageV1().StorageClasses().Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.StorageV1().StorageClasses().Create(ctx, scTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.StorageV1().StorageClasses().Update(ctx, scTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 StorageClass 是否存在,存在则删除 func (k K8sClient) DeleteStorageClassIfExists(ctx context.Context, name string) error { _, err := k.StorageV1().StorageClasses().Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.StorageV1().StorageClasses().Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 StatefulSet func (k K8sClient) CreateOrUpdateStatefulSet(ctx context.Context, namespace, name, serviceName string, replicas int, labels, nodeSelector map[string]string, initContainers, containers []corev1.Container, volumes []corev1.Volume, volumeClaimTemplates []corev1.PersistentVolumeClaim) error { replicasInt32 := int32(replicas) stsTemplate := &appv1.StatefulSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: appv1.StatefulSetSpec{ ServiceName: serviceName, Replicas: &replicasInt32, Selector: &metav1.LabelSelector{ MatchLabels: labels, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: labels, }, Spec: corev1.PodSpec{ InitContainers: initContainers, Containers: containers, NodeSelector: nodeSelector, Volumes: volumes, }, }, VolumeClaimTemplates: volumeClaimTemplates, }, } _, err := k.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.AppsV1().StatefulSets(namespace).Create(ctx, stsTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.AppsV1().StatefulSets(namespace).Update(ctx, stsTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 StatefulSet 是否存在,存在则删除 func (k K8sClient) DeleteStatefulSetIfExists(ctx context.Context, namespace, name string) error { _, err := k.AppsV1().StatefulSets(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.AppsV1().StatefulSets(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 Ingress func (k K8sClient) CreateOrUpdateIngress(ctx context.Context, namespace, name string, annotations map[string]string, ingressClassName string, rules []networkingv1.IngressRule) error { ingTemplate := &networkingv1.Ingress{ ObjectMeta: metav1.ObjectMeta{ Name: name, Annotations: annotations, }, Spec: networkingv1.IngressSpec{ IngressClassName: &ingressClassName, Rules: rules, }, } _, err := k.NetworkingV1().Ingresses(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.NetworkingV1().Ingresses(namespace).Create(ctx, ingTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.NetworkingV1().Ingresses(namespace).Update(ctx, ingTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 Ingress 是否存在,存在则删除 func (k K8sClient) DeleteIngressIfExists(ctx context.Context, namespace, name string) error { _, err := k.NetworkingV1().Ingresses(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.NetworkingV1().Ingresses(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 HPA func (k K8sClient) CreateOrUpdateHPA(ctx context.Context, namespace, name, resourceKind, resourceName, resourceApiVersion string, minReplicas, maxReplicas, cpuPercent int) error { minReplicasInt32 := int32(minReplicas) maxReplicasInt32 := int32(maxReplicas) cpuPercentInt32 := int32(cpuPercent) hpaTemplate := &autoscalingv2.HorizontalPodAutoscaler{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Spec: autoscalingv2.HorizontalPodAutoscalerSpec{ ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{ Kind: resourceKind, Name: resourceName, APIVersion: resourceApiVersion, }, MinReplicas: &minReplicasInt32, MaxReplicas: maxReplicasInt32, Metrics: []autoscalingv2.MetricSpec{ { Type: autoscalingv2.ResourceMetricSourceType, Resource: &autoscalingv2.ResourceMetricSource{ Name: corev1.ResourceCPU, Target: autoscalingv2.MetricTarget{ Type: autoscalingv2.UtilizationMetricType, AverageUtilization: &cpuPercentInt32, }, }, }, }, }, } _, err := k.AutoscalingV2().HorizontalPodAutoscalers(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.AutoscalingV2().HorizontalPodAutoscalers(namespace).Create(ctx, hpaTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.AutoscalingV2().HorizontalPodAutoscalers(namespace).Update(ctx, hpaTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 HPA 是否存在,存在则删除 func (k K8sClient) DeleteHPAIfExists(ctx context.Context, namespace, name string) error { _, err := k.AutoscalingV2().HorizontalPodAutoscalers(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.AutoscalingV2().HorizontalPodAutoscalers(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 判断 ServiceAccount 是否存在,不存在则创建 func (k K8sClient) CreateServiceAccountIfNotExists(ctx context.Context, namespace, name string) error { saTemplate := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, } _, err := k.CoreV1().ServiceAccounts(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.CoreV1().ServiceAccounts(namespace).Create(ctx, saTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } return errors.New("ServiceAccount 已存在!") } // 判断 ServiceAccount 是否存在,存在则删除 func (k K8sClient) DeleteServiceAccountIfExists(ctx context.Context, namespace, name string) error { _, err := k.CoreV1().ServiceAccounts(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.CoreV1().ServiceAccounts(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 Role func (k K8sClient) CreateOrUpdateRole(ctx context.Context, namespace, name string, rules []rbacv1.PolicyRule) error { roleTemplate := &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Rules: rules, } _, err := k.RbacV1().Roles(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.RbacV1().Roles(namespace).Create(ctx, roleTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.RbacV1().Roles(namespace).Update(ctx, roleTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 Role 是否存在,存在则删除 func (k K8sClient) DeleteRoleIfExists(ctx context.Context, namespace, name string) error { _, err := k.RbacV1().Roles(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.RbacV1().Roles(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 RoleBinding func (k K8sClient) CreateOrUpdateRoleBinding(ctx context.Context, namespace, name string, subjects []rbacv1.Subject, roleRef rbacv1.RoleRef) error { rolebindingTemplate := &rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Subjects: subjects, RoleRef: roleRef, } _, err := k.RbacV1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.RbacV1().RoleBindings(namespace).Create(ctx, rolebindingTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.RbacV1().RoleBindings(namespace).Update(ctx, rolebindingTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 RoleBinding 是否存在,存在则删除 func (k K8sClient) DeleteRoleBindingIfExists(ctx context.Context, namespace, name string) error { _, err := k.RbacV1().RoleBindings(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.RbacV1().RoleBindings(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 ClusterRole func (k K8sClient) CreateOrUpdateClusterRole(ctx context.Context, name string, rules []rbacv1.PolicyRule) error { clusterroleTemplate := &rbacv1.ClusterRole{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Rules: rules, } _, err := k.RbacV1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.RbacV1().ClusterRoles().Create(ctx, clusterroleTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.RbacV1().ClusterRoles().Update(ctx, clusterroleTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 ClusterRole 是否存在,存在则删除 func (k K8sClient) DeleteClusterRoleIfExists(ctx context.Context, name string) error { _, err := k.RbacV1().ClusterRoles().Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.RbacV1().ClusterRoles().Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } // 创建或更新 ClusterRoleBinding func (k K8sClient) CreateOrUpdateClusterRoleBinding(ctx context.Context, name string, subjects []rbacv1.Subject, roleRef rbacv1.RoleRef) error { clusterrolebindingsTemplate := &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: name, }, Subjects: subjects, RoleRef: roleRef, } _, err := k.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) if err != nil { _, err = k.RbacV1().ClusterRoleBindings().Create(ctx, clusterrolebindingsTemplate, metav1.CreateOptions{}) if err != nil { return err } return nil } _, err = k.RbacV1().ClusterRoleBindings().Update(ctx, clusterrolebindingsTemplate, metav1.UpdateOptions{}) if err != nil { return err } return nil } // 判断 ClusterRoleBinding 是否存在,存在则删除 func (k K8sClient) DeleteClusterRoleBindingIfExists(ctx context.Context, name string) error { _, err := k.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{}) if err != nil { return err } err = k.RbacV1().ClusterRoleBindings().Delete(ctx, name, metav1.DeleteOptions{}) if err != nil { return err } return nil } func main() { config, err := clientcmd.BuildConfigFromFlags("", "./.kube/config") if err != nil { panic(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } ctx := context.Background() namespace := "test-namespace" client := K8sClient{ clientset, } // 1. Namespace // 创建 Namespace if err := client.CreateNamespaceIfNotExists(ctx, namespace); err != nil { fmt.Println("Namespace 创建失败:", err) } else { fmt.Println("Namespace 创建成功") } // 删除 Namespace if err := client.DeleteNamespaceIfExists(ctx, namespace); err != nil { fmt.Println("Namespace 删除失败:", err) } else { fmt.Println("Namespace 删除成功") } // 2. ConfigMap configMapName := "test-configmap" configMapData := map[string]string{ "test-key": ` username=admin password=admin123 `, } // 创建或更新 ConfigMap if err := client.CreateOrUpdateConfigMap(ctx, namespace, configMapName, configMapData); err != nil { fmt.Println("ConfigMap 创建/更新失败:", err) } else { fmt.Println("ConfigMap 创建/更新成功") } // 删除 ConfigMap if err := client.DeleteConfigMapIfExists(ctx, namespace, configMapName); err != nil { fmt.Println("ConfigMap 删除失败:", err) } else { fmt.Println("ConfigMap 删除成功") } // 3. Secret secretName := "test-secret" secretData := map[string][]byte{ "test-key": []byte("admin123"), } // 创建或更新 Secret if err := client.CreateOrUpdateSecret(ctx, namespace, secretName, secretData); err != nil { fmt.Println("Secret 创建/更新失败:", err) } else { fmt.Println("Secret 创建/更新成功") } // 删除 Secret if err := client.DeleteSecretIfExists(ctx, namespace, secretName); err != nil { fmt.Println("Secret 删除失败:", err) } else { fmt.Println("Secret 删除成功") } // 4. PV pvName := "test-pv" pvAccessMode := corev1.ReadWriteMany pvReclaimPolicy := corev1.PersistentVolumeReclaimRecycle pvSource := corev1.PersistentVolumeSource{ HostPath: &corev1.HostPathVolumeSource{ Path: "/home/vagrant/tmp", }, } // 创建或更新 PV if err := client.CreateOrUpdatePV(ctx, pvName, 1, pvAccessMode, pvReclaimPolicy, pvSource); err != nil { fmt.Println("PV 创建/更新失败:", err) } else { fmt.Println("PV 创建/更新成功") } // 删除 PV if err := client.DeletePVIfExists(ctx, pvName); err != nil { fmt.Println("PV 删除失败:", err) } else { fmt.Println("PV 删除成功") } // 5. PVC pvcName := "test-pvc" pvcAccessMode := corev1.ReadWriteMany pvcStorageClassName := "test-nfs-client-provisioner" // 创建或更新 PVC if err := client.CreateOrUpdatePVC(ctx, namespace, pvcName, 1, pvcAccessMode, pvcStorageClassName); err != nil { fmt.Println("PVC 创建/更新失败:", err) } else { fmt.Println("PVC 创建/更新成功") } // 删除 PVC if err := client.DeletePVCIfExists(ctx, namespace, pvcName); err != nil { fmt.Println("PVC 删除失败:", err) } else { fmt.Println("PVC 删除成功") } // 6. Job jobName := "test-job" jobPodName := "test-job-pod" jobImageName := "busybox" env := []corev1.EnvVar{ { Name: "STR", Value: "hello job", }, } command := []string{ "/bin/sh", "-c", "echo $STR > /tmp/job.txt", } volumeMount := corev1.VolumeMount{ Name: "job-volume", MountPath: "/tmp", } volume := corev1.Volume{ Name: "job-volume", VolumeSource: corev1.VolumeSource{ HostPath: &corev1.HostPathVolumeSource{ Path: "/home/vagrant/tmp", }, }, } // 创建 Job if err := client.CreateJobIfNotExists(ctx, namespace, jobName, jobPodName, jobImageName, env, command, volumeMount, volume); err != nil { fmt.Println("Job 创建失败:", err) } else { fmt.Println("Job 创建成功") } // 删除 Job if err := client.DeleteJobIfExists(ctx, namespace, jobName); err != nil { fmt.Println("Job 删除失败:", err) } else { fmt.Println("Job 删除成功") } // 7. CronJob cronJobName := "test-cronjob" schedule := "*/1 * * * *" cronJobPodName := "test-cronjob-pod" cronJobImageName := "busybox" cronJobRestartPolicy := corev1.RestartPolicyOnFailure cronJobEnv := []corev1.EnvVar{ { Name: "STR", Value: "hello cronjob", }, } cronJobCommand := []string{ "/bin/sh", "-c", "echo $STR >> /tmp/cronjob.txt", } cronJobImagePullPolicy := corev1.PullIfNotPresent cronJobVolumeMount := corev1.VolumeMount{ Name: "cronjob-volume", MountPath: "/tmp", } cronJobVolume := corev1.Volume{ Name: "cronjob-volume", VolumeSource: corev1.VolumeSource{ HostPath: &corev1.HostPathVolumeSource{ Path: "/home/vagrant/tmp", }, }, } // 创建或更新 CronJob if err := client.CreateOrUpdateCronJob(ctx, namespace, cronJobName, schedule, cronJobPodName, cronJobImageName, cronJobRestartPolicy, cronJobEnv, cronJobCommand, cronJobImagePullPolicy, cronJobVolumeMount, cronJobVolume); err != nil { fmt.Println("CronJob 创建/更新失败:", err) } else { fmt.Println("CronJob 创建/更新成功") } // 删除 CronJob if err := client.DeleteCronJobIfExists(ctx, namespace, cronJobName); err != nil { fmt.Println("CronJob 删除失败:", err) } else { fmt.Println("CronJob 删除成功") } // 8. Deployment deployName := "test-deploy" deployLabels := map[string]string{ "app": "nginx", } deployInitContainers := []corev1.Container{ { Name: "test-deploy-initcontainer", Image: "busybox", Env: []corev1.EnvVar{ { Name: "STR", Value: "hello nginx", }, }, Command: []string{ "sh", "-c", "echo $STR > /usr/share/nginx/html/index.html", }, VolumeMounts: []corev1.VolumeMount{ { Name: "test-deploy-volume", MountPath: "/usr/share/nginx/html", }, }, }, } deployContainers := []corev1.Container{ { Name: "test-deploy-container", Image: "nginx:1.7.9", ImagePullPolicy: corev1.PullIfNotPresent, Ports: []corev1.ContainerPort{ { Name: "t-d-p", ContainerPort: 80, }, }, ReadinessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/", Port: intstr.IntOrString{ Type: intstr.Int, IntVal: 80, }, Scheme: corev1.URISchemeHTTP, }, }, FailureThreshold: 3, SuccessThreshold: 1, PeriodSeconds: 5, TimeoutSeconds: 3, }, LivenessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/", Port: intstr.IntOrString{ Type: intstr.Int, IntVal: 80, }, Scheme: corev1.URISchemeHTTP, }, }, FailureThreshold: 3, SuccessThreshold: 1, InitialDelaySeconds: 10, // 延迟 10 秒检查 PeriodSeconds: 5, TimeoutSeconds: 3, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), // 单位: 核,如: 100m == 0.1核 corev1.ResourceMemory: *resource.NewQuantity(int64(256*1024*1024), resource.BinarySI), // 单位: M }, Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), // 单位: 核,如: 100m == 0.1核 corev1.ResourceMemory: *resource.NewQuantity(int64(256*1024*1024), resource.BinarySI), // 单位: M }, }, VolumeMounts: []corev1.VolumeMount{ { Name: "test-deploy-volume", MountPath: "/usr/share/nginx/html", }, }, }, } deployNodeSelector := map[string]string{ "role": "master", } deployVolumes := []corev1.Volume{ { Name: "test-deploy-volume", VolumeSource: corev1.VolumeSource{ HostPath: &corev1.HostPathVolumeSource{ Path: "/home/vagrant/tmp", }, }, }, } // 创建或更新 Deployment if err := client.CreateOrUpdateDeployment(ctx, namespace, deployName, deployLabels, 1, deployInitContainers, deployContainers, deployNodeSelector, deployVolumes); err != nil { fmt.Println("Deployment 创建/更新失败:", err) } else { fmt.Println("Deployment 创建/更新成功") } // 删除 Deployment if err := client.DeleteDeploymentIfExists(ctx, namespace, deployName); err != nil { fmt.Println("Deployment 删除失败:", err) } else { fmt.Println("Deployment 删除成功") } // 9. DaemonSet dsName := "test-ds" dsLabels := map[string]string{ "app": "nginx", } dsInitContainers := []corev1.Container{ { Name: "test-ds-initcontainer", Image: "busybox", Env: []corev1.EnvVar{ { Name: "STR", Value: "hello nginx", }, }, Command: []string{ "sh", "-c", "echo $STR > /usr/share/nginx/html/index.html", }, VolumeMounts: []corev1.VolumeMount{ { Name: "test-ds-volume", MountPath: "/usr/share/nginx/html", }, }, }, } dsContainers := []corev1.Container{ { Name: "test-ds-container", Image: "nginx:1.7.9", ImagePullPolicy: corev1.PullIfNotPresent, Ports: []corev1.ContainerPort{ { Name: "t-d-p", ContainerPort: 80, }, }, ReadinessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/", Port: intstr.IntOrString{ Type: intstr.Int, IntVal: 80, }, Scheme: corev1.URISchemeHTTP, }, }, FailureThreshold: 3, SuccessThreshold: 1, PeriodSeconds: 5, TimeoutSeconds: 3, }, LivenessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/", Port: intstr.IntOrString{ Type: intstr.Int, IntVal: 80, }, Scheme: corev1.URISchemeHTTP, }, }, FailureThreshold: 3, SuccessThreshold: 1, InitialDelaySeconds: 10, // 延迟 10 秒检查 PeriodSeconds: 5, TimeoutSeconds: 3, }, Resources: corev1.ResourceRequirements{ Limits: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), // 单位: 核,如: 100m == 0.1核 corev1.ResourceMemory: *resource.NewQuantity(int64(256*1024*1024), resource.BinarySI), // 单位: M }, Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("100m"), // 单位: 核,如: 100m == 0.1核 corev1.ResourceMemory: *resource.NewQuantity(int64(256*1024*1024), resource.BinarySI), // 单位: M }, }, VolumeMounts: []corev1.VolumeMount{ { Name: "test-ds-volume", MountPath: "/usr/share/nginx/html", }, }, }, } dsVolumes := []corev1.Volume{ { Name: "test-ds-volume", VolumeSource: corev1.VolumeSource{ HostPath: &corev1.HostPathVolumeSource{ Path: "/home/vagrant/tmp", }, }, }, } // 创建或更新 DaemonSet if err := client.CreateOrUpdateDaemonSet(ctx, namespace, dsName, dsLabels, dsInitContainers, dsContainers, dsVolumes); err != nil { fmt.Println("DaemonSet 创建/更新失败:", err) } else { fmt.Println("DaemonSet 创建/更新成功") } // 删除 DaemonSet if err := client.DeleteDaemonSetIfExists(ctx, namespace, dsName); err != nil { fmt.Println("DaemonSet 删除失败:", err) } else { fmt.Println("DaemonSet 删除成功") } // 10. Service svcName := "test-svc" svcSelector := map[string]string{ "app": "mysql", } svcPorts := []corev1.ServicePort{ { Name: "t-s-p", Protocol: corev1.ProtocolTCP, Port: int32(3306), TargetPort: intstr.IntOrString{ Type: intstr.String, StrVal: "t-s-p", }, }, } // 创建或更新 Service if err := client.CreateOrUpdateService(ctx, namespace, svcName, true, svcSelector, corev1.ServiceTypeClusterIP, svcPorts, 30001); err != nil { fmt.Println("Service 创建/更新失败:", err) } else { fmt.Println("Service 创建/更新成功") } // 删除 Service if err := client.DeleteServiceIfExists(ctx, namespace, svcName); err != nil { fmt.Println("Service 删除失败:", err) } else { fmt.Println("Service 删除成功") } // 11. StorageClass scName := "test-sc" // 创建或更新 StorageClass if err := client.CreateOrUpdateStorageClass(ctx, scName, "test-nfs-client-provisioner"); err != nil { fmt.Println("StorageClass 创建/更新失败:", err) } else { fmt.Println("StorageClass 创建/更新成功") } // 删除 StorageClass if err := client.DeleteStorageClassIfExists(ctx, scName); err != nil { fmt.Println("StorageClass 删除失败:", err) } else { fmt.Println("StorageClass 删除成功") } // 12. StatefulSet stsName := "test-sts" stsLabels := map[string]string{ "app": "mysql", } stsNodeSelector := map[string]string{ "kubernetes.io/hostname": "master", } stsInitContainers := []corev1.Container{ { Name: "test-sts-initcontainer", Image: "busybox", Env: []corev1.EnvVar{}, Command: []string{ "sh", "-c", "echo $(hostname)", }, VolumeMounts: []corev1.VolumeMount{}, }, } stsContainers := []corev1.Container{ { Name: "test-sts-container", Image: "mysql:5.7", Env: []corev1.EnvVar{ { Name: "MYSQL_ROOT_PASSWORD", Value: "123456", }, }, Ports: []corev1.ContainerPort{ { Name: "t-s-p", ContainerPort: 3306, }, }, VolumeMounts: []corev1.VolumeMount{ { Name: "test-sts-vct", MountPath: "/var/lib/mysql", }, }, }, } stsVolumes := []corev1.Volume{ { Name: "test-sts-volume", VolumeSource: corev1.VolumeSource{ HostPath: &corev1.HostPathVolumeSource{ Path: "/home/vagrant/tmp", }, }, }, } stsScName := "test-sc" stsVolumeClaimTemplates := []corev1.PersistentVolumeClaim{ { ObjectMeta: metav1.ObjectMeta{ Name: "test-sts-vct", }, Spec: corev1.PersistentVolumeClaimSpec{ AccessModes: []corev1.PersistentVolumeAccessMode{ corev1.ReadWriteMany, }, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceStorage: *resource.NewQuantity(int64(1*1024*1024*1024), resource.BinarySI), // 单位: G }, }, StorageClassName: &stsScName, }, }, } // 创建或更新 StatefulSet if err := client.CreateOrUpdateStatefulSet(ctx, namespace, stsName, "test-svc", 2, stsLabels, stsNodeSelector, stsInitContainers, stsContainers, stsVolumes, stsVolumeClaimTemplates); err != nil { fmt.Println("StatefulSet 创建/更新失败:", err) } else { fmt.Println("StatefulSet 创建/更新成功") } // 删除 StatefulSet if err := client.DeleteStatefulSetIfExists(ctx, namespace, stsName); err != nil { fmt.Println("StatefulSet 删除失败:", err) } else { fmt.Println("StatefulSet 删除成功") } // 13. Ingress ingName := "test-ing" ingAnnotations := map[string]string{ //"kubernetes.io/ingress.class": "nginx", } ingPathType := networkingv1.PathTypePrefix ingRules := []networkingv1.IngressRule{ { Host: "nginx.lee.com", IngressRuleValue: networkingv1.IngressRuleValue{ HTTP: &networkingv1.HTTPIngressRuleValue{ Paths: []networkingv1.HTTPIngressPath{ { Path: "/", PathType: &ingPathType, Backend: networkingv1.IngressBackend{ Service: &networkingv1.IngressServiceBackend{ Name: "test-svc", Port: networkingv1.ServiceBackendPort{ Number: 80, }, }, }, }, }, }, }, }, } // 创建或更新 Ingress if err := client.CreateOrUpdateIngress(ctx, namespace, ingName, ingAnnotations, "ingress-nginx", ingRules); err != nil { fmt.Println("Ingress 创建/更新失败:", err) } else { fmt.Println("Ingress 创建/更新成功") } // 删除 Ingress if err := client.DeleteIngressIfExists(ctx, namespace, ingName); err != nil { fmt.Println("Ingress 删除失败:", err) } else { fmt.Println("Ingress 删除成功") } // 14. HPA hpaName := "test-hpa" hpaResourceKind := "Deployment" hpaResourceName := "test-deploy" hpaResourceApiVersion := "apps/v1" // 创建或更新 HPA if err := client.CreateOrUpdateHPA(ctx, namespace, hpaName, hpaResourceKind, hpaResourceName, hpaResourceApiVersion, 1, 2, 10); err != nil { fmt.Println("HPA 创建/更新失败:", err) } else { fmt.Println("HPA 创建/更新成功") } // 删除 HPA if err := client.DeleteHPAIfExists(ctx, namespace, hpaName); err != nil { fmt.Println("HPA 删除失败:", err) } else { fmt.Println("HPA 删除成功") } // 15. RBAC-ServiceAccount saName := "test-sa" // 创建 ServiceAccount if err := client.CreateServiceAccountIfNotExists(ctx, namespace, saName); err != nil { fmt.Println("ServiceAccount 创建失败:", err) } else { fmt.Println("ServiceAccount 创建成功") } // 删除 ServiceAccount if err := client.DeleteServiceAccountIfExists(ctx, namespace, saName); err != nil { fmt.Println("ServiceAccount 删除失败:", err) } else { fmt.Println("ServiceAccount 删除成功") } // 16. Role roleName := "test-role" roleRules := []rbacv1.PolicyRule{ { APIGroups: []string{ "", }, Resources: []string{ "pods", }, Verbs: []string{ "get", "list", "watch", }, }, { APIGroups: []string{ "apps", }, Resources: []string{ "deployments", }, Verbs: []string{ "create", "update", "delete", "patch", "get", "list", "watch", }, }, } // 创建或更新 Role if err := client.CreateOrUpdateRole(ctx, namespace, roleName, roleRules); err != nil { fmt.Println("Role 创建/更新失败:", err) } else { fmt.Println("Role 创建/更新成功") } // 删除 Role if err := client.DeleteRoleIfExists(ctx, namespace, roleName); err != nil { fmt.Println("Role 删除失败:", err) } else { fmt.Println("Role 删除成功") } // 17. RoleBinding roleBindingName := "test-rolebinding" roleBindingSubjects := []rbacv1.Subject{ { Kind: "ServiceAccount", Name: "test-sa", Namespace: "test-namespace", }, } roleBindingRoleRef := rbacv1.RoleRef{ Kind: "Role", Name: "test-role", APIGroup: "rbac.authorization.k8s.io", } // 创建或更新 RoleBinding if err := client.CreateOrUpdateRoleBinding(ctx, namespace, roleBindingName, roleBindingSubjects, roleBindingRoleRef); err != nil { fmt.Println("RoleBinding 创建/更新失败:", err) } else { fmt.Println("RoleBinding 创建/更新成功") } // 删除 RoleBinding if err := client.DeleteRoleBindingIfExists(ctx, namespace, roleBindingName); err != nil { fmt.Println("RoleBinding 删除失败:", err) } else { fmt.Println("RoleBinding 删除成功") } // 18. ClusterRole clusterroleName := "test-clusterrole" clusterroleRules := []rbacv1.PolicyRule{ { APIGroups: []string{ "", }, Resources: []string{ "pods", }, Verbs: []string{ "get", "list", "watch", }, }, { APIGroups: []string{ "apps", }, Resources: []string{ "deployments", }, Verbs: []string{ "create", "update", "delete", "patch", "get", "list", "watch", }, }, } // 创建或更新 ClusterRole if err := client.CreateOrUpdateClusterRole(ctx, clusterroleName, clusterroleRules); err != nil { fmt.Println("ClusterRole 创建/更新失败:", err) } else { fmt.Println("ClusterRole 创建/更新成功") } // 删除 ClusterRole if err := client.DeleteClusterRoleIfExists(ctx, clusterroleName); err != nil { fmt.Println("ClusterRole 删除失败:", err) } else { fmt.Println("ClusterRole 删除成功") } // 19. ClusterRoleBinding clusterRoleBindingName := "test-clusterrolebindings" clusterRoleBindingSubjects := []rbacv1.Subject{ { Kind: "ServiceAccount", Name: "test-sa", Namespace: "test-namespace", }, } clusterRoleBindingRoleRef := rbacv1.RoleRef{ Kind: "ClusterRole", Name: "test-clusterrole", APIGroup: "rbac.authorization.k8s.io", } // 创建或更新 ClusterRoleBinding if err := client.CreateOrUpdateClusterRoleBinding(ctx, clusterRoleBindingName, clusterRoleBindingSubjects, clusterRoleBindingRoleRef); err != nil { fmt.Println("ClusterRoleBinding 创建/更新失败:", err) } else { fmt.Println("ClusterRoleBinding 创建/更新成功") } // 删除 ClusterRoleBinding if err := client.DeleteClusterRoleBindingIfExists(ctx, clusterRoleBindingName); err != nil { fmt.Println("ClusterRoleBinding 删除失败:", err) } else { fmt.Println("ClusterRoleBinding 删除成功") } }
文档更新时间: 2024-04-20 10:57 作者:lee