如何减少我的java/gradle docker图像大小?

diu*_*lde 10 java gradle docker gradlew dockerfile

我有一个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" ]
Run Code Online (Sandbox Code Playgroud)

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

Arn*_*ter 7

我对你的图像大小感到很困惑.我有典型的Spring Boot应用程序提供REST服务,包括一个不到200MB的嵌入式servlet容器!看起来您的项目依赖项可以并且应该进行优化.

Docker Image

openjdk:8(243MB压缩)可以通过一个被替换像一个缩小高山UNIX图像openjdk:8-jdk-alpine(52MB)作为基础的图像,但如果你不需要编译能力(如不使用的JSP),你还可以去openjdk:8-jre-alpine(42MB),这仅包含运行时,请查看Docker Hub.我使用它来实现基于Spring Boot的REST服务.

Java依赖项

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

  • 检查您的依赖项,是当前正在使用的编译/运行时依赖项,还是可以删除或移动测试,请参阅Gradle Java插件
  • 一些依赖项有很多传递依赖项(显示使用gradle dependencies),检查不必要的依赖项并在未使用时排除它们,请参阅Gradle依赖项管理.确保在最终应用之前进行集成测试,一些传递依赖性没有很好地记录,但可能是必不可少的!


Gui*_*ido 6

使用 Docker 17.05+,您可以使用多阶段构建

“通过多阶段构建,您可以在 Dockerfile 中使用多个 FROM 语句。每个 FROM 指令可以使用不同的基础,并且每个指令都开始构建的新阶段。您可以有选择地将工件从一个阶段复制到另一个阶段,留下在最终图像中你不想要的一切。”

因此,您的 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=build /usr/share/app-name/app-name.jar .

EXPOSE 8080

RUN chmod +x ./docker-entry.sh

ENTRYPOINT [ "./docker-entry.sh" ]
Run Code Online (Sandbox Code Playgroud)

这样您只保留 jar,所有不必要的文件都不会包含在最终图像中。


Yuv*_*uva 5

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

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

RUN ./gradlew build \
    mv ./build/libs/app-name*.jar /usr/share/app-name/app-name.jar \
    rm -rf /usr/share/app-name-tmp/*
Run Code Online (Sandbox Code Playgroud)

所以,你的最终 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" ]
Run Code Online (Sandbox Code Playgroud)

构建的图像仍然会增加目录 /usr/share/app-name-tmp 的大小。