问题描述
我想使用带有 Gradle 的 jib 将我的 Spring Boot 应用程序打包为 Docker 容器。
More 除了关注 Jib's readme 之外,我还从一个简单的 JHipster 项目中复制了一个示例。你猜怎么着?它没有用。
好的,这是代码。
JHipster 生成器创建一个专用的 gradle/docker.gradle
文件,该文件从主 Gradle 构建文件应用,并导入 jib 插件
我的gradle/jib.gradle
jib {
from {
// image = "adoptopenjdk:8-jre"
image = "adoptopenjdk:11-jre-hotspot"
}
to {
image = "myapp:latest"
}
container {
entrypoint = ["bash","-c","/entrypoint.sh"]
ports = ["8080"]
environment = [
SPRING_OUTPUT_ANSI_ENABLED: "ALWAYS",SPRBOOT_SLEEP: "0"
]
creationTime = "USE_CURRENT_TIMESTAMP"
}
exTradirectories {
paths = file("src/main/jib")
permissions = ["/entrypoint.sh": "755"]
}
}
评论部分是因为我想使用 JDK8,但我正在尝试 JHipster 所做的。
其次,我根据 JH 的存储库复制了自己的 entrypoint.sh
。这是src/main/jib/entrypoint.sh
#!/bin/sh
echo "The application will start in ${SPRBOOT_SLEEP}s..." && sleep "${SPRBOOT_SLEEP}" # Author's note: it's pointless
exec java "${JAVA_OPTS}" -noverify \
-XX:+AlwaysPretouch \
-Djava.security.egd=file:/dev/./urandom \
-cp /app/resources/:/app/classes/:/app/libs/* \
"com.acme.MyApplication" "$@"
当然,我必须将 jib
插件 3.0.0
添加到我的 Gradle 文件中,应用 jib.gradle
脚本
plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'war'
id "com.google.cloud.tools.jib" version '3.0.0'
id 'org.unbroken-dome.test-sets' version '3.0.1'
id 'org.flywaydb.flyway' version '7.5.4' apply false
id 'com.telenia.gradle.MybatisGenerator' version '2.1.5'
id 'net.ltgt.apt-eclipse' version '0.21' apply false
}
apply from: 'gradle/jib.gradle'
讲解时间
现在我希望 gradle jibDockerBuild
在 /app
下创建一个包含我的应用程序文件的容器,并使用入口点启动 Spring Boot 可执行文件。我不关心睡眠,它是 0,由 JH 继承
当然,当我从 JHipster 项目构建 Docker 镜像时,它的作用就像一个魅力。当我构建自己的容器时,运行它失败并出现经典的 Unable to locate main class
错误
The application will start in 0s...
Error: Could not find or load main class
Caused by: java.lang.classNotFoundException:
我尝试 bash
进入容器,但根本没有 /app
目录。 JHipster 构建的容器下有一个 /app
目录。
在写这篇文章时尝试检查两张图片,我发现了一些不同之处。 JHipster 在 /app
下部署文件,而我的 Gradle 脚本在 /var/lib/jetty/webapps/ROOT
下部署 jar。我的应用程序始终启用 war
插件,而 JHipster 仅在设置了 -Pwar
变量时启用插件。
我不在乎在图像中使用战争或嵌入式服务器,只要结果是生产级的。我仍然需要能够构建一个战争文件。
问题
如何正确配置现有的基于 Gradle 的 Spring Boot 项目以使用 jib 构建为 Docker 容器?鉴于我优先考虑基于 Spring Boot 的 JHipster 现有代码,我的代码有什么问题?
编辑 1
酷:在 JHipster 项目中,gradle -Pwar jibDockerBuild
在容器内的 /jetty/webapps
下部署文件,当我启动应用程序时,我收到了神奇的错误 Could not find or load main class
>
解决方法
我的错误是没有完整阅读 Jib 文档。
Jib 决定如何处理战争项目
Jib 还容器化 WAR 项目。如果 Gradle 项目使用 WAR Plugin,Jib 默认会使用 jetty 作为基础镜像来部署项目 WAR。除了使用 WAR 插件让 Jib 构建 WAR 镜像外,无需额外配置。
这可能就是 JHipster 需要一个 -Pwar
启动属性来公开战争任务的原因,以便您可以构建 Spring Boot jar 的容器化版本,或者生成结果的 web-server-ed 容器战争文件。
为我没有阅读文档而感到羞耻
,对于那些可能只想开始在 Spring Boot 中使用 Jib 但由于任何原因遇到问题的人:
大多数时候,Jib 应该使用 Spring Boot 开箱即用。这是用于演示的最小设置:
- 例如,使用 Spring Initializr 创建一个 Spring Boot 应用程序。无论是 Maven 还是 Gradle 项目都没有关系:
$ curl https://start.spring.io/starter.tgz \ -d type=gradle-project \ -d dependencies=web \ -d baseDir=demo | tar -xzvf -
- 打开
build.gradle
并应用 Jib 插件。plugins { id 'org.springframework.boot' version '2.4.5' id 'io.spring.dependency-management' version '1.0.11.RELEASE' + id 'com.google.cloud.tools.jib' version '3.0.0' id 'java' }
- 使用 Jib 进行容器化。
$ ./gradlew jibDockerBuild
- 运行图像。 (该应用程序可在
localhost:8080
访问。)$ docker run --rm -p8080:8080 demo:0.0.1-SNAPSHOT
这是一个最小的设置,但您肯定希望进一步自定义 Jib 配置。
最后,尽可能选择 <packaging>jar
而非 war
。