Przeglądaj źródła

test: docker image build

370774330@qq.com 5 lat temu
rodzic
commit
867be2969d

+ 7 - 0
api/pom.xml

@@ -26,6 +26,13 @@
         <dependency>
             <groupId>com.nju.edu</groupId>
             <artifactId>seecoder-gitlab-client</artifactId>
+            <!-- 这个包引入的log产生了绑定冲突,所以排除掉 -->
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.logging.log4j</groupId>
+                    <artifactId>log4j-slf4j-impl</artifactId>
+                </exclusion>
+            </exclusions>
             <version>0.1.0</version>
         </dependency>
         <!-- https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit -->

+ 7 - 0
api/src/main/java/seecoder/devcloud/api/ApplicationProperties.java

@@ -49,6 +49,13 @@ public class ApplicationProperties {
 
 		private String host;
 
+		/**
+		 * 是否开启tls验证
+		 */
+		private Boolean tls = false;
+
+		private String certificatesPath = "docker/";
+
 		private String registry;
 
 		private String registryUsername;

+ 2 - 1
api/src/main/java/seecoder/devcloud/api/DevcloudApiAutoConfiguration.java

@@ -2,6 +2,7 @@ package seecoder.devcloud.api;
 
 import com.nju.edu.gitlab.SeecoderGitlabApi;
 import com.nju.edu.gitlab.SeecoderGitlabClient;
+import com.spotify.docker.client.exceptions.DockerCertificateException;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -45,7 +46,7 @@ public class DevcloudApiAutoConfiguration {
 
     @Bean
     @ConditionalOnBean(ApplicationProperties.class)
-    public DockerApi dockerApi(){
+    public DockerApi dockerApi() throws DockerCertificateException {
         return new DockerApiImpl(applicationProperties());
     }
 

+ 20 - 8
api/src/main/java/seecoder/devcloud/api/docker/impl/DockerApiImpl.java

@@ -1,12 +1,10 @@
 package seecoder.devcloud.api.docker.impl;
 
 
-import com.spotify.docker.client.DefaultDockerClient;
-import com.spotify.docker.client.DockerClient;
-import com.spotify.docker.client.DockerConfigReader;
-import com.spotify.docker.client.ProgressHandler;
+import com.spotify.docker.client.*;
 import com.spotify.docker.client.auth.ConfigFileRegistryAuthSupplier;
 import com.spotify.docker.client.auth.RegistryAuthSupplier;
+import com.spotify.docker.client.exceptions.DockerCertificateException;
 import com.spotify.docker.client.exceptions.DockerException;
 import com.spotify.docker.client.messages.Image;
 import com.spotify.docker.client.messages.ProgressMessage;
@@ -14,11 +12,14 @@ import lombok.extern.apachecommons.CommonsLog;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.system.ApplicationHome;
 import org.springframework.stereotype.Component;
+import org.springframework.util.ResourceUtils;
 import seecoder.devcloud.api.ApplicationProperties;
 import seecoder.devcloud.api.docker.DockerApi;
 
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.net.URI;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -34,13 +35,24 @@ public class DockerApiImpl implements DockerApi {
     private final String registry;
 
     @Autowired
-    public DockerApiImpl(ApplicationProperties properties){
+    public DockerApiImpl(ApplicationProperties properties) throws DockerCertificateException {
         registry = properties.getDocker().getRegistry();
-        client = new DefaultDockerClient(properties.getDocker().getHost());
+        Path dockerConfigPath = null;
+        try {
+            dockerConfigPath = ResourceUtils.getFile("classpath:docker").toPath();
+            if (properties.getDocker().getTls()){
+                client = new DefaultDockerClient(URI.create(properties.getDocker().getHost()), new DockerCertificates(dockerConfigPath));
+            } else {
+                client = new DefaultDockerClient(properties.getDocker().getHost());
+            }
+        } catch (FileNotFoundException e) {
+            throw new DockerCertificateException("设置读取失败");
+        }
+
         defaultHandler = new NoActionProgressHandler();
         ApplicationHome applicationHome = new ApplicationHome(getClass());
-        Path path = Paths.get(applicationHome.getDir().getAbsolutePath(), "docker-config.json");
-        registryAuthSupplier = new ConfigFileRegistryAuthSupplier(new DockerConfigReader(), path);
+        // Path path = Paths.get(applicationHome.getDir().getAbsolutePath(), "docker-config.json");
+        registryAuthSupplier = new ConfigFileRegistryAuthSupplier(new DockerConfigReader(), Paths.get(dockerConfigPath.toString(),"docker-config.json"));
     }
 
     @Override

+ 0 - 6
core/pom.xml

@@ -28,17 +28,11 @@
             <artifactId>api</artifactId>
             <version>0.0.1-SNAPSHOT</version>
         </dependency>
-
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>
         </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>

+ 0 - 9
core/src/main/java/seecoder/devcloud/core/pipeline/Context.java

@@ -24,19 +24,10 @@ public class Context {
 
     private Integer pipelineId;
 
-    private String pipelineName;
-
     private String templateName;
 
-
-    /**
-     * 流水线所属namespace
-     */
     private String namespace;
 
-    /**
-     * 项目名称
-     */
     private String projectName;
 
 

+ 5 - 1
core/src/main/java/seecoder/devcloud/core/pipeline/PipelineFactory.java

@@ -23,9 +23,11 @@ public class PipelineFactory {
      * @param configJson configJson 流水线配置的json字符串
      * @param namespace 流水线的k8s namespace,devcloud后端采用{@code Project}中的{@code name}作为namespace
      * @param projectName 流水线部署k8s的应用名称,devcloud后端采用{@code Pipeline}中的{@code name} 作为project name
+     * @param pipelineId 流水线id
+     * @param templateName 模板名称
      * @return
      */
-    public static Pipeline init(String configJson, String namespace, String projectName) throws PipelineException {
+    public static Pipeline init(String configJson, String namespace, String projectName, Integer pipelineId, String templateName) throws PipelineException {
 
         ObjectMapper mapper = new ObjectMapper();
         List<HandlerConfig> handlerConfigs = null;
@@ -39,6 +41,8 @@ public class PipelineFactory {
         Context context = Context.builder()
                 .projectName(projectName)
                 .namespace(namespace)
+                .pipelineId(pipelineId)
+                .templateName(templateName)
                 .build();
 
         Handler firstHandler = initHandlerChainAndContext(handlerConfigs,context.getConfigs());

+ 4 - 1
core/src/main/java/seecoder/devcloud/core/pipeline/handler/DockerImageBuildHandler.java

@@ -58,11 +58,13 @@ public class DockerImageBuildHandler extends AbstractHandler {
             context.appendErrorResult(PipelineException.GIT_CLONE_ERROR,e);
             throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.GIT_CLONE_ERROR,e);
         }
-        //2. 帮助学生创建dockerfile文件
+        //2. 帮助学生创建dockerfile和maven的setting.xml文件
         //todo 待测试创建非临时文件会不会有问题
         Path dockerfile = Paths.get(directory.toString(), "Dockerfile");
+        Path mavenSetting = Paths.get(directory.toString(), "settings.xml");
         try {
             PipelineTemplateTable.copyTemplateDockerfile(templateName,dockerfile);
+            PipelineTemplateTable.copyTemplateMavenSetting(mavenSetting);
         } catch (IOException e) {
             context.appendErrorResult(PipelineException.DOCKERFILE_CREATE_ERROR,e);
             throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,PipelineException.DOCKERFILE_CREATE_ERROR,e);
@@ -76,6 +78,7 @@ public class DockerImageBuildHandler extends AbstractHandler {
                 @Override
                 public void progress(ProgressMessage message) throws DockerException {
                     String value = message.stream();
+                    System.out.println(value);
                     if (value == null) {
                         value = "";
                     }

+ 14 - 3
core/src/main/java/seecoder/devcloud/core/pipeline/template/PipelineTemplateTable.java

@@ -55,8 +55,19 @@ public class PipelineTemplateTable {
      */
     public static void copyTemplateDockerfile(String templateName, Path dockerfile) throws IOException {
         Files.createFile(dockerfile);
-        File template = ResourceUtils.getFile("classpath:dockerfile/" + templateName);
-        FileUtils.copyDirectory(template, dockerfile.toFile());
+        File template = ResourceUtils.getFile("classpath:template/dockerfile/" + templateName);
+        FileUtils.copyFile(template, dockerfile.toFile());
+    }
+
+    /**
+     * 读取默认的maven setting信息,复制进项目
+     * (帮助学生部署的项目可以正确拉到镜像)
+     * @param mavenSetting 需要写入的settings文件路径
+     * @return
+     */
+    public static void copyTemplateMavenSetting(Path mavenSetting) throws IOException {
+        File template = ResourceUtils.getFile("classpath:template/settings.xml");
+        FileUtils.copyFile(template, mavenSetting.toFile());
     }
 
     /**
@@ -66,7 +77,7 @@ public class PipelineTemplateTable {
         File file = null;
         String template = null;
         try {
-            file = ResourceUtils.getFile("classpath:config/" + templateName + ".json");
+            file = ResourceUtils.getFile("classpath:template/config/" + templateName + ".json");
             List<String> lines = Files.readAllLines(file.toPath());
             StringBuffer sb = new StringBuffer();
             for (String line : lines) {

+ 4 - 3
core/src/main/resources/application-local.yml

@@ -38,13 +38,14 @@ seecoder:
   mail:
     from: 370774330@qq.com
   git:
-    password: mock
-    username: mock
+    username: root
+    password: rootroot
   docker:
-    host: unix:///var/run/docker.sock
+    host: https://192.168.99.105:2376
     registry: 192.168.99.105:30060
     registryUsername: admin
     registryPassword: admin
+    tls: true
 
 
 

+ 18 - 0
core/src/main/resources/docker/ca.pem

@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdmgAwIBAgIRAKQJIyz98Irf8Ay5x5snj4owDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHZGVwb25pYTAeFw0yMDEyMDIxNTIyMDBaFw0yMzExMTcxNTIy
+MDBaMBIxEDAOBgNVBAoTB2RlcG9uaWEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDMC7rbvdWIMe2bNzWKVeBTlVHdBjc/XAi2LzUeRAY/G9ibB59uqjLG
+L62kjqMIP7p2WAQA2yD23hBXeHi+CIh0qItTZXa6KuguGUsOJCtISReDPVd3c0Ub
+6fLCHYk/PpGUeN94M29CdhB/O2oyslapeUQQnNxukFqYne6oWVOHtCZQbM7NvRaa
+IGguMJZnoCIsaVSyNAvQ2ftS+GK4vWdQ1Q+5UgGAW42gCwT/ilcXHXcImzoovVsf
+uTsprMyY5iloZiicf5hpjHx7XNeYwOvPGFwf00VgIlxtjD0CCl8JyXyYs0opx5xT
+YpMQuHp6z3CFWPWIKThMgrtBBG0+rxIDAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIC
+rDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQf1wYXm/AUnqG9rwDBZMdNETkP
+AzANBgkqhkiG9w0BAQsFAAOCAQEAF3XObE3Lmi5rh+gYA35yuAjRvEbmS42Rkn0L
+ntzYzet18OG/2ZUjhLwElZlQln/3yHhsNsdETUuRbVjoCoFQoMjcoN7JOQHn2/GF
+QuLnXaGwHLBwXDl/ogSPJfShzw/vUV2+EXMi+3TV7dVJ43h26Eczqvkem/mlqkpc
+LMsd+7iAIFII66MBktW+SajvFS2v7YxABPJjH92O2t9JklkmgFoAYeE/FyXbolPy
+IzX0ps6+kqcgxZ2fu5w2XFWSNfZfT836mIDfFro2qDsdMV61cCHlHdyvfHJENxla
+x+yjvPZVoANAzWZzYInO/aCHYoZTjArg+Pcl+8cmEpzg086yxA==
+-----END CERTIFICATE-----

+ 19 - 0
core/src/main/resources/docker/cert.pem

@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDETCCAfmgAwIBAgIRALOlivIw9909Q3Bp/0zOI7gwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHZGVwb25pYTAeFw0yMDEyMDIxNTIyMDBaFw0yMzExMTcxNTIy
+MDBaMB4xHDAaBgNVBAoME2RlcG9uaWEuPGJvb3RzdHJhcD4wggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDwnxAQQnbpT+ukGvk33H2JJbXHsDzOS/5ej+81
+f1zXJCUJN45GuiPNJs2r6m4HGKRPO2r+2tJhBwbw0XoePOjobMMA8sQEvpTkllVg
+IZr7tnFcb1tB83irvueW8SLw8z/PW2xWqw5oq0F2QZjzYdvFU/iFw64Ezw2yfKZU
+ut4p6xCnsZKkvqU+MoOrGLfFZrybHC1Yq8IZs12g4ifhsUURPOYEe7sBlempfWZt
+QpZ348sUqpo/M5hU3O+whWjcLtYb5xckKRgwo6C5TvkrZD13fAx8C+2pFY9ueIeV
+hVSMl+IWkfjbenJ8OE+GRdERTSRzXuYSrPOF63fvaToaJg7pAgMBAAGjVjBUMA4G
+A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
+MB8GA1UdIwQYMBaAFB/XBheb8BSeob2vAMFkx00ROQ8DMA0GCSqGSIb3DQEBCwUA
+A4IBAQAHglVS6GYNKB6M1EznEUAKS+qXjIwgRbFL1gToCgMoaf5SnQCmNWIIFF15
+43n8drp/95x51CizorYJ+gJcXEtiW8dljWrOgm9ARvaCpQAIMwbqG6y4CjYqXLAW
+txXyX0TrZ7GHJp6RTtrmVofdTb9bCQRQmw241oBd3gb5t+2VfOZE2iJ1RTXWBZ3z
+TikVmnLmJNJgzmh8v1WOFJRd/VJJ6K8U/87m/LndOemCQtdxaEnwnkKy2lGk+sUV
+KAXAd3THnalo0ibVWIWDUxnTaMFWNpJwjgwwPDhFb4Px94Rry3lAlrQ4q9AfAmS9
+d1ZnhoqV+Pms6SUzEJ6NQ6jz4mxG
+-----END CERTIFICATE-----

+ 8 - 0
core/src/main/resources/docker/docker-config.json

@@ -0,0 +1,8 @@
+{
+  "auths": {
+    "http://192.168.99.105:30005": {
+      "username": "admin",
+      "password": "admin"
+    }
+  }
+}

+ 27 - 0
core/src/main/resources/docker/key.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA8J8QEEJ26U/rpBr5N9x9iSW1x7A8zkv+Xo/vNX9c1yQlCTeO
+RrojzSbNq+puBxikTztq/trSYQcG8NF6Hjzo6GzDAPLEBL6U5JZVYCGa+7ZxXG9b
+QfN4q77nlvEi8PM/z1tsVqsOaKtBdkGY82HbxVP4hcOuBM8NsnymVLreKesQp7GS
+pL6lPjKDqxi3xWa8mxwtWKvCGbNdoOIn4bFFETzmBHu7AZXpqX1mbUKWd+PLFKqa
+PzOYVNzvsIVo3C7WG+cXJCkYMKOguU75K2Q9d3wMfAvtqRWPbniHlYVUjJfiFpH4
+23pyfDhPhkXREU0kc17mEqzzhet372k6GiYO6QIDAQABAoIBAEo/2xYZXFYsajtO
+c37QVBCBCXHgKTNDce++HIN2lLByn9cTRJ0AjVGd2rNk+KTJ7tHgNOkFnwt/vp2L
+FlLEWt51yUq+nswT/x/2X8v1MrzflGWAmzljpuXgV9hU+oI9nYAf5vNrf1u/FMkn
+/smDdeyTN8oXEti7B6//FNhqfWmTXXhpygQrXeB2SGmH+kPgg851Kxi5lcz9DDBU
+GCgvvt0GL0i+q6rQ0e9Rwc87LxviG5lsgl+yA7TpzDkzpXQGKMtfzQpPUWsYRkoU
+qaebBUdWVX4Ldmwx6VmMACPvFnCg4lzFrc7ve8dZ/bmnHxMLkvSyP5DQ6hUFjTh6
+OxzzL60CgYEA9toSOTwngUIJADyG1CXQWoeCiSRx3XsU2PIxTkxo7DSUSwJMqwRv
+NEZhhOmDLNte2eDp6Wblk/xoBD0yQyXsjNaCs9GLZlzUcadg4zn2E/hqDyhX59dw
+oUVaKnkC7UZrhmJHbzbJtuvkerq22C4vJcd0zf9UqHdAaLNWMTROsCcCgYEA+Ynh
+s5c7wXab9rSurY8r85PpHo2dRWOn/CBm1xK4bY/lDDE2SRL7R3fzBDmxiL0ZtzFL
+pkwqlGq3kR3uCGKz5td6/c9aD9OpSoKLNfQ065PPdO+Ixi/sVP7O67OXBRu5Wkc1
+lHV4Gb9r21TldgFTXVGAl4LtNpa3sKJ6kGVZom8CgYEAjjVFCFoCPDHJs6wq1G7Q
+YEbuyYkIW9q7QNwN0ZitXV5RDAFQH7mXQttE9Of9nMroEsbCmqafnahsV/zVRt/D
+LcOqWmNeVmMmNC+D3oOWoxyaJQ9NzQ9NIGsurYc3S3AlI67cjlJW1J2C671C9rls
+iewk+0OcBs1keqzN+9yxdEMCgYBhBIKD2GCbLwokOMtRH0DvSqpv/o8O01gUZmSV
+aenabv+WZeu9LWwUtUX+do/Xoe3Fk5zd4u8LFRKZkRFioT1gmpZu55cUYC6JkYee
+Snvou2cFB7wdkbRIt2irqv8kNUszFkx2k9VF7W55r+AmqQ1IUs+0GGsxthdkzUbp
+rP3UcQKBgA4PC3h4OxpDnC3Usj5rZe0inkBq9W8yUlOJFKa+r0e6OQWaH7dLH3OG
+097YDXLZ0sRG4BOEnpqvlhIoNRvtmcYAOjoxaTOzqKnPZ9Xo7ppdz855VbVpAlkS
+oYPF9mWfnSt4E25z14Q/Is1Fan6FevlrKi2I2Y3ipB158SRstgyl
+-----END RSA PRIVATE KEY-----

+ 1 - 0
core/src/main/resources/docker/readme.md

@@ -0,0 +1 @@
+这个是本地测试连接时用的证书,实际生成环境直接通过 unix:/// 

+ 13 - 0
core/src/main/resources/template/settings.xml

@@ -0,0 +1,13 @@
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
+					http://maven.apache.org/xsd/settings-1.0.0.xsd">
+	<mirrors>
+		<mirror>
+			<id>nexus-aliyun</id>
+			<mirrorOf>central</mirrorOf>
+			<name>Nexus aliyun</name>
+			<url>http://maven.aliyun.com/nexus/content/groups/public</url>
+		</mirror>
+	</mirrors>
+</settings>

+ 17 - 5
core/src/test/java/seecoder/devcloud/core/CoreApplicationTests.java

@@ -16,10 +16,7 @@ import seecoder.devcloud.api.k8s.ServiceApi;
 import seecoder.devcloud.core.pipeline.Context;
 import seecoder.devcloud.core.pipeline.PipelineException;
 import seecoder.devcloud.core.pipeline.config.HandlerConfig;
-import seecoder.devcloud.core.pipeline.handler.K8sDeploymentHandler;
-import seecoder.devcloud.core.pipeline.handler.K8sIngressHandler;
-import seecoder.devcloud.core.pipeline.handler.K8sNamespaceHandler;
-import seecoder.devcloud.core.pipeline.handler.K8sServiceHandler;
+import seecoder.devcloud.core.pipeline.handler.*;
 
 import java.util.*;
 
@@ -96,7 +93,20 @@ class CoreApplicationTests {
     }
 
     @Test
-    void json(){
+    void k8sImageBuild() {
+        context.getConfigs().put("repoUrl","http://gitlab.192.168.99.105.nip.io/root/imagebuildetest.git");
+        context.getConfigs().put("branchName", "master");
+        DockerImageBuildHandler dockerImageBuildHandler = new DockerImageBuildHandler();
+
+        try {
+            dockerImageBuildHandler.process(context);
+        } catch (PipelineException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Test
+    void jsonTrans(){
         ObjectMapper mapper = new ObjectMapper();
         Map<String,String> m = new HashMap<String,String>();
         m.put("go","go");
@@ -130,6 +140,8 @@ class CoreApplicationTests {
         this.context = Context.builder()
                 .namespace("test-group")
                 .projectName("test-project")
+                .templateName("JAVA8")
+                .pipelineId(1)
                 .applicationProperties(applicationProperties)
                 .build();
     }

+ 4 - 3
web/src/main/java/seecoder/devcloud/web/infrastructure/security/TokenExpiredException.java

@@ -1,14 +1,15 @@
 package seecoder.devcloud.web.infrastructure.security;
 
-import lombok.Data;
-import org.springframework.http.HttpStatus;
+import lombok.Getter;
+import lombok.Setter;
 
 /**
  * @author PuHong Weng
  * @date 2021/3/14
  * @description:
  */
-@Data
+@Getter
+@Setter
 public class TokenExpiredException extends Exception{
 
     private int code = 10010;