在Docker容器中运行Spring Boot GraalVM原生镜像

本文介绍了如何在Docker容器中使用SDKMAN、Maven和GraalVM Native Image构建Spring Boot的原生应用。首先,通过Dockerfile安装SDKMAN、Maven和GraalVM,然后通过多阶段构建,将编译好的原生应用放入轻量级的基础镜像中。在构建过程中,解决了内存不足导致的`OutOfMemoryError`问题,并展示了如何动态配置Spring Boot应用的端口以适应Heroku等云平台。最后,提到了使用Travis CI编译Heroku就绪的Docker镜像,以解决在Heroku上部署时遇到的问题。
摘要由CSDN通过智能技术生成

在这个博客文章系列的第一篇文章中,我们已经习惯了利用SDKMAN安装Maven。正如甲骨文官方的GraalVM Docker镜像是基于 oraclelinux:7-slim ,我们需要先安装 unzipzip 。为了正常工作,SDKMAN需要两者:

FROM oracle/graalvm-ce:20.0.0-java11

For SDKMAN to work we need unzip & zip

RUN yum install -y unzip zip

RUN \

Install SDKMAN

curl -s “https://get.sdkman.io” | bash; \

source “$HOME/.sdkman/bin/sdkman-init.sh”; \

Install Maven

sdk install maven; \

Install GraalVM Native Image

gu install native-image;

RUN source “$HOME/.sdkman/bin/sdkman-init.sh” && mvn --version

RUN native-image --version

Always use source sdkman-init.sh before any command, so that we will be able to use ‘mvn’ command

ENTRYPOINT bash -c “source $HOME/.sdkman/bin/sdkman-init.sh && $0”

我们不应该忘记为Docker映像的用户启用 mvn 命令。因此,我们创建了一个稍微有趣的入口点,它总是在命令前面加上 source$HOME/.sdkman/bin/sdkman-init.sh 。定义了Dockerfile之后,我们应该用以下内容构建我们的镜像:

docker build . --tag=graalvm-ce:20.0.0-java11-mvn-native-image

构建完成后,我们可以在Docker容器中启动GraalVM本机映像编译。但是请稍候,下面的命令继承了第二个Docker卷定义 --volume“$HOME”/.m2:/root/.m2 。为什么?因为我真的想避免每次启动Docker容器时一遍又一遍地下载所有SpringMaven依赖项。通过这种装载,我们只需使用机器上缓存的Maven存储库:

docker run -it --rm \

–volume $(pwd):/build \

–workdir /build \

–volume “$HOME”/.m2:/root/.m2 \

graalvm-ce:20.0.0-java11-mvn-native-image ./compile.sh

第一个列 --volume$(pwd):/build 只是将Spring Boot应用程序的源代码(包括用于GraalVM本机映像编译的 .compile.sh 脚本)装载到Docker容器中。运行这个Docker构建,经过几分钟的繁重编译后,生成的 spring-boot-graal 本机应用程序应该已经准备好了。

防止java.lang.OutOfMemoryError错误


当我开始尝试Spring Boot应用程序的GraalVM本机映像编译时,我经常体验到 docker run 命令似乎需要很长时间才能完成。最后,一个 java.lang.OutOfMemoryError 错误被抛出到日志中,如下所示:

14:06:34.609 [ForkJoinPool-2-worker-3] DEBUG io.netty.handler.codec.compression.ZlibCodecFactory - -Dio.netty.noJdkZlibEncoder: false

Exception in thread “native-image pid watcher”

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread “native-image pid watcher”

在这种情况下,Docker引擎很可能无法使用足够的内存。在Mac的Docker安装中,默认值只有2.00GB。正如stackoverflow q&a的评论所述,您必须给Docker更多的内存,因为GraalVM本机映像编译过程实际上是RAM密集型的。分配Docker引擎大约9到12GB的RAM,我可以在Docker容器中进行编译:

img

如果一切正常,您应该在 /target/native-image 目录中找到本机编译的Spring Boot应用程序 spring-boot-graal 。因此,要运行我们的应用程序,只需使用 ./target/native-image/spring-boot-graal :

$ ./spring-boot-graal

zsh: exec format error: ./spring-boot-graal

噢!原来这不管用!为什么?我们真的需要记住,我们是从Java应用程序编译本机可执行文件! 所以他们现在完全依赖平台了! 我们的Docker容器的基本映像将与我们的主机操作系统大不相同。我想这对所有的Java人来说都是新鲜事!从一开始我们就被告知Java是独立于平台的,这要归功于它的虚拟机。这个问题只有在这一点上我们才真正明白,我们开始在Docker容器中编译我们的应用程序。

这个问题的解决方案很简单

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值