You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发公司级Gradle插件,统一Spring微服务构建与K8s部署流程

解决方案

一、开发自定义Gradle插件统一构建逻辑

1. 插件项目初始化

新建独立的Gradle插件项目(采用Kotlin DSL),把原手动复制的4-5个工具文件中的Docker构建、Nexus发布、K8s部署逻辑全部迁移到该项目中。示例结构:

company-gradle-plugin/
├── build.gradle.kts
├── settings.gradle.kts
└── src/
    ├── main/
    │   ├── kotlin/
    │   │   └── com/company/gradle/plugin/CompanyBuildPlugin.kt
    │   └── resources/
    │       └── META-INF/gradle-plugins/
    │           └── com.company.build.properties
    └── test/

2. 依赖开源插件

在插件的build.gradle.kts中引入所需开源插件,统一管控版本:

plugins {
    `java-gradle-plugin`
    `kotlin-dsl`
    id("com.bmuschko.docker-spring-boot-application") version "9.3.0"
    id("io.fabric8.kubernetes-gradle-plugin") version "6.8.0"
}

gradlePlugin {
    plugins {
        create("companyBuildPlugin") {
            id = "com.company.build"
            implementationClass = "com.company.gradle.plugin.CompanyBuildPlugin"
        }
    }
}

3. 封装自定义扩展

定义扩展类,让微服务仅需配置少量差异化参数(如镜像仓库地址、K8s命名空间):

open class CompanyBuildExtension(
    val project: Project
) {
    var dockerRegistry: String = "registry.company.com"
    var k8sNamespace: String = "default"
    var imageTag: String = "${project.version}-${project.extra["gitCommitId"] ?: "unknown"}"
}

在插件中注册扩展:

class CompanyBuildPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val extension = project.extensions.create<CompanyBuildExtension>("companyBuild", project)
        
        // 后续逻辑基于extension配置展开
    }
}

4. 发布插件到内部Nexus

配置插件项目发布到公司Nexus仓库,所有微服务只需在build.gradle.kts中添加插件依赖即可:

// 微服务项目的build.gradle.kts
plugins {
    id("com.company.build") version "1.0.0"
    id("org.springframework.boot") version "3.2.0"
}

二、实现单任务完成构建-扫描-部署流程

在自定义插件中创建复合任务fullDeploy,串联所有必要步骤并强制执行顺序:

class CompanyBuildPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val extension = project.extensions.create<CompanyBuildExtension>("companyBuild", project)
        
        // 1. 镜像扫描任务(集成Trivy)
        val scanImage = project.tasks.register<Exec>("scanImage") {
            commandLine(
                "trivy", "image",
                "${extension.dockerRegistry}/${project.name}:${extension.imageTag}",
                "--severity", "CRITICAL,HIGH",
                "--exit-code", "1" // 发现高危漏洞时终止流程
            )
            mustRunAfter("dockerBuildImage")
        }
        
        // 2. 配置Docker插件
        project.plugins.apply("com.bmuschko.docker-spring-boot-application")
        project.extensions.configure<DockerSpringBootApplicationExtension> {
            images {
                create {
                    name = "${extension.dockerRegistry}/${project.name}:${extension.imageTag}"
                    setBuildArgs(mapOf("JAR_FILE" to "build/libs/${project.name}-${project.version}.jar"))
                }
            }
            registryCredentials {
                url = extension.dockerRegistry
                username = project.findProperty("dockerUsername")?.toString()
                password = project.findProperty("dockerPassword")?.toString()
            }
        }
        
        // 3. 配置K8s部署插件
        project.plugins.apply("io.fabric8.kubernetes-gradle-plugin")
        project.extensions.configure<KubernetesExtension> {
            namespace = extension.k8sNamespace
            deploy {
                replicas = 2
                imagePullSecrets.add("registry-secret")
            }
        }
        
        // 4. 复合任务串联所有流程
        val fullDeploy = project.tasks.register("fullDeploy") {
            dependsOn(
                project.tasks.named("build"),
                project.tasks.named("dockerBuildImage"),
                scanImage,
                project.tasks.named("dockerPushImage"),
                project.tasks.named("kubernetesDeploy")
            )
            // 强制任务执行顺序
            project.tasks.named("dockerBuildImage").get().mustRunAfter("build")
            project.tasks.named("dockerPushImage").get().mustRunAfter(scanImage)
            project.tasks.named("kubernetesDeploy").get().mustRunAfter("dockerPushImage")
        }
    }
}

微服务项目只需执行:

./gradlew fullDeploy -PdockerUsername=xxx -PdockerPassword=xxx

三、K8s部署结构复用方案

1. 内嵌通用K8s资源模板

将99%一致的Deployment、Service、Ingress等资源模板放到插件的src/main/resources/k8s目录,用占位符替换差异化内容:

# src/main/resources/k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{serviceName}}
  namespace: {{namespace}}
spec:
  replicas: {{replicas}}
  selector:
    matchLabels:
      app: {{serviceName}}
  template:
    metadata:
      labels:
        app: {{serviceName}}
    spec:
      containers:
      - name: {{serviceName}}
        image: {{image}}
        ports:
        - containerPort: {{port}}
        env:
        - name: SPRING_PROFILES_ACTIVE
          value: {{env}}

2. 模板参数替换

在插件中配置K8s插件加载模板,并通过扩展参数替换占位符:

project.extensions.configure<KubernetesExtension> {
    namespace = extension.k8sNamespace
    resources {
        from(project.resources.text.fromFile("k8s/deployment.yaml")
            .replace("{{serviceName}}", project.name)
            .replace("{{namespace}}", extension.k8sNamespace)
            .replace("{{image}}", "${extension.dockerRegistry}/${project.name}:${extension.imageTag}")
            .replace("{{port}}", project.extra["servicePort"].toString())
            .replace("{{env}}", project.findProperty("env") ?: "dev")
        )
    }
}

3. 差异化配置支持

允许个别微服务通过扩展覆盖或追加配置,比如添加自定义环境变量:

// 某微服务的build.gradle.kts
companyBuild {
    k8sNamespace = "special-service"
    project.extra["servicePort"] = 8081
}

kubernetes {
    env {
        add("CUSTOM_FEATURE_FLAG", "true")
    }
}

4. 统一管理全局K8s资源

将命名空间、资源配额、服务账户等全局资源单独维护在插件或公司级配置仓库中,通过插件自动应用,避免每个项目重复定义。


内容的提问来源于stack exchange,提问作者George Cimpoies

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 06:23:22