为了避免因为编译平台不一致导致的部署文件不一样,可以使用Docker进行编译,以保证编译环境的一致性, 参考:编译native镜像的两种方法:本地 & docker。
但是,Docker编译的时候,会有一些缺点,比如下载依赖文件、编译时间过长等问题。为了解决这些问题,可以使用一些优化方案。
方案1:原始编译部署方案
Dockerfile.native
FROM bellsoft/liberica-native-image-kit-container:jdk-22-nik-24.0.2-glibc as builder
WORKDIR /home/build
COPY . /home/build/
RUN ./mvnw -Pnative clean -DskipTests native:compile
FROM bellsoft/alpaquita-linux-base:stream-glibc-240821
WORKDIR /home/myapp
COPY --from=builder /home/build/target/flutter-flex-backend .
EXPOSE 8080
CMD ["/bin/sh", "-c", "/home/myapp/flutter-flex-backend"]
- 缺点:需要下载maven依赖,耗时较长
方案2:拆分编译部署
# bellsoft的NIK镜像
docker pull bellsoft/liberica-native-image-kit-container:jdk-22-nik-24.0.2-glibc
# 映射本地文件和maven仓库进行编译
docker run -it --rm --name temp-container \
-v $PWD:/home/build \
-v $HOME/.m2:/root/.m2 \
bellsoft/liberica-native-image-kit-container:jdk-22-nik-24.0.2-glibc \
/bin/sh -c "cd /home/build && ./mvnw -Pnative clean -DskipTests native:compile"
# 运行测试
docker run -it --rm --name temp-container \
-v $PWD/target/flutter-flex-backend:/home/myapp/flutter-flex-backend \
-p 8080:8080 \
bellsoft/alpaquita-linux-base:stream-glibc-240821 \
/bin/sh -c "cd /home/myapp && ./flutter-flex-backend"
- 优点:充分利用本地maven仓库,减少下载时间
- 缺点:比较繁琐,但是可以配置快捷指令
方案3:映射本地maven仓库
在docker run 的时候可以直接映射宿主机文件夹,但是在build期间不能映射,只能执行COPY操作,所以需要在Dockerfile中COPY maven仓库到镜像中。
- Dockerfile将maven仓库拷贝到镜像中的配置:
COPY .m2 /root/.m2 - 在$HOME目录下,执行 build 操作:因为build期间的COPY指令,只能拷贝当前目录或者子目录下的文件
Dockerfile.native
FROM bellsoft/liberica-native-image-kit-container:jdk-22-nik-24.0.2-glibc as builder
COPY .m2 /root/.m2
WORKDIR /home/build
COPY . /home/build/
RUN ./mvnw -Pnative clean -DskipTests native:compile
FROM bellsoft/liberica-runtime-container:jdk-21.0.4-crac-cds-slim-glibc
WORKDIR /home/myapp
COPY --from=builder /home/build/target/flutter-flex-backend.jar .
EXPOSE 8080
CMD ["java", "-jar", "/home/myapp/flutter-flex-backend.jar"]
- 缺点:需要切换操作目录到$HOME,否则会拷贝不到maven仓库,且拷贝的无用依赖文件较多,会增加镜像大小
方案4:构建包含缓存的编译镜像
构建镜像描述文件:
Dockerfile-build
FROM bellsoft/liberica-native-image-kit-container:jdk-22-nik-24.0.2-glibc as builder
WORKDIR /home/build
COPY . /home/build/
RUN ./mvnw -Pnative clean -DskipTests package
RUN rm -rf /home/build/
需要在项目根目录下执行,以便拷贝项目文件,编译镜像名称mytool-group-develop:jdk-22-nik-24.0.2-glibc-with-m2:
docker build --platform=linux/amd64 -f Dockerfile.build -t mytool-group-develop:jdk-22-nik-24.0.2-glibc-with-m2 .
使用范例:
Dockerfile.native
FROM mytool-group-develop:jdk-22-nik-24.0.2-glibc-with-m2 as builder
WORKDIR /home/build
COPY . /home/build/
RUN ./mvnw -Pnative clean -DskipTests native:compile
FROM bellsoft/alpaquita-linux-base:stream-glibc-240821
WORKDIR /home/myapp
COPY --from=builder /home/build/target/flutter-flex-backend .
EXPOSE 8080
CMD ["/bin/sh", "-c", "/home/myapp/flutter-flex-backend"]
- 优点:构建镜像时,可以利用缓存,减少编译时间
- 缺点:当maven仓库有变动时,需要重新构建编译镜像
总结
- ✅ 原始编译部署方案:分发项目的时候使用此方案,使用的是公共镜像,保证了编译环境的一致性
- ⚠️ 拆分编译部署:本地开发的时候可以使用此方案,充分使用本地maven缓存资源
- ❌ 映射本地maven仓库:不推荐使用,构建的时候必须进入$HOME目录,不方便使用
- ✅ 构建包含缓存的编译镜像:推荐使用,只需要在maven依赖变更的时候重新构建一次就可以使用缓存
参考资料
文档信息
- 本文作者:Bob.Zhu
- 本文链接:https://home.mytool.group/2024/08/27/01-graalvm-native-image-optimization/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
