すきま風

勉強したことのメモとか

JibでSpring BootのFat Jarを利用する

Jib Version 2.0.0からFat Jarが正式にサポートされました!

Release jib-gradle-plugin v2.0.0 · GoogleContainerTools/jib · GitHub

※ 1.8.0 時点ではFat Jarでの起動をデフォルトでサポートしていなかったので、ExtraDirectoryにJarをCopyしてEntryPointを書き換える辛みがありました。

How to package Spring Boot Executable Jar to Docker image? · Issue #954 · GoogleContainerTools/jib · GitHub


前回の記事のような、Multi-Project構成でresourcesファイルが複数のsubProjectにまたがっている場合、Fat Jarを利用するのがベストプラクティスだと思います。

buld.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.2.4.RELEASE" apply false
    id("io.spring.dependency-management") version "1.0.9.RELEASE"
    id("java")
    kotlin("jvm") version "1.3.61"
    kotlin("plugin.spring") version "1.3.61"
    id("com.google.cloud.tools.jib") version "2.0.0" apply false
}

// 以下略

docker-app-web/build.gradle.kts

import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
    id("org.springframework.boot")
    id("io.spring.dependency-management")
    id("com.google.cloud.tools.jib")
}

dependencies {
    implementation(project(":docker-app-env"))
    implementation("org.springframework.boot:spring-boot-starter-webflux")
}

jib {
    from {
        // test用にdebugを利用
        image = "gcr.io/distroless/java:11-debug"
    }

    // Fat Jarを利用する
    containerizingMode = "packaged"

    container {
        mainClass = "com.example.dockerapp.DockerAppApplicationKt"
        creationTime = "USE_CURRENT_TIMESTAMP"
    }
}

tasks.getByName<BootJar>("bootJar") {
    mainClassName = "com.example.dockerapp.DockerAppApplicationKt"
}

exec jib

$ ./gradlew jibDockerBuild
$ docker run -it --entrypoint /busybox/sh --rm docker-app-web:0.0.1-SNAPSHOT
# ls -l /app/classpath/
total 8
-rw-r--r--    1 root     root          6338 Jan  1  1970 docker-app-web-0.0.1-SNAPSHOT-original.jar  // original.jarがある 😊
# exit

$ docker container run -p 8080:8080 --rm docker-app-web:0.0.1-SNAPSHOT

build時のentrypointは

[java, -cp, /app/classpath/*:/app/libs/*, com.example.dockerapp.DockerAppApplicationKt]

となっています。

org.springframework.boot.loader.JarLauncher でexecutable jarを起動しているわけではなく、executable jarを解凍して依存ファイルをapp/libsにcopyして、main-classを指定して実行する形式のようです。Localで実行するとこんなイメージ。

$ java -cp BOOT-INF/lib/\*:docker-app-web-0.0.1-SNAPSHOT-original.jar com.example.dockerapp.DockerAppApplicationKt