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.HttpNodePort, 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",
|
},
|
{
|
Name: "HOST",
|
ValueFrom: &apiv1.EnvVarSource{
|
FieldRef: &apiv1.ObjectFieldSelector{
|
APIVersion: "v1",
|
FieldPath: "status.hostIP",
|
},
|
},
|
},
|
{
|
Name: "ADMIN_GRPC",
|
Value: "$(HOST):50051",
|
},
|
}
|
|
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 {
|
httpServiceName := config.ServiceName + "-http"
|
fmt.Println("\033[1;37;40mCreating Service:", httpServiceName, "\033[0m")
|
|
service := &apiv1.Service{
|
ObjectMeta: metav1.ObjectMeta{
|
Name: httpServiceName,
|
},
|
Spec: apiv1.ServiceSpec{
|
Selector: map[string]string{
|
"cid": c.GetCid(config),
|
},
|
Type: apiv1.ServiceTypeNodePort,
|
Ports: []apiv1.ServicePort{
|
{
|
Name: "http",
|
Protocol: apiv1.ProtocolTCP,
|
Port: config.HttpPort, // 集群内部访问端口
|
TargetPort: intstr.FromInt(int(config.HttpPort)), // 容器对外端口
|
NodePort: config.HttpNodePort, // 外部访问端口
|
},
|
},
|
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", httpServiceName, config.NameSpace)
|
} else {
|
log.Printf("Service %s created in Namespace %s\n", httpServiceName, config.NameSpace)
|
}
|
|
clusterIPService := &apiv1.Service{
|
ObjectMeta: metav1.ObjectMeta{
|
Name: config.ServiceName,
|
},
|
Spec: apiv1.ServiceSpec{
|
Selector: map[string]string{
|
"cid": c.GetCid(config),
|
},
|
Type: apiv1.ServiceTypeClusterIP,
|
Ports: []apiv1.ServicePort{
|
{
|
Name: "grpc",
|
Protocol: apiv1.ProtocolTCP,
|
Port: config.RpcPort, // 集群内部访问端口
|
TargetPort: intstr.FromInt(int(config.RpcPort)), // 容器对外端口
|
},
|
},
|
SessionAffinity: apiv1.ServiceAffinityClientIP,
|
},
|
}
|
|
_, err = config.Client.CoreV1().Services(config.NameSpace).Create(context.TODO(), clusterIPService, metav1.CreateOptions{})
|
|
if err != nil {
|
if !errors.IsAlreadyExists(err) {
|
return fmt.Errorf("failed to create clusterIP 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")
|
}
|