我有一个我想要打包的Java服务,最终的docker镜像需要的唯一东西是JAR文件和配置文件。但是,我需要先运行gradle
命令来构建JAR,但我不希望gradle
使用的所有内容都在结果docker镜像中。
这是我当前的DockerFile:
RUN apt-get update && apt-get install -y openjdk-7-jdk
COPY . /
RUN ./gradlew shadowJar
CMD ["java", "-jar", "service/build/libs/service.jar", "server", "service/service.yml"]
你可以看到我必须首先COPY
所有内容,以便我可以运行./gradlew
(否则它说无法找到命令)。但最后,我需要的只是service.jar
和service.yml
个文件。
我可能遗漏了一些内容,但我如何在./gradlew
构建步骤中使所有内容都可用,但只有结果图片包含service.jar
和service.yml
。
答案 0 :(得分:6)
Docker推出了所谓的“多阶段构建”。使用它们,您可以避免在图像中包含不必要的文件。您的Dockerfile
将如下所示:
FROM ubuntu AS build
COPY . /src
# run your build
FROM ubuntu
RUN mkdir -p /dist/
COPY --from=build /src/my.object /dist/
原则很简单。在第一个FROM
中,您可以为您的构建命名。在第二个FROM
中,您可以使用COPY --from=
- 参数将文件从第一个版本复制到第二个版本。第二个版本是稍后产生可用图像的版本。
有关详细信息:https://docs.docker.com/engine/userguide/eng-image/multistage-build/#use-multi-stage-builds
答案 1 :(得分:4)
构建图像的工作方式如下。
... docker build命令将使用包含Dockerfile的任何目录作为构建上下文(包括其所有子目录)。在构建映像之前,构建上下文将被发送到Docker守护程序,这意味着如果您使用/作为源存储库,硬盘驱动器的全部内容将被发送到守护程序......
请参阅https://docs.docker.com/reference/builder/
我认为无法达到你想要的效果。有两种选择:
在映像中包含所有构建依赖项,并在容器内构建JAR文件。这会使你的形象膨胀。
我建议单独构建您的JAR,并在构建时只构建ADD
可执行文件和配置文件。这意味着所有构建依赖项必须在您的开发环境中可用,但您的映像尽可能小。
答案 2 :(得分:1)
有一个实验性的构建标记--squash
,用于将所有内容汇总到一个层中。
例如,docker build --squash -t <tag> .
文档https://docs.docker.com/engine/reference/commandline/image_build/#options。
Github讨论https://github.com/moby/moby/issues/332。
如何在守护程序中启用实验功能? https://github.com/docker/docker-ce/blob/master/components/cli/experimental/README.md
答案 3 :(得分:1)
另一种解决方法是使用Web服务器提取数据。
启动Web服务器,以提供您临时需要的文件。您可以使用
Project Properties -> Run -> Console Type -> Standard output
要提供当前目录,请参见https://docs.python.org/3/library/http.server.html#http-server-cli
在您的python3 -m http.server 8000 --bind 127.0.0.1 &
中获取文件,执行操作,在单个Dockerfile
中删除文件
RUN
使用RUN wget http://localhost:8000/big.tar && tar xf big.tar && ... && rm big.tar
构建图像以能够访问--network host
答案 4 :(得分:0)
我采纳了各种意见,并使用DOCKER_BUILDKIT
提出了此解决方案。我将somefile.tar.gz
临时复制到了阶段0,但最终图像中没有该文件。容器的整体尺寸减小了。
# syntax=docker/dockerfile:experimental
# File: Dockerfile
# Build:
# DOCKER_BUILDKIT=1 docker build -t sometag -f Dockerfile $(pwd)
# =============================================================================
# STAGE 0 ---------------------------------------------------------------------
# =============================================================================
FROM somebase as devel
COPY somefile.tar.gz /somemodules/
RUN cd /somemodules && \
tar -xf somefile.tar.gz
# =============================================================================
# STAGE 1 ---------------------------------------------------------------------
# =============================================================================
FROM same_or_another_base
RUN apt-get update -y && \
apt-get install -y --no-install-recommends \
rsync && \
rm -rf /var/lib/apt/lists/*
RUN --mount=from=devel,src=/somemodules,dst=/somemodules \
rsync -I -K -a /somemodules/somefile/* /usr/local/somemodules/
RUN echo "/usr/local/somemodules/lib" >> /etc/ld.so.conf.d/somemodules.conf
ENV PATH=/usr/local/somemodules/bin:$PATH
# a bunch of other stuff . . .
RUN ldconfig
答案 5 :(得分:-1)
你可以这样做:
FROM java:7
COPY . /sourcecode
WORKDIR /sourcecode
RUN ./gradlew shadowJar && rm -rf /sourcecode
WORKDIR /
CMD ["java", "-jar", "service/build/libs/service.jar", "server", "service/service.yml"]
这使用Docker官方java
图片(see repo)。
RUN
行应创建您的service.jar
,然后在创建图层之前删除您已经COPY
d的所有源代码,因此源代码不会成为其中的一部分最终的形象。我假设gradlew
也会将其复制/安装到/ service / build / libs,否则你应该添加该步骤。