在map循环内运行gradle任务时,任务仅在脚本

时间:2020-10-07 07:27:13

标签: gradle build

我正在使用docker插件构建我的docker映像, 我有一个包含multiple services的项目,但它是一个monolete,所以我只有一个build.gradle文件。 我要尝试的是使用地图循环构建所有图像, 但是在构建项目时,只会构建地图中的最后一个元素。

这些是 build.gradle 文件的相关部分:

plugins {
    id 'java'
    id 'application'
    id 'maven'
    id 'distribution'
    id 'maven-publish'
    //docker-plugin
    id 'com.palantir.docker' version '0.25.0'
}

group = 'com.company.scheduler'
version '4.0.0-SNAPSHOT'


//Handle release version scenario 
def PublishedVersion
def buildNumber
if (version ==~ /(?s).*SNAPSHOT.*/) {  //Check if SNAPSHOT/Release version
    if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
    PublishedVersion = version
} else {
    if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
    PublishedVersion = version + '-' + buildNumber
}

mainClassName = 'com.company.scheduler'

dependencies {
    compile group: 'com.coralogix.sdk', name: 'coralogix-sdk', version: '2.0.3'
}

def serviceOptionMap =   [ "utility-meters": "utility_meters_import_plugins",
                           "weather":        "weather_importer"
]

serviceOptionMap.each { k, v ->
    docker {
            def service_id="${k}"
            def artifact_start_script="${v}"
            println 'artifact_start_script: ' + artifact_start_script
            println 'service_id: ' + service_id
            name "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/${service_id}:$PublishedVersion"
            //if (version ==~ /(?s).*SNAPSHOT.*/) {tag "$version", "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/ev/${project.name}:latest"}
            copySpec.from("build/distributions").into(".")
            dockerfile file("${rootProject.projectDir}/Dockerfile")
            buildArgs([ARTIFACT_ID: "${service_id}", PANPWR_VERSION: "$PublishedVersion", ARTIFACT_START_SCRIPT: "$artifact_start_script"])
            labels(["service-name": "${service_id}", "service-version": "$PublishedVersion"])
            pull false //TODO: change to true
            noCache false
            println 'built docker image: ' + service_id
        }
}

这是构建输出:

> Configure project :scheduled-tasks
artifact_start_script: utility_meters_import_plugins
service_id: utility-meters
built docker image: utility-meters
artifact_start_script: weather_importer
service_id: weather
built docker image: weather

> Task :scheduled-tasks:dockerClean
> Task :scheduled-tasks:dockerPrepare
> Task :scheduled-tasks:docker

BUILD SUCCESSFUL in 5s
3 actionable tasks: 3 executed
10:16:39 AM: Task execution finished 'docker'.

当我查看本地图像时,我只能看到第二张图像:

$ docker images | grep gradle
47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/weather           4.0.0-SNAPSHOT      729a926206ed        20 hours ago        1.11GB

2 个答案:

答案 0 :(得分:1)

这是对Gradle运作方式的常见误解。虽然以强制性方式(例如常见的Groovy脚本)评估了实际的构建脚本,但是任务概念还是声明性的:

Gradle区分配置阶段执行阶段。在配置阶段期间,将评估构建脚本并配置任务。在执行阶段,将执行所有必需的任务。必需的任务是使用命令行及其(传递)依赖项指定的任务。

当构建脚本作者使用println来了解任务的执行方式,但是所有println语句都是在配置阶段进行评估时,这种误解通常会变得很明显。


让我们看看您的具体问题。您有一个循环,在该循环内,您有类似docker { ... }的内容。标题中显示“正在Map循环中运行gradle任务”,因此您认为docker { ... }运行任务,但这是不正确的。没错,docker在您的示例中是一个任务,但是您的代码不会运行(或执行)该任务,而您的代码只是配置了该任务。评估构建脚本后,Gradle将根据所有任务及其配置的任务依赖项(dependsOn语句)设置任务图。使用此任务图,Gradle将确定所需的任务并执行它们。

现在,知道任务docker并未执行而是仅已配置,因此您的代码问题非常明显:任务的第二个配置将覆盖第一个配置。顺便说一下,这与循环无关,您可以随后应用这两种配置并获得相同的结果:

docker {
    name "first"
    dockerfile file("first/Dockerfile")
}

docker {
    name "second"
    dockerfile file("second/Dockerfile")
}

您的方法的实际问题却完全不同:在Gradle中,每个任务在构建中将仅被执行一次一次。这意味着,您将无法运行任务docker两次以创建两个Docker映像。您要么需要配置任务,以便它在一次执行中创建两个docker映像,要么以某种方式生成相同类型的两个不同任务。我不熟悉您使用的插件,因此不知道它是否可以使用这两种方法之一。

您可以看看本杰明·穆奇科(Benjamin Muschko)的Gradle Docker Plugin,您可以根据需要创建任意数量的DockerBuildImage类型的任务。

答案 1 :(得分:0)

事实证明,此插件doesn't support building multiple images, 因此,我最终为每个服务创建了一个子模块,该子模块仅使用此插件创建docker映像。 因此,这几乎是结构:

├── Dockerfile
├── app1
│   └── build.gradle
├── app2
│   └── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle-user-home
├── gradlew
├── build.gradle

这是子模块的简单 gradle.build

plugins {
    //docker-plugin
    id 'com.palantir.docker' version '0.25.0'
}

version '4.0.0-SNAPSHOT'


//Handle release version scenario 
def PublishedVersion
def buildNumber
if (version ==~ /(?s).*SNAPSHOT.*/) {  //Check if SNAPSHOT/Release version
    if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
    PublishedVersion = version
} else {
    if ("$System.env.BUILD_NUMBER" == null) {buildNumber = '0'} else {buildNumber = "$System.env.BUILD_NUMBER"}
    PublishedVersion = version + '-' + buildNumber
}

docker {
    name "47957039666.dkr.ecr.us-east-1.amazonaws.com/panpwr/service-gradle/${project.name}:$PublishedVersion"
    copySpec.from("${rootProject.projectDir}/scheduled-tasks/build/distributions").into(".")
    dockerfile file("${rootProject.projectDir}/Dockerfile")
    buildArgs([ARTIFACT_ID: "${project.name}", PANPWR_VERSION: "$PublishedVersion", ARTIFACT_START_SCRIPT: "${project.name}"])
    labels(["service-name": "${project.name}", "service-version": "$PublishedVersion"])
    pull true
    noCache false
    println 'built docker image: ' + project.name
}


publishing {
    publications {
        dockerPublication(MavenPublication) {
            from components.docker
            artifactId project.name + "-docker"
        }
    }
}

在根项目上运行docker任务会创建所有docker映像:

./gradlew clean build docker -g gradle-user-home