如何减少我的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加起来大小的图像。
看来你的形象来自
FROM openjdk:8
所以从
,事实上一个Debian
FROM buildpack-deps:jessie-scm
英语新HOULD尝试使用高山基地
我猜你的形象将至少有一半的大小
我知道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。一定要在最终应用之前进行集成测试,一些传递依赖性没有很好的记录,但可能是必要的!
如果我执行./gradlew构建,生成的jar只有95MB,但图像大小大约为1GB – diugalde
为什么你从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" ]
这样,你只保留罐子和所有不必要的文件不包含在最终的影像中。
第一阶段被命名为'build'(而不是'builder'),它不应该是'COPY --from = build'吗? –
基础图像可能有点贡献,但这是真正的答案。不幸的是,[Docker没有解决“嵌套构建”](https://github.com/docker/docker/issues/7115)。我一般处理这个问题的方式是使用单独的“构建”和“运行时”映像来处理Docker限制。请参阅[本文](https://www.fpcomplete.com/blog/2015/12/docker-split-images)了解可能的解决方法。 – mkobit
@mkobit你现在可以使用多阶段构建来解决这个问题https://docs.docker.com/engine/userguide/eng-image/multistage-build/ –
@GuidoGarcía好点!可能是一个新的答案或改进这个问题的好机会。 – mkobit