簡體   English   中英

Docker:在 Dockerfile 中,臨時復制文件,但不復制最終圖像

[英]Docker: In Dockerfile, copy files temporarily, but not for final image

我有一個想要打包的 Java 服務,最終的 docker 鏡像唯一需要的是 JAR 文件和一個配置文件。 但是,我需要先運行我的gradle命令來構建 JAR,但我不希望gradle使用的所有東西都在結果gradle映像中。

這是我當前的 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

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= -parameter 將文件從第一個構建復制到第二個構建。 第二個構建是稍后產生可用圖像的構建。

如果要測試構建結果而不是生成的圖像,可以使用docker build --target build myimage:build . . 生成的圖像僅包含Dockerfile的第一個FROM

更多信息: https : //docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds

構建圖像的工作如下。

... docker build 命令將使用任何包含 Dockerfile 的目錄作為構建上下文(包括其所有子目錄)。 構建上下文將在構建映像之前發送到 Docker 守護程序,這意味着如果您使用 / 作為源存儲庫,則硬盤驅動器的全部內容將被發送到守護程序...

請參閱https://docs.docker.com/reference/builder/

我看不出有什么辦法可以實現你想要的。 有兩種選擇:

  1. 在鏡像中包含所有構建依賴項,並在容器內構建 JAR 文件。 那會膨脹你的形象。

  2. 我建議單獨構建您的 JAR,並在構建時ADD可執行文件和配置文件。 這意味着所有構建依賴項都必須在您的開發環境中可用,但您的映像要盡可能小。

另一種解決方法是使用 Web 服務器來拉入數據。

  1. 啟動一個 Web 服務器,為您臨時需要的文件提供服務。 您可以使用

    python3 -m http.server 8000 --bind 127.0.0.1 &

    要提供當前目錄,請參閱https://docs.python.org/3/library/http.server.html#http-server-cli

  2. 在您的Dockerfile獲取文件,執行操作,在單個RUN刪除文件

    RUN wget http://localhost:8000/big.tar && tar xf big.tar && ... && rm big.tar
  3. 使用--network host構建映像以能夠訪問localhost

有一個實驗性的構建標志--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

我采納了各種意見,並使用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

你可以這樣做:

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映像(請參閱 repo )。

RUN行應該創建您的service.jar ,然后在創建層之前刪除您COPY所有源代碼,因此源代碼不會成為最終圖像的一部分。 我假設gradlew也會將它復制/安裝到 /service/build/libs,否則您應該添加該步驟。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM