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

问题描述:

我有一个码头工人文件类似如下:如何减少我的java/gradle 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指令都会在现有文件系统之上创建一个新层。所以在RUN指令之后的新层删除你app-name-tmp目录只是掩盖了包含下载库的前一层。因此,您的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" ] 

内置仍将从目录/ usr /共享/应用程序名称-TMP加起来大小的图像。

+0

基础图像可能有点贡献,但这是真正的答案。不幸的是,[Docker没有解决“嵌套构建”](https://github.com/docker/docker/issues/7115)。我一般处理这个问题的方式是使用单独的“构建”和“运行时”映像来处理Docker限制。请参阅[本文](https://www.fpcomplete.com/blog/2015/12/docker-split-images)了解可能的解决方法。 – mkobit

+0

@mkobit你现在可以使用多阶段构建来解决这个问题https://docs.docker.com/engine/userguide/eng-image/multistage-build/ –

+1

@GuidoGarcía好点!可能是一个新的答案或改进这个问题的好机会。 – mkobit

看来你的形象来自

FROM openjdk:8

所以从

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

,事实上一个Debian

FROM buildpack-deps:jessie-scm

英语新HOULD尝试使用高山基地

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

我猜你的形象将至少有一半的大小

+0

我知道Alpine,但我想继续使用'openjdk:8'图像。它大约是650MB,但我的应用程序在./gradlew构建步骤中增加了大约500MB以上的内容。 – diugalde

我真搞不清楚你的图像大小。我有典型的Spring Boot应用程序提供REST服务,包括一个嵌入式servlet容器,少于200MB!看起来您的项目依赖关系可以并应该进行优化。

泊坞图片

openjdk:8的(243MB压缩)可以由一个替换像openjdk:8-jdk-alpine(52MB)减小的高山UNIX图像作为基础图像,而且如果不需要的编译器能力(例如唐不使用JSP),你也可以去openjdk:8-jre-alpine(42MB),其中只包含运行时间,查看Docker Hub。我使用基于Spring Boot的REST服务,效果很好。

了Java相关

需要编译和运行Java的依赖关系必须被包括在内,但你可能有未使用的依赖包括:

  • 检查你的依赖,是当前编译/运行时依赖真的使用或可能被删除或移动到测试,请参阅Gradle Java Plugin
  • 某些依赖项有很多传递依赖性(使用gradle dependencies显示),请检查unne如果未使用,请将其排除,请参阅Gradle Dependency Management。一定要在最终应用之前进行集成测试,一些传递依赖性没有很好的记录,但可能是必要的!
+1

如果我执行./gradlew构建,生成的jar只有95MB,但图像大小大约为1GB – diugalde

+0

为什么你从docker运行gradle和添加的目录是什么?我使用gradle docker插件,只从池中添加jar到图像调用docker,而不是其他方式 –

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

使用Docker 17.05+,您可以使用multi-stage builds

“随着多级版本,您使用多个从您Dockerfile语句组成,每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" ] 

这样,你只保留罐子和所有不必要的文件不包含在最终的影像中。

+1

第一阶段被命名为'build'(而不是'builder'),它不应该是'COPY --from = build'吗? –