Docker:在Dockerfile中,临时复制文件,但不能复制最终图像

时间:2014-10-10 18:46:31

标签: docker

我有一个我想要打包的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.jarservice.yml个文件。

我可能遗漏了一些内容,但我如何在./gradlew构建步骤中使所有内容都可用,但只有结果图片包含service.jarservice.yml

6 个答案:

答案 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/

我认为无法达到你想要的效果。有两种选择:

  1. 在映像中包含所有构建依赖项,并在容器内构建JAR文件。这会使你的形象膨胀。

  2. 我建议单独构建您的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服务器提取数据。

  1. 启动Web服务器,以提供您临时需要的文件。您可以使用

    Project Properties -> Run -> Console Type -> Standard output

    要提供当前目录,请参见https://docs.python.org/3/library/http.server.html#http-server-cli

  2. 在您的python3 -m http.server 8000 --bind 127.0.0.1 & 中获取文件,执行操作,在单个Dockerfile中删除文件

    RUN
  3. 使用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,否则你应该添加该步骤。