如何减less我的java / gradle docker镜像大小?

我有一个像下面这样的Docker文件:

FROM openjdk:8 ADD . /usr/share/app-name-tmp WORKDIR /usr/share/app-name-tmp RUN ./gradlew build \ mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar WORKDIR /usr/share/app-name RUN rm -rf /usr/share/app-name-tmp EXPOSE 8080 RUN chmod +x ./docker-entry.sh ENTRYPOINT [ "./docker-entry.sh" ] 

问题是,最终的图像大小是1.1GB,我知道这是因为gradle下载和存储所有的依赖关系。 删除这些不必要的文件并保留jar的最好方法是什么?

每个RUN指令都在现有文件系统上创build一个新层。 因此,在删除了app-name-tmp目录的RUN指令之后的新层只是掩盖了包含下载库的上一层。 因此,您的docker图像仍然具有来自所有图层的大小。

删除单独的RUN rm -rf /usr/share/app-name-tmp指令,并将其包含在与gradle build相同的RUN指令中,如下所示。

 RUN ./gradlew build \ mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \ rm -rf /usr/share/app-name-tmp/* 

所以,你的最终Dockerfile将是

 FROM openjdk:8 ADD . /usr/share/app-name-tmp WORKDIR /usr/share/app-name-tmp RUN ./gradlew build \ mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \ rm -rf /usr/share/app-name-tmp/* WORKDIR /usr/share/app-name EXPOSE 8080 RUN chmod +x ./docker-entry.sh ENTRYPOINT [ "./docker-entry.sh" ] 

构build的映像仍然会从目录/ usr / share / app-name-tmp中添加大小。

我真的很困惑你的图像大小。 我有典型的Spring Boot应用程序提供了一个REST服务,包括一个小于200MB的embedded式servlet容器! 看起来你的项目依赖关系可以并且应该被优化。

Docker图像

openjdk:8 (243MB压缩)可以用一个像openjdk:8-jdk-alpine (52MB)这样的Alpine unix映像作为基础映像来替代,但是如果你不需要编译器function的话(比如不要使用JSP )你也可以去openjdk:8-jre-alpine (42MB),其中只包括运行时,看看Docker Hub 。 我使用基于Spring Boot的REST服务,效果很好。

Java依赖关系

必须包含编译和运行时所需的Java依赖关系,但可能包含未使用的依赖关系:

  • 检查你的依赖关系,是当前的编译/运行时依赖关系是真正使用的,或者可以被删除或移动testing,请参阅Gradle Java插件
  • 有些依赖有很多传递依赖(使用gradle dependencies关系显示),检查不必要的gradle dependencies ,如果未使用,请将其排除,请参阅Gradle依赖关系pipe理 。 确保在最终应用之前进行集成testing,一些传递依赖性没有很好的logging,但可能是必不可less的!

看起来你的形象来自于

FROM openjdk:8

所以从

https://github.com/docker-library/openjdk/blob/e6e9cf8b21516ba764189916d35be57486203c95/8-jdk/Dockerfile

实际上是一个Debian

FROM buildpack-deps:jessie-scm

你应该尝试使用阿尔卑斯山基地

https://github.com/docker-library/openjdk/blob/9a0822673dffd3e5ba66f18a8547aa60faed6d08/8-jdk/alpine/Dockerfile

我想你的形象将至less有一半的大小

这是你部署到生产的容器吗? 如果是这样,请勿将其用于实际构build。 在其他地方进行构build(和testing),一旦它被祝福,只需将JAR复制到Docker生产容器。

随着Docker 17.05+,你可以使用多阶段构build 。

“使用多阶段构build,您可以在Dockerfile中使用多个FROM语句,每个FROM指令可以使用不同的基础,并且每个FROM指令都开始一个新的构build阶段,您可以select性地将工件从一个阶段复制到另一个阶段,一切你不想在最后的形象。“

所以你的Dockerfile可能看起来像这样:

 # # first stage (build) # FROM openjdk:8 as build ADD . /usr/share/app-name-tmp WORKDIR /usr/share/app-name-tmp RUN ./gradlew build && \ mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar # # second stage. use alpine to reduce the image size # FROM openjdk:8-jre-alpine WORKDIR /usr/share/app-name COPY --from=builder /usr/share/app-name/app-name.jar . EXPOSE 8080 RUN chmod +x ./docker-entry.sh ENTRYPOINT [ "./docker-entry.sh" ] 

这样你只保留jar子和所有不必要的文件不包括在最终的形象。