From 064c0874e5fd041c4641ef873d1bf72ac98a184d Mon Sep 17 00:00:00 2001 From: wangpengfei <274878379@qq.com> Date: 星期五, 02 六月 2023 16:26:09 +0800 Subject: [PATCH] Merge branch 'master' into fly_develop --- src/main/main.go | 596 ++++++++++++++++++++--------------------------------------- 1 files changed, 206 insertions(+), 390 deletions(-) diff --git a/src/main/main.go b/src/main/main.go index 006d1a5..e3e8f81 100644 --- a/src/main/main.go +++ b/src/main/main.go @@ -1,22 +1,22 @@ package main import ( - "context" "flag" "fmt" "log" - "math/rand" "os" "path/filepath" "time" - appsv1 "k8s.io/api/apps/v1" - apiv1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" + "basic.com/aps/aps_deploy.git/src/cluster" + "basic.com/aps/aps_deploy.git/src/rancher" + "basic.com/aps/aps_deploy.git/src/util" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" + + "basic.com/aps/aps_deploy.git/src/k8s" + + "github.com/spf13/viper" ) var ( @@ -26,10 +26,104 @@ namespaces = []string{"guangsheng", "geruimi", "tongsheng"} ) +func rancher_install_test(node rancher.Node) { + /* nodes := []Node{ + { + Roles: []string{"etcd", "controlplane", "worker"}, + IP: "192.168.20.189", + SSHUsername: "basic", + SSHPassword: "123", + SSHPort: 22, + }, + { + Roles: []string{"worker"}, + IP: "192.168.20.10", + SSHUsername: "basic", + SSHPassword: "123", + SSHPort: 22, + }, + { + Roles: []string{"worker"}, + IP: "192.168.20.115", + SSHUsername: "basic", + SSHPassword: "alien123", + SSHPort: 22, + }, + // Add more nodes here if needed + }*/ + + //install rancher on master node + err := rancher.InstallDockerAndRancher(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort) + if err != nil { + log.Fatalf("Failed to install Rancher: %v", err) + } + + os.Exit(0) +} + +func cluster_test(clusterName string, rancherClusterConfig rancher.RancherClusterConfig) { + + // Create the cluster + // Rancher configuration + /*rancherConfig := RancherConfig{ + RancherURL: "https://192.168.20.119:8443", + BearerToken: "token-nnrsc:w68zdt8s47fnpjd5xqdl5hhzpz4j2d56kt5nx49nsswcbpdzc28kh5", + }*/ + + fmt.Println(rancherClusterConfig) + fmt.Println(rancherClusterConfig.RancherURL) + fmt.Println(rancherClusterConfig.BearerToken) + // Deploy clusterId + clusterID, err := cluster.GetClusterID(rancherClusterConfig.RancherURL, rancherClusterConfig.BearerToken, clusterName) + if err != nil { + fmt.Printf("Cluster not found: %s %v\n", clusterName, err) + err = cluster.CreateCluster(rancherClusterConfig, clusterName) + if err != nil { + log.Fatalf("Failed to create cluster: %v", err) + } + fmt.Printf("Cluster created: %s\n", clusterName) + clusterID, err = cluster.GetClusterID(rancherClusterConfig.RancherURL, rancherClusterConfig.BearerToken, clusterName) + if err != nil { + log.Fatal(err) + } + } + fmt.Println(clusterID) + + // Deploy nodeCommand + nodeCommand, err := cluster.GetNodeCommand(rancherClusterConfig.RancherURL, rancherClusterConfig.BearerToken, clusterID) + if err != nil { + log.Fatal(err) + } + fmt.Println(nodeCommand) + + for _, node := range rancherClusterConfig.Nodes { + //Deploy Docker on each node + err = util.InstallDocker(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort) + if err != nil { + log.Fatal(err) + } + + // Deploy Kubectl on each node + err = util.InstallKubectl(node.IP, node.SSHUsername, node.SSHPassword, node.SSHPort) + if err != nil { + log.Fatal(err) + } + + // Deploy Kubernetes roles on each node + err = cluster.Deployk8sRolesOnNode(node.IP, node.SSHUsername, node.SSHPassword, nodeCommand, node.SSHPort, node.Roles) + if err != nil { + log.Fatal(err) + } + } + os.Exit(0) +} + func main() { createCmd := flag.NewFlagSet("create", flag.ExitOnError) deleteCmd := flag.NewFlagSet("delete", flag.ExitOnError) testCmd := flag.NewFlagSet("test", flag.ExitOnError) + clusterCmd := flag.NewFlagSet("cluster", flag.ExitOnError) + rancherInstallCmd := flag.NewFlagSet("rancher_install", flag.ExitOnError) createNamespace := createCmd.String("ns", "", "Namespace name") createDeployment := createCmd.String("deployment", "", "Deployment name") @@ -40,7 +134,7 @@ deleteService := deleteCmd.String("service", "", "Service name") if len(os.Args) < 2 { - fmt.Println("create/delete/test command is required") + fmt.Println("create/delete/test/cluster/rancher_install command is required") os.Exit(1) } @@ -51,40 +145,81 @@ deleteCmd.Parse(os.Args[2:]) case "test": testCmd.Parse(os.Args[2:]) + case "cluster": + clusterCmd.Parse(os.Args[2:]) + case "rancher_install": + rancherInstallCmd.Parse(os.Args[2:]) default: flag.PrintDefaults() os.Exit(1) } - // 閰嶇疆 Kubernetes 闆嗙兢鐨� kubeconfig 璺緞 - kubeconfig := flag.String("kubeconfig", filepath.Join(homeDir(), ".kube", "config"), "kubeconfig file") - flag.Parse() + if rancherInstallCmd.Parsed() { + //// 鍒濆鍖栭厤缃В鏋愬簱 + //viper.SetConfigName("config") + //viper.SetConfigType("yaml") + //viper.AddConfigPath("./config") + // + //// 璇诲彇閰嶇疆鏂囦欢 + //err := viper.ReadInConfig() + //if err != nil { + // log.Fatalf("Failed to read config file: %v", err) + //} - // 鍒涘缓 Kubernetes 瀹㈡埛绔� - config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) - if err != nil { - panic(err.Error()) - } + // 瑙f瀽閰嶇疆鏂囦欢涓殑瀛楁 + var rancherClusterConfig rancher.RancherClusterConfig + //err = viper.Unmarshal(&rancherClusterConfig) + //if err != nil { + // log.Fatalf("Failed to unmarshal config: %v", err) + //} - clientset, err := kubernetes.NewForConfig(config) - if err != nil { - panic(err.Error()) + rancherClusterConfig.Nodes = make([]rancher.Node, 3) + rancherClusterConfig.Nodes[0] = rancher.Node{ + Roles: []string{"worker"}, + IP: "192.168.20.189", + SSHUsername: "basic", + SSHPassword: "123", + SSHPort: 22, + } + + rancher_install_test(rancherClusterConfig.Nodes[0]) + os.Exit(1) } // 鎵ц create 鍛戒护 if createCmd.Parsed() { + + // 閰嶇疆 Kubernetes 闆嗙兢鐨� kubeconfig 璺緞 + kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file") + flag.Parse() + + fmt.Println(&kubeconfig) + + // 鍒涘缓 Kubernetes 瀹㈡埛绔� + config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) + if err != nil { + panic(err.Error()) + } + + fmt.Println(&config) + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + panic(err.Error()) + } + if *createNamespace == "" || *createDeployment == "" || *createService == "" { fmt.Println("Namespace, Deployment, and Service names are required") createCmd.PrintDefaults() os.Exit(1) } - err := CreateDeploymentAndService(clientset, *createNamespace, *createDeployment, *createService) + err = k8s.CreateDeploymentAndService(clientset, *createNamespace, *createDeployment, *createService) if err != nil { panic(err) } - nodeport, err := GetServiceNodePort(clientset, *createNamespace, *createService) + nodeport, err := k8s.GetServiceNodePort(clientset, *createNamespace, *createService) if err != nil { panic(err) } @@ -94,13 +229,28 @@ // 鎵ц delete 鍛戒护 if deleteCmd.Parsed() { + // 閰嶇疆 Kubernetes 闆嗙兢鐨� kubeconfig 璺緞 + kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file") + flag.Parse() + + // 鍒涘缓 Kubernetes 瀹㈡埛绔� + config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) + if err != nil { + panic(err.Error()) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + panic(err.Error()) + } + if *deleteNamespace == "" || *deleteDeployment == "" || *deleteService == "" { fmt.Println("Namespace, Deployment, and Service names are required") deleteCmd.PrintDefaults() os.Exit(1) } - err := DeleteResources(clientset, *deleteNamespace, *deleteDeployment, *deleteService) + err = k8s.DeleteResources(clientset, *deleteNamespace, *deleteDeployment, *deleteService) if err != nil { panic(err) } @@ -110,6 +260,21 @@ // 鎵ц鍒涘缓鍜屽垹闄ゆ祴璇� if testCmd.Parsed() { + // 閰嶇疆 Kubernetes 闆嗙兢鐨� kubeconfig 璺緞 + kubeconfig := flag.String("kubeconfig", filepath.Join(util.HomeDir(), ".kube", "config"), "kubeconfig file") + flag.Parse() + + // 鍒涘缓 Kubernetes 瀹㈡埛绔� + config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) + if err != nil { + panic(err.Error()) + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + panic(err.Error()) + } + fmt.Println("\033[97;40mRunning create and delete tests...\033[0m") // 鍒涘缓娴嬭瘯 @@ -117,11 +282,11 @@ for _, ns := range namespaces { deploymentName := ns serviceName := ns - err := CreateDeploymentAndService(clientset, ns, deploymentName, serviceName) + err := k8s.CreateDeploymentAndService(clientset, ns, deploymentName, serviceName) if err != nil { log.Printf("\033[97;41mFailed to create resources in namespace %s: %v\033[0m\n", ns, err) } else { - nodeport, err := GetServiceNodePort(clientset, ns, ns) + nodeport, err := k8s.GetServiceNodePort(clientset, ns, ns) if err != nil { panic(err) } @@ -139,7 +304,7 @@ // 鍒犻櫎澶氫釜 Namespace 涓嬬殑鐩稿悓鍚嶇О鐨� Deployment 鍜� Service for _, ns := range namespaces { - err = DeleteResources(clientset, ns, ns, ns) + err = k8s.DeleteResources(clientset, ns, ns, ns) if err != nil { panic(err) } @@ -148,376 +313,27 @@ fmt.Println("Resources deleted.") } -} + if clusterCmd.Parsed() { + // 鍒濆鍖栭厤缃В鏋愬簱 + viper.SetConfigName("config") + viper.SetConfigType("yaml") + viper.AddConfigPath("./config") -// CheckAndDeleteResources 妫�娴嬪苟鍒犻櫎鎸囧畾鐨� Namespace銆丏eployment 鍜� Service -func CheckAndDeleteResources(clientset *kubernetes.Clientset, namespace, deploymentName, serviceName string) error { - fmt.Println("\033[1;37;40mChecking and deleting resources in Namespace:", namespace, "\033[0m") - - // 妫�鏌ュ苟鍒犻櫎 Deployment - err := deleteDeploymentIfExists(clientset, namespace, deploymentName) - if err != nil { - return err - } - - // 妫�鏌ュ苟鍒犻櫎 Service - err = deleteServiceIfExists(clientset, namespace, serviceName) - if err != nil { - return err - } - - return nil -} - -// deleteDeploymentIfExists 妫�鏌ュ苟鍒犻櫎鎸囧畾鐨� Deployment锛堝鏋滃瓨鍦級 -func deleteDeploymentIfExists(clientset *kubernetes.Clientset, namespace, deploymentName string) error { - fmt.Println("\033[1;37;40mChecking and deleting Deployment:", deploymentName, "\033[0m") - - err := clientset.AppsV1().Deployments(namespace).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{}) - if err != nil { - if errors.IsNotFound(err) { - fmt.Printf("Deployment %s not found in Namespace %s\n", deploymentName, namespace) - } else { - return fmt.Errorf("failed to delete Deployment: %v", err) - } - } else { - fmt.Printf("Deployment %s deleted from Namespace %s\n", deploymentName, namespace) - } - - return nil -} - -// deleteServiceIfExists 妫�鏌ュ苟鍒犻櫎鎸囧畾鐨� Service锛堝鏋滃瓨鍦級 -func deleteServiceIfExists(clientset *kubernetes.Clientset, namespace, serviceName string) error { - fmt.Println("\033[1;37;40mChecking and deleting Service:", serviceName, "\033[0m") - - err := clientset.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{}) - if err != nil { - if errors.IsNotFound(err) { - fmt.Printf("Service %s not found in Namespace %s\n", serviceName, namespace) - } else { - return fmt.Errorf("failed to delete Service: %v", err) - } - } else { - fmt.Printf("Service %s deleted from Namespace %s\n", serviceName, namespace) - } - - return nil -} - -func CreateDeploymentAndService(clientset *kubernetes.Clientset, namespace, deploymentName, serviceName string) error { - fmt.Println("\033[1;37;40mCreating resources in Namespace:", namespace, "\033[0m") - - // 妫�娴嬪苟鍒犻櫎宸插瓨鍦ㄧ殑 Deployment 鍜� Service - err := CheckAndDeleteResources(clientset, namespace, deploymentName, serviceName) - if err != nil { - return err - } - - // 鍒涘缓 Namespace - err = createNamespace(clientset, namespace) - if err != nil { - return err - } - - // 鍒涘缓 Deployment - err = createDeployment(clientset, namespace, deploymentName) - if err != nil { - return err - } - - // 鍒涘缓 Service - err = createService(clientset, namespace, serviceName) - if err != nil { - return err - } - - return nil -} - -// createNamespace 鍒涘缓鎸囧畾鐨� Namespace -func createNamespace(clientset *kubernetes.Clientset, namespace string) error { - log.Printf("Creating Namespace: %s\n", namespace) - - ns := &apiv1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: namespace, - }, - } - - _, err := clientset.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) - if err != nil { - if !errors.IsAlreadyExists(err) { - return fmt.Errorf("failed to create Namespace: %w", err) - } - log.Printf("Namespace %s already exists\n", namespace) - } else { - log.Printf("Namespace %s created\n", namespace) - } - - return nil -} - -func createDeployment(clientset *kubernetes.Clientset, namespace, deploymentName string) error { - fmt.Println("\033[1;37;40mCreating Deployment:", deploymentName, "\033[0m") - - deployment := &appsv1.Deployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: deploymentName, - }, - Spec: appsv1.DeploymentSpec{ - Replicas: &replicas, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "cid": namespace, - }, - }, - Template: apiv1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "cid": namespace, - }, - }, - Spec: apiv1.PodSpec{ - TopologySpreadConstraints: []apiv1.TopologySpreadConstraint{ - { - MaxSkew: 1, - TopologyKey: "kubernetes.io/hostname", - WhenUnsatisfiable: apiv1.DoNotSchedule, - LabelSelector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "cid": namespace, - }, - }, - }, - }, - Containers: []apiv1.Container{ - { - Name: namespace, - Image: "192.168.20.119/apsserver/apsserver:v0.2", - Env: []apiv1.EnvVar{ - { - Name: "NODE_ID", - Value: namespace, - }, - }, - }, - }, - }, - }, - }, - } - - _, err := clientset.AppsV1().Deployments(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{}) - if err != nil { - if !errors.IsAlreadyExists(err) { - return fmt.Errorf("failed to create Deployment: %v", err) - } - fmt.Printf("Deployment %s already exists in Namespace %s\n", deploymentName, namespace) - } else { - fmt.Printf("Deployment %s created in Namespace %s\n", deploymentName, namespace) - } - - return nil -} - -// createService 鍒涘缓鎸囧畾鐨� Service -func createService(clientset *kubernetes.Clientset, namespace, serviceName string) error { - fmt.Println("\033[1;37;40mCreating Service:", serviceName, "\033[0m") - - nodePort, err := getRandomNodePort(clientset) - if err != nil { - return err - } - - service := &apiv1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: serviceName, - }, - Spec: apiv1.ServiceSpec{ - Selector: map[string]string{ - "cid": namespace, - }, - Type: apiv1.ServiceTypeNodePort, - Ports: []apiv1.ServicePort{ - { - Name: "http", - Protocol: apiv1.ProtocolTCP, - Port: port, - TargetPort: intstr.FromInt(int(port)), - NodePort: nodePort, - }, - }, - }, - } - - _, err = clientset.CoreV1().Services(namespace).Create(context.TODO(), service, metav1.CreateOptions{}) - if err != nil { - if !errors.IsAlreadyExists(err) { - return fmt.Errorf("failed to create Service: %v", err) - } - fmt.Printf("Service %s already exists in Namespace %s\n", serviceName, namespace) - } else { - fmt.Printf("Service %s created in Namespace %s\n", serviceName, namespace) - } - - return nil -} - -// getRandomNodePort 鑾峰彇涓�涓湭浣跨敤鐨勯殢鏈� NodePort -func getRandomNodePort(clientset *kubernetes.Clientset) (int32, error) { - // 鑾峰彇涓�涓殢鏈虹殑 NodePort - nodePort := int32(0) - for { - // 鐢熸垚涓�涓殢鏈虹殑 NodePort - nodePort = generateRandomNodePort() - - // 妫�鏌ヨ NodePort 鏄惁宸茶浣跨敤 - used, err := isNodePortUsed(clientset, nodePort) + // 璇诲彇閰嶇疆鏂囦欢 + err := viper.ReadInConfig() if err != nil { - return 0, err - + log.Fatalf("Failed to read config file: %v", err) } - // 濡傛灉鏈浣跨敤锛屽垯鏍囪涓哄凡浣跨敤锛屽苟閫�鍑哄惊鐜� - if !used { - usedNodePorts[nodePort] = true - break + // 瑙f瀽閰嶇疆鏂囦欢涓殑瀛楁 + var rancherClusterConfig rancher.RancherClusterConfig + err = viper.Unmarshal(&rancherClusterConfig) + if err != nil { + log.Fatalf("Failed to unmarshal config: %v", err) } + clusterName := "kubernetus" + fmt.Println(rancherClusterConfig) + cluster_test(clusterName, rancherClusterConfig) } - return nodePort, nil -} - -// generateRandomNodePort 鐢熸垚涓�涓殢鏈虹殑 NodePort -func generateRandomNodePort() int32 { - // 鍦ㄨ寖鍥� 30000-32767 涓敓鎴愰殢鏈烘暟浣滀负 NodePort - return int32(rand.Intn(32767-30000+1) + 30000) -} - -// isNodePortUsed 妫�鏌ユ寚瀹氱殑 NodePort 鏄惁宸茶浣跨敤 -func isNodePortUsed(clientset *kubernetes.Clientset, nodePort int32) (bool, error) { - // 鑾峰彇鎵�鏈� Service - services, err := clientset.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return false, err - } - - // 妫�鏌ユ瘡涓� Service 鐨� NodePort 鏄惁涓庢寚瀹氱殑 NodePort 鐩稿悓 - for _, svc := range services.Items { - for _, port := range svc.Spec.Ports { - if port.NodePort == nodePort { - return true, nil - } - } - } - - return false, nil -} - -// DeleteResources 鍒犻櫎鎸囧畾鐨� Namespace銆丏eployment 鍜� Service -func DeleteResources(clientset *kubernetes.Clientset, namespace, deploymentName, serviceName string) error { - fmt.Println("\033[1;37;40mDeleting resources in Namespace:", namespace, "\033[0m") - - // 鍒犻櫎 Deployment - err := deleteDeployment(clientset, namespace, deploymentName) - if err != nil { - return err - } - - // 鍒犻櫎 Service - err = deleteService(clientset, namespace, serviceName) - if err != nil { - return err - } - - // 鍒犻櫎 Namespace - err = deleteNamespace(clientset, namespace) - if err != nil { - return err - } - - return nil -} - -// deleteDeployment 鍒犻櫎鎸囧畾鐨� Deployment -func deleteDeployment(clientset *kubernetes.Clientset, namespace, deploymentName string) error { - fmt.Println("\033[1;37;40mDeleting Deployment:", deploymentName, "\033[0m") - - err := clientset.AppsV1().Deployments(namespace).Delete(context.TODO(), deploymentName, metav1.DeleteOptions{}) - if err != nil { - if errors.IsNotFound(err) { - fmt.Printf("Deployment %s not found in Namespace %s\n", deploymentName, namespace) - } else { - return fmt.Errorf("failed to delete Deployment: %v", err) - } - } else { - fmt.Printf("Deployment %s deleted from Namespace %s\n", deploymentName, namespace) - } - - return nil -} - -// deleteService 鍒犻櫎鎸囧畾鐨� Service -func deleteService(clientset *kubernetes.Clientset, namespace, serviceName string) error { - fmt.Println("\033[1;37;40mDeleting Service:", serviceName, "\033[0m") - - err := clientset.CoreV1().Services(namespace).Delete(context.TODO(), serviceName, metav1.DeleteOptions{}) - if err != nil { - if errors.IsNotFound(err) { - fmt.Printf("Service %s not found in Namespace %s\n", serviceName, namespace) - } else { - return fmt.Errorf("failed to delete Service: %v", err) - } - } else { - fmt.Printf("Service %s deleted from Namespace %s\n", serviceName, namespace) - } - - return nil -} - -// deleteNamespace 鍒犻櫎鎸囧畾鐨� Namespace -func deleteNamespace(clientset *kubernetes.Clientset, namespace string) error { - fmt.Println("\033[1;37;40mDeleting Namespace:", namespace, "\033[0m") - - err := clientset.CoreV1().Namespaces().Delete(context.TODO(), namespace, metav1.DeleteOptions{}) - if err != nil { - if errors.IsNotFound(err) { - fmt.Printf("Namespace %s not found\n", namespace) - } else { - return fmt.Errorf("failed to delete Namespace: %v", err) - } - } else { - fmt.Printf("Namespace %s deleted\n", namespace) - } - - return nil -} - -// homeDir 鑾峰彇褰撳墠鐢ㄦ埛鐨勫鐩綍璺緞 -func homeDir() string { - if h := os.Getenv("HOME"); h != "" { - return h - } - return os.Getenv("USERPROFILE") // Windows 鐜涓嬭幏鍙栫敤鎴风洰褰� -} - -// GetServiceNodePort 鑾峰彇鎸囧畾 Service 鐨� NodePort -func GetServiceNodePort(clientset *kubernetes.Clientset, namespace, serviceName string) (int32, error) { - svc, err := clientset.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{}) - if err != nil { - return 0, fmt.Errorf("failed to get Service: %v", err) - } - - // 妫�鏌� Service 绫诲瀷鏄惁涓� NodePort - if svc.Spec.Type != apiv1.ServiceTypeNodePort { - return 0, fmt.Errorf("Service %s is not of type NodePort", serviceName) - } - - // 鑾峰彇绗竴涓鍙g殑 NodePort - if len(svc.Spec.Ports) > 0 { - return svc.Spec.Ports[0].NodePort, nil - } - - return 0, fmt.Errorf("no ports defined for Service %s", serviceName) } -- Gitblit v1.8.0