网易首页 > 网易号 > 正文 申请入驻

如何创建 GraalVM Docker 镜像

0
分享至

在本文中,您将学习如何为 GraalVM 原生镜像创建 Docker 镜像。通过一些动手实验,您将了解到它在创建 Docker 镜像时比您习惯的要复杂一些。享受!
介绍
在上一篇博文中,您学习了如何为 Spring Boot 3 应用程序创建 GraalVM 本机映像。如今,应用程序通常以 Docker 镜像的形式分发,因此验证 GraalVM 本机镜像是如何做到这一点很有趣。GraalVM 本机镜像不需要 JVM,那么您可以使用更简约的 Docker 基础镜像吗?您将在本博客期间执行一些实验,并边做边学。
本博客中使用的资源可在GitHub上找到。
GraalVM 文档中提供的信息是一个很好的学习起点。阅读此博客时,这是很好的参考资料。
作为示例应用程序,您将使用上一篇文章中的 Spring Boot 应用程序。该应用程序包含一个基本的RestController,它只返回一条hello消息。它还RestController包括一些代码,以便结合反射执行测试,但这部分是为上一篇文章添加的。
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello() {
// return "Hello GraalVM!"
String helloMessage = "Default message";
try {
Class helloClass = Class.forName("com.mydeveloperplanet.mygraalvmplanet.Hello");
Method helloSetMessageMethod = helloClass.getMethod("setMessage", String.class);
Method helloGetMessageMethod = helloClass.getMethod("getMessage");
Object helloInstance = helloClass.getConstructor().newInstance();
helloSetMessageMethod.invoke(helloInstance, "Hello GraalVM!");
helloMessage = (String) helloGetMessageMethod.invoke(helloInstance);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
return helloMessage;
}
}

构建应用程序:

$ mvn clean verify

从存储库的根目录运行应用程序:

$ java -jar target/mygraalvmplanet-0.0.1-SNAPSHOT.jar

测试端点:

$ curl http://localhost:8080/hello
Hello GraalVM!


您现在已准备好对这个应用程序进行 Docker 化!
先决条件
此博客的先决条件是:
基本的 Linux 知识,这篇文章中使用的是 Ubuntu 22.04
基本的 Java 和 Spring Boot 知识
基本的 GraalVM 知识
基本的 Docker 知识
基础SDKMAN知识
为 Spring Boot 应用程序创建 Docker 镜像
在本节中,您将为 Spring Boot 应用程序创建一个 Dockerfile。这是一个非常基本的 Dockerfile,不会在生产代码中使用。请参阅以前的帖子“ Docker 最佳实践”和“ Spring Boot Docker 最佳实践”,了解生产就绪 Docker 映像的提示和技巧。您将使用的 Dockerfile 如下:

FROM eclipse-temurin:17.0.5_8-jre-alpine
COPY target/mygraalvmplanet-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]


您使用包含 Java JRE 的 Docker 基础映像,将 JAR 文件复制到映像中,最后运行 JAR 文件。
构建 Docker 镜像:

$ docker build . --tag mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT


验证镜像的大小。它的大小为 188MB。

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mydeveloperplanet/mygraalvmplanet 0.0.1-SNAPSHOT be12e1deda89 33 seconds ago 188MB


运行 Docker 镜像:

$ docker run --name mygraalvmplanet mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT
...
2023-02-26T09:20:48.033Z INFO 1 --- [ main] c.m.m.MyGraalVmPlanetApplication : Started MyGraalVmPlanetApplication in 2.389 seconds (process running for 2.981)


如您所见,应用程序在大约 2 秒内启动。
再次测试端点。首先,找到您的 Docker 容器的 IP 地址。在下面的输出中,IP 地址是 172.17.0.2,但它可能是您机器上的其他地址。

$ docker inspect mygraalvmplanet | grep IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",


使用 IP 地址调用端点并验证它是否有效。

$ curl http://172.17.0.2:8080/hello
Hello GraalVM!


为了继续,停止容器,删除它,同时删除镜像。每次实验后都这样做。这样,您可以确保每次都从干净的情况开始。

$ docker rm mygraalvmplanet
$ docker rmi mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT


为 GraalVM 原生镜像创建 Docker 镜像
让我们对 GraalVM 本机图像做同样的事情。首先,切换到使用 GraalVM。

$ sdk use java 22.3.r17-nik


创建原生镜像:

$ mvn -Pnative native:compile


创建一个类似的 Dockerfile (Dockerfile-native-image)。这次,您使用不带 JVM 的 Alpine Docker 基础映像。您不需要 JVM 来运行 GraalVM 本机映像,因为它是可执行文件而不是 JAR 文件。

FROM alpine:3.17.1
COPY target/mygraalvmplanet mygraalvmplanet
ENTRYPOINT ["/mygraalvmplanet"]


构建 Docker 镜像,这次带有一个额外的--file参数,因为文件名与默认值不同。

$ docker build . --tag mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT --file Dockerfile-native-image


验证 Docker 镜像的大小。现在只有 76.5MB 而不是之前的 177MB。

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mydeveloperplanet/mygraalvmplanet 0.0.1-SNAPSHOT 4f7c5c6a9b29 25 seconds ago 76.5MB


运行容器并注意它没有正确启动。

$ docker run --name mygraalvmplanet mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT
exec /mygraalvmplanet: no such file or directory

exec /mygraalvmplanet: 没有这样的文件或目录
这里有什么问题?为什么这不起作用?
这是一个模糊的错误,但 Alpine Linux Docker 映像使用musl作为标准 C 库,而 GraalVM 本机映像是使用使用 glibc 的 Ubuntu Linux 发行版编译的。
让我们将 Docker 基础映像更改为 Ubuntu。Dockerfile 是Dockerfile-native-image-ubuntu:

FROM ubuntu:jammy
COPY target/mygraalvmplanet mygraalvmplanet
ENTRYPOINT ["/mygraalvmplanet"]

构建 Docker 映像。

$ docker build . --tag mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT --file Dockerfile-native-image-ubuntu


验证 Docker 镜像的大小,现在是 147MB。

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mydeveloperplanet/mygraalvmplanet 0.0.1-SNAPSHOT 1fa90b1bfc54 3 hours ago 147MB


运行容器,它在不到 200 毫秒的时间内成功启动。

$ docker run --name mygraalvmplanet mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT
...
2023-02-26T12:48:26.140Z INFO 1 --- [ main] c.m.m.MyGraalVmPlanetApplication : Started MyGraalVmPlanetApplication in 0.131 seconds (process running for 0.197)


基于 Distroless 镜像创建 Docker 镜像
使用 Ubuntu 基础镜像构建的 Docker 镜像大小为 147MB。但是,Ubuntu 映像确实包含很多不需要的工具。我们可以使用尺寸非常小的distroless镜像来减小镜像的大小吗?
创建一个 DockerfileDockerfile-native-image-distroless并使用一个 distroless 基础镜像。

FROM gcr.io/distroless/base
COPY target/mygraalvmplanet mygraalvmplanet
ENTRYPOINT ["/mygraalvmplanet"]


构建 Docker 映像。

$ docker build . --tag mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT --file Dockerfile-native-image-distroless


验证 Docker 镜像的大小,现在是 89.9MB。

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mydeveloperplanet/mygraalvmplanet 0.0.1-SNAPSHOT 6fd4d44fb622 9 seconds ago 89.9MB


运行容器,发现它无法启动。distroless 镜像中似乎没有几个必要的库。

$ docker run --name mygraalvmplanet mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT
/mygraalvmplanet: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

/mygraalvmplanet:加载共享库时出错:libz.so.1:无法打开共享对象文件:没有这样的文件或目录
在谷歌搜索此错误消息时,您会发现线程提到从其他图像(例如,Ubuntu 图像)复制所需的库,但您会遇到下一个错误和下一个错误。这是一条艰难的道路,需要花费一些时间。例如,请参阅此线程。
可以在此处找到使用 distroless 图像的解决方案。
基于 Oracle Linux 创建 Docker 镜像
另一种创建 Docker 镜像的方法可以在 GraalVM GitHub 页面上找到。在 Docker 容器中构建本机镜像,并使用多阶段构建来构建目标镜像。
正在使用的 Dockerfile 是从此处复制的,可以在存储库中找到 Dockerfile-oracle-linux。
新建文件Dockerfile-native-image-oracle-linux,将Dockerfile-oracle-linux的内容复制进去,修改如下:
更新 Maven SHA 和 DOWNLOAD_URL。
更改 L36 以便像以前一样编译本机映像:mvn -Pnative native:compile
更改 L44 和 L45 以复制和使用mygraalvmplanet本机映像。
生成的 Dockerfile 如下所示:

FROM ghcr.io/graalvm/native-image:ol8-java17-22 AS builder
# Install tar and gzip to extract the Maven binaries
RUN microdnf update \
&& microdnf install --nodocs \
tar \
gzip \
&& microdnf clean all \
&& rm -rf /var/cache/yum
# Install Maven
# Source:
# 1) https://github.com/carlossg/docker-maven/blob/925e49a1d0986070208e3c06a11c41f8f2cada82/openjdk-17/Dockerfile
# 2) https://maven.apache.org/download.cgi
ARG USER_HOME_DIR="/root"
ARG SHA=1ea149f4e48bc7b34d554aef86f948eca7df4e7874e30caf449f3708e4f8487c71a5e5c072a05f17c60406176ebeeaf56b5f895090c7346f8238e2da06cf6ecd
ARG MAVEN_DOWNLOAD_URL=https://dlcdn.apache.org/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.tar.gz
RUN mkdir -p /usr/share/maven /usr/share/maven/ref \
&& curl -fsSL -o /tmp/apache-maven.tar.gz ${MAVEN_DOWNLOAD_URL} \
&& echo "${SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \
&& tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \
&& rm -f /tmp/apache-maven.tar.gz \
&& ln -s /usr/share/maven/bin/mvn /usr/bin/mvn
ENV MAVEN_HOME /usr/share/maven
ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2"
# Set the working directory to /home/app
WORKDIR /build
# Copy the source code into the image for building
COPY . /build
# Build
RUN mvn -Pnative native:compile
# The deployment Image
FROM docker.io/oraclelinux:8-slim
EXPOSE 8080
# Copy the native executable into the containers
COPY --from=builder /build/target/mygraalvmplanet .
ENTRYPOINT ["/mygraalvmplanet"]


构建 Docker 映像。放松,这需要相当长的时间。

$ docker build . --tag mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT -f Dockerfile-native-image-oracle-linux


此镜像大小为 177MB。

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mydeveloperplanet/mygraalvmplanet 0.0.1-SNAPSHOT 57e0fda006f0 9 seconds ago 177MB


运行容器,它会在 55 毫秒后启动。

$ docker run --name mygraalvmplanet mydeveloperplanet/mygraalvmplanet:0.0.1-SNAPSHOT
...
2023-02-26T13:13:50.188Z INFO 1 --- [ main] c.m.m.MyGraalVmPlanetApplication : Started MyGraalVmPlanetApplication in 0.055 seconds (process running for 0.061)


所以,这很好用。这是为 GraalVM 原生镜像创建 Docker 镜像的方法:
根据您的目标基础镜像准备一个 Docker 镜像;
安装必要的工具,在此应用程序中为 GraalVM 和 Maven;
使用多阶段 Docker 构建来创建目标图像。
结论
可以为您的 GraalVM 本机映像创建 Docker 映像,但您需要了解您在做什么。使用多阶段构建是最佳选择。根据是否需要使用distroless镜像缩小镜像大小,需要自己准备镜像来构建原生镜像。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
国务院刚刚定了两件大事,直接关系你的钱袋子!

国务院刚刚定了两件大事,直接关系你的钱袋子!

21世纪经济报道
2026-01-16 21:29:29
发现没?凡是男人带女人出去玩,女的都会穿裙子,你知道为什么吗

发现没?凡是男人带女人出去玩,女的都会穿裙子,你知道为什么吗

老好人的愤怒
2026-01-15 18:52:47
秋瓷炫:我这辈子最正确的决定,就是39岁高龄为中国籍小丈夫生子

秋瓷炫:我这辈子最正确的决定,就是39岁高龄为中国籍小丈夫生子

八斗小先生
2026-01-15 09:59:08
风暴眼丨实探西贝:贾国龙赌上一切,员工称“我们只能服从”

风暴眼丨实探西贝:贾国龙赌上一切,员工称“我们只能服从”

凤凰网财经
2026-01-16 21:11:28
不满换帅+3天丢2冠!皇马球迷拉横幅要求老佛爷下台 将在主场狂嘘

不满换帅+3天丢2冠!皇马球迷拉横幅要求老佛爷下台 将在主场狂嘘

我爱英超
2026-01-17 06:27:10
老佛爷终极计划曝光:欲请回穆帅,后者疑在本菲卡制造混乱?

老佛爷终极计划曝光:欲请回穆帅,后者疑在本菲卡制造混乱?

田先生篮球
2026-01-16 14:16:21
千亿换来百万辆,赛力斯交给华为的天价学费到底值不值?

千亿换来百万辆,赛力斯交给华为的天价学费到底值不值?

汽车十三行
2026-01-15 09:22:09
纪委通报:他接受纪律审查和监察调查

纪委通报:他接受纪律审查和监察调查

锡望
2026-01-17 11:54:35
早稻田大学取消5名中国籍研究生入学资格,涉及作弊

早稻田大学取消5名中国籍研究生入学资格,涉及作弊

东京在线
2026-01-16 22:27:28
人口告别世界第一?二孩催生无效后,国家终于向住房出手了

人口告别世界第一?二孩催生无效后,国家终于向住房出手了

泠泠说史
2025-12-23 17:42:35
36岁男演员因电视剧《轧戏》爆火!多年前的历史都被翻出来,曾被刘亦菲在剧里说“长得丑想得美”……

36岁男演员因电视剧《轧戏》爆火!多年前的历史都被翻出来,曾被刘亦菲在剧里说“长得丑想得美”……

鲁中晨报
2026-01-17 07:31:05
火箭击败森林狼,赛后4个好消息和3个坏消息,保住前六难度不小

火箭击败森林狼,赛后4个好消息和3个坏消息,保住前六难度不小

邹维体育
2026-01-17 13:41:38
马斯克“无聊公司”被曝将新建地下隧道,缓解通勤压力

马斯克“无聊公司”被曝将新建地下隧道,缓解通勤压力

IT之家
2026-01-17 11:45:43
斯诺克大师赛四强名单及对阵:特鲁姆普vs希金斯,吴宜泽vs威尔逊

斯诺克大师赛四强名单及对阵:特鲁姆普vs希金斯,吴宜泽vs威尔逊

菲儿看球
2026-01-17 15:02:17
韩国法院以妨害公务执行等罪名判处尹锡悦有期徒刑5年

韩国法院以妨害公务执行等罪名判处尹锡悦有期徒刑5年

新京报
2026-01-16 14:16:19
罗永浩声明:决定和西贝和解!但是他结尾说的一句话,让网友后怕

罗永浩声明:决定和西贝和解!但是他结尾说的一句话,让网友后怕

晴晴的娱乐日记
2025-09-15 22:22:29
俄罗斯在库页岛发现汉字石碑,我国专家赶到后,碑上内容让人尴尬

俄罗斯在库页岛发现汉字石碑,我国专家赶到后,碑上内容让人尴尬

疯狂的小历史
2026-01-16 11:35:56
环沪惨案十周年:部分购房者实在太短视了

环沪惨案十周年:部分购房者实在太短视了

环线房产咨询
2026-01-16 19:13:11
网传华为终端BG董事长余承东工作群怒批鸿蒙座舱:各种智能提醒都不具备,不该提醒的瞎提醒!非常非常愚蠢

网传华为终端BG董事长余承东工作群怒批鸿蒙座舱:各种智能提醒都不具备,不该提醒的瞎提醒!非常非常愚蠢

和讯网
2026-01-16 15:50:10
36年前陈宝国主演的盗墓恐怖片!尺度大到少儿不宜

36年前陈宝国主演的盗墓恐怖片!尺度大到少儿不宜

释凡电影
2025-08-14 09:33:19
2026-01-17 15:35:00
墨谈科技 incentive-icons
墨谈科技
业务数码玩家.无聊的博主
5685文章数 611关注度
往期回顾 全部

科技要闻

8亿周活扛不住烧钱 ChatGPT终向广告"低头"

头条要闻

郑丽文喊话:国民党2026全台要像桃园一样全面胜利

头条要闻

郑丽文喊话:国民党2026全台要像桃园一样全面胜利

体育要闻

三巨头走了俩,联盟笑柄却起飞了

娱乐要闻

徐家还是爱孩子的,在马筱梅生产前选择和解

财经要闻

保不准,人民币会闪击6.8!

汽车要闻

林肯贾鸣镝:稳中求进,将精细化运营进行到底

态度原创

数码
亲子
手机
本地
公开课

数码要闻

摩米士推出10000mAh半固态电池移动电源,支持25W无线快充

亲子要闻

养男孩的妈妈一定要保护好自己

手机要闻

年度第二周排名,OPPO稳在第三,vivo稳在第四

本地新闻

云游内蒙|黄沙与碧波撞色,乌海天生会“混搭”

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版