Jelajahi Sumber

refactor: 整合部署步骤的deploy流程,使其更好理解

370774330@qq.com 5 tahun lalu
induk
melakukan
aa4b563fd7

+ 1 - 0
web/src/main/java/cn/seecoder/web/core/pipeline/config/HandlerConfigTable.java

@@ -35,6 +35,7 @@ public class HandlerConfigTable {
         handlerConfigMap.put("k8s-service", K8sServiceHandler.class);
         handlerConfigMap.put("k8s-ingress", K8sIngressHandler.class);
         handlerConfigMap.put("k8s-namespace", K8sNamespaceHandler.class);
+        handlerConfigMap.put("deploy", DeployHandler.class);
         handlerConfigMap.put("api-test", ApiTestHandler.class);
     }
 

+ 212 - 0
web/src/main/java/cn/seecoder/web/core/pipeline/handler/DeployHandler.java

@@ -0,0 +1,212 @@
+package cn.seecoder.web.core.pipeline.handler;
+
+import cn.seecoder.api.ApplicationProperties;
+import cn.seecoder.api.k8s.*;
+import cn.seecoder.api.k8s.exception.K8sApiException;
+import cn.seecoder.api.k8s.model.*;
+import cn.seecoder.api.k8s.vo.SecretVO;
+import cn.seecoder.common.util.SpringUtil;
+import cn.seecoder.web.core.pipeline.Context;
+import cn.seecoder.web.core.pipeline.PipelineException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpStatus;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author PuHong Weng
+ * @date 2021/5/1
+ * @description:
+ */
+@Slf4j
+public class DeployHandler extends AbstractHandler{
+
+    private final SecretApi secretApi;
+
+    private final DeploymentApi deploymentApi;
+
+    private final ApplicationProperties applicationProperties;
+
+    private final NamespaceApi namespaceApi;
+
+    private final ServiceApi serviceApi;
+
+    private final IngressApi ingressApi;
+
+    private final static String DEFAULT_IMAGE_PULL_SECRET_NAME = "seecoder-devcloud-image-pull-secret";
+
+    public DeployHandler(){
+        this.applicationProperties = SpringUtil.getBean(ApplicationProperties.class);
+        secretApi = SpringUtil.getBean(SecretApi.class);
+        deploymentApi = SpringUtil.getBean(DeploymentApi.class);
+        namespaceApi = SpringUtil.getBean(NamespaceApi.class);
+        serviceApi = SpringUtil.getBean(ServiceApi.class);
+        ingressApi = SpringUtil.getBean(IngressApi.class);
+    }
+
+    private Integer port;
+
+    @Override
+    public void process(Context context) throws PipelineException {
+
+        //1. 创建namespace
+        Namespace k8sNamespace = new Namespace();
+        k8sNamespace.setName(context.getNamespace());
+        //todo namespace在底下资源未删除时,不能轻易删除重建,只能直接通过异常查是否已创建,丑陋,待修改
+        try {
+            List<Namespace> namespaces = namespaceApi.getByCondition(K8sObjectRequest.builder()
+                    .name(context.getNamespace()).build());
+            if (namespaces.size() == 0) {
+                namespaceApi.create(k8sNamespace);
+                log.info("Namespace创建成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+            } else {
+                log.info("Namespace已经存在, 无需新建: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+            }
+        } catch (K8sApiException e) {
+            context.appendErrorResult(PipelineException.NAMESPACE_CREATE_ERROR, e);
+            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.NAMESPACE_CREATE_ERROR, e);
+        }
+        context.appendSuccessResult("K8s Namespace创建成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+
+
+        //2. 创建deployment
+        //2.0. 镜像配置信息获取
+        String imageName = context.getConfigs().get("imageName");
+        String imageTag = context.getConfigs().get("imageTag");
+        int replicas = 1;
+        String namespace = context.getNamespace();
+        String deployName = context.getDeployName();
+
+        //2.1. 配置容器暴露端口
+        ContainerPort containerPort = ContainerPort.builder()
+                .port(port)
+                .build();
+
+        //2.2. 配置容器
+        Container container = Container.builder()
+                .image(applicationProperties.getDocker().getRegistry() + "/" + imageName + ":" + imageTag)
+                .name(deployName + K8sConstants.CONTAINER_SUFFIX)
+                .ports(Collections.singleton(containerPort))
+                .build();
+
+        //2.3. 配置deployment
+        Deployment deployment = Deployment.builder()
+                .replicas(replicas)
+                .containers(Collections.singletonList(container))
+                .build();
+        deployment.setName(deployName + K8sConstants.DEPLOYMENT_SUFFIX);
+        deployment.setNamespace(namespace);
+        deployment.setLabel(K8sConstants.APPLICATION_LABEL, deployName);
+
+        //2.4. 检查镜像仓库secret是否存在,没有则创建。
+        SecretVO secretVO = secretApi.getSecretByName(namespace, DEFAULT_IMAGE_PULL_SECRET_NAME);
+        if (secretVO == null) {
+            secretApi.createPrivateRegistrySecret(
+                    namespace,
+                    DEFAULT_IMAGE_PULL_SECRET_NAME,
+                    applicationProperties.getDocker().getRegistry(),
+                    applicationProperties.getDocker().getRegistryUsername(),
+                    applicationProperties.getDocker().getRegistryPassword()
+            );
+        }
+        deployment.setImagePullSecrets(Collections.singletonList(DEFAULT_IMAGE_PULL_SECRET_NAME));
+
+
+        //2.5. 创建Deployment实例
+        try {
+            List<Deployment> deployments = deploymentApi.getByCondition(K8sObjectRequest.builder()
+                    .namespace(context.getNamespace())
+                    .name(context.getDeployName() + K8sConstants.DEPLOYMENT_SUFFIX)
+                    .build());
+            if (deployments.size() == 0) {
+                deploymentApi.create(deployment);
+                log.info("deployment创建成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+            } else {
+                deploymentApi.update(deployment);
+                log.info("deployment更新成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+
+            }
+        } catch (K8sApiException e) {
+            context.appendErrorResult(PipelineException.DEPLOYMENT_CREATE_ERROR, e);
+            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.DEPLOYMENT_CREATE_ERROR, e);
+        }
+
+        //3. 创建service
+        //3.1. 配置K8s的service
+        Service service = new Service();
+        service.setNamespace(context.getNamespace());
+        service.setName(context.getDeployName() + K8sConstants.SERVICE_SUFFIX);
+        //标签选择器选择 此项目对应的deployment的name
+        service.setSelectors(Collections.singletonMap(K8sConstants.APPLICATION_LABEL, context.getDeployName()));
+        service.setServicePorts(
+                Collections.singleton(ServicePort.builder().port(port).targetPort(port).build())
+        );
+
+        //3.2. 创建service实例
+        try {
+            List<Service> services = serviceApi.getByCondition(K8sObjectRequest.builder()
+                    .namespace(context.getNamespace())
+                    .name(context.getDeployName() + K8sConstants.SERVICE_SUFFIX)
+                    .build());
+            if (services.size() == 0) {
+                serviceApi.create(service);
+                log.info("service创建成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+            } else {
+                serviceApi.update(service);
+                log.info("service更新成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+            }
+        } catch (K8sApiException e) {
+            context.appendErrorResult(PipelineException.SERVICE_CREATE_ERROR, e);
+            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.SERVICE_CREATE_ERROR, e);
+        }
+        context.appendSuccessResult("K8s Service创建成功: [namespace: " + context.getNamespace() + ", deployName: " + context.getDeployName() + "]");
+
+        //4. 创建ingress
+        //4.1. ingress路径规则
+        Ingress.IngressRule ingressRule = new Ingress.IngressRule();
+        ingressRule.setHost( deployName+"."+namespace + applicationProperties.getK8s().getIngressHostSuffix());
+        Ingress.IngressPath path = new Ingress.IngressPath();
+        path.setPath("/");
+        path.setPort(port);
+        path.setServiceName(deployName+K8sConstants.SERVICE_SUFFIX);
+        ingressRule.setRuleValues(Collections.singleton(path));
+
+        //4.2. 配置ingress
+        Ingress ingress = new Ingress();
+        ingress.setName(deployName + K8sConstants.INGRESS_SUFFIX);
+        ingress.setNamespace(namespace);
+        ingress.setHttpRules(Collections.singletonList(ingressRule));
+        ingress.setLabel(K8sConstants.APPLICATION_LABEL, deployName);
+        ingress.setAnnotation("kubernetes.io/ingress.class","nginx");
+        ingress.setAnnotation("kubernetes.io/ingress.provider","nginx");
+        ingress.setAnnotation("nginx.ingress.kubernetes.io/rewrite-target","/");
+        ingress.setAnnotation("nginx.ingress.kubernetes.io/proxy-body-size","512m");
+        ingress.setAnnotation("nginx.ingress.kubernetes.io/proxy-connect-timeout","15");
+        ingress.setAnnotation("nginx.ingress.kubernetes.io/proxy-read-timeout","600");
+        ingress.setAnnotation("nginx.ingress.kubernetes.io/service-upstream","true");
+
+        //4.3. 创建ingress实例
+        try {
+            List<Ingress> ingresses = ingressApi.getByCondition(K8sObjectRequest.builder()
+                    .namespace(context.getNamespace())
+                    .name(context.getDeployName() + K8sConstants.INGRESS_SUFFIX)
+                    .build());
+            if (ingresses.size()==0){
+                ingressApi.create(ingress);
+                log.info("ingress创建成功");
+            } else{
+                ingressApi.update(ingress);
+                log.info("ingress更新成功");
+            }
+        } catch (K8sApiException e){
+            context.appendErrorResult(PipelineException.INGRESS_CREATE_ERROR,e);
+            throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,PipelineException.INGRESS_CREATE_ERROR,e);
+        }
+
+        //4. 存入访问路径
+        context.getConfigs().put("accessUrl",namespace + applicationProperties.getK8s().getIngressHostSuffix()+"/" + deployName + "/");
+        context.appendSuccessResult("K8s Ingress创建成功");
+
+    }
+}

+ 1 - 19
web/src/main/resources/template/config/NODE_10.json

@@ -8,28 +8,10 @@
     }
   },
   {
-    "name": "k8s-namespace",
-    "active": true,
-    "configs": {
-    }
-  },
-  {
-    "name": "k8s-deployment",
+    "name": "deploy",
     "active": true,
     "configs": {
       "port": "#todo"
     }
-  },
-  {
-    "name": "k8s-service",
-    "active": true,
-    "configs": {
-    }
-  },
-  {
-    "name": "k8s-ingress",
-    "active": true,
-    "configs": {
-    }
   }
 ]

+ 1 - 19
web/src/main/resources/template/config/SPRINGBOOT_JAVA8.json

@@ -9,30 +9,12 @@
     }
   },
   {
-    "name": "k8s-namespace",
-    "active": true,
-    "configs": {
-    }
-  },
-  {
-    "name": "k8s-deployment",
+    "name": "deploy",
     "active": true,
     "configs": {
       "port": "#todo"
     }
   },
-  {
-    "name": "k8s-service",
-    "active": true,
-    "configs": {
-    }
-  },
-  {
-    "name": "k8s-ingress",
-    "active": true,
-    "configs": {
-    }
-  },
   {
     "name": "api-test",
     "active": true,