package k8s import ( "context" "fmt" 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" "log" "strconv" ) type CrmCreate struct{} func (c *CrmCreate) CreateDeploymentAndService(config Config, extendEnv map[string]string) error { fmt.Println("\033[1;37;40mCreating resources in Namespace:", config.NameSpace, "\033[0m") fmt.Printf("Crm CreateDeployment config:%+v\n", config) // 检测并删除已存在的 Deployment 和 Service err := CheckAndDeleteResources(config.Client, config.NameSpace, config.DeploymentName, config.ServiceName) if err != nil { return err } config.HttpPort, err = getRandomNodePort(config.Client) if err != nil { return err } // 创建 Deployment err = c.CreateDeployment(config, extendEnv) if err != nil { return err } log.Printf("Waiting for Deployment %s to be ready...\n", config.DeploymentName) // 创建 Service err = c.CreateService(config) if err != nil { return err } return nil } func (c *CrmCreate) CreateEnv(config Config, pairs map[string]string) []apiv1.EnvVar { envs := []apiv1.EnvVar{ { Name: "DB_HOST", Value: config.DBHost, }, { Name: "DB_PORT", Value: strconv.Itoa(3306), }, { Name: "DB_NAME", Value: config.NameSpace + "_crm", }, { Name: "DB_USER", Value: config.NameSpace, }, { Name: "DB_PASSWD", Value: config.NameSpace + "@Basic2023", }, } for name, value := range pairs { envs = append(envs, apiv1.EnvVar{ Name: name, Value: value, }) } return envs } func (c *CrmCreate) CreateDeployment(config Config, extendEnv map[string]string) error { fmt.Println("\033[1;37;40mCreating Deployment:", config.DeploymentName, "\033[0m") envs := c.CreateEnv(config, extendEnv) deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: config.DeploymentName, }, Spec: appsv1.DeploymentSpec{ Replicas: &replicas, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "cid": c.GetCid(config), }, }, Template: apiv1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ "cid": c.GetCid(config), }, }, Spec: apiv1.PodSpec{ TopologySpreadConstraints: []apiv1.TopologySpreadConstraint{ { MaxSkew: 1, TopologyKey: "kubernetes.io/hostname", WhenUnsatisfiable: apiv1.DoNotSchedule, LabelSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "cid": c.GetCid(config), }, }, }, }, Containers: []apiv1.Container{ { Name: config.DeploymentName, Image: config.Image, Env: envs, ImagePullPolicy: apiv1.PullIfNotPresent, // 设置镜像拉取策略为 Always }, }, }, }, }, } _, err := config.Client.AppsV1().Deployments(config.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", config.DeploymentName, config.NameSpace) } else { fmt.Printf("Deployment %s created in Namespace %s\n", config.DeploymentName, config.NameSpace) } return nil } // createService 创建指定的 Service func (c *CrmCreate) CreateService(config Config) error { fmt.Println("\033[1;37;40mCreating Service:", config.ServiceName, "\033[0m") service := &apiv1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: config.ServiceName, }, Spec: apiv1.ServiceSpec{ Selector: map[string]string{ "cid": c.GetCid(config), }, Type: apiv1.ServiceTypeNodePort, Ports: []apiv1.ServicePort{ { Name: "http", Protocol: apiv1.ProtocolTCP, Port: port, // 集群内部访问端口 TargetPort: intstr.FromInt(int(port)), // 容器对外端口 NodePort: config.HttpPort, // 外部访问端口 }, }, SessionAffinity: apiv1.ServiceAffinityClientIP, }, } _, err := config.Client.CoreV1().Services(config.NameSpace).Create(context.TODO(), service, metav1.CreateOptions{}) if err != nil { if !errors.IsAlreadyExists(err) { return fmt.Errorf("failed to create Service: %v", err) } log.Printf("Service %s already exists in Namespace %s\n", config.ServiceName, config.NameSpace) } else { log.Printf("Service %s created in Namespace %s\n", config.ServiceName, config.NameSpace) } return nil } func (c *CrmCreate) GetCid(config Config) string { return fmt.Sprintf("%v-%v", config.NameSpace, "crm") }