首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么停靠-撰写构建运行我的步骤两次?

为什么停靠-撰写构建运行我的步骤两次?
EN

Stack Overflow用户
提问于 2020-10-22 02:42:41
回答 2查看 551关注 0票数 0

我使用的是多阶段建筑,其中有这样的Dockerfile:

代码语言:javascript
复制
#####################################
## Build the client
#####################################

FROM node:12.19.0 as web-client-builder
WORKDIR /workspace
COPY web-client/package*.json ./

# Running npm install before we update our source allows us to take advantage
# of docker layer caching. We are excluding node_modules in .dockerignore
RUN npm ci

COPY web-client/ ./
RUN npm run test:ci
RUN npm run build


#####################################
## Host the client on a static server
#####################################

FROM nginx:1.19 as web-client
COPY --from=web-client-builder /workspace/nginx-templates /etc/nginx/templates/
COPY --from=web-client-builder /workspace/nginx.conf /etc/nginx/nginx.conf
COPY --from=web-client-builder /workspace/build /var/www/

#####################################
## Build the server
#####################################

FROM openjdk:11-jdk-slim as server-builder
WORKDIR /workspace
COPY build.gradle settings.gradle gradlew ./
COPY gradle ./gradle
COPY server/ ./server/
RUN ./gradlew --no-daemon :server:build

#####################################
## Start the server
#####################################

FROM openjdk:11-jdk-slim as server
WORKDIR /app
ARG JAR_FILE=build/libs/*.jar
COPY --from=server-builder /workspace/server/$JAR_FILE ./app.jar
ENTRYPOINT ["java","-jar","/app/app.jar"]

我也有一个像这样的拼图:

代码语言:javascript
复制
version: "3.8"
services:
  server:
    restart: always
    container_name: server
    build:
      context: .
      dockerfile: Dockerfile
      target: server
    image: server
    ports:
      - "8090:8080"
  web-client:
    restart: always
    container_name: web-client
    build:
      context: .
      dockerfile: Dockerfile
      target: web-client
    image: web-client
    environment:
      - LISTEN_PORT=80
    ports:
      - "8091:80"

这里涉及的两个图像,web-clientserver是完全独立的。我想利用多阶段构建并行化。

当我运行docker-compose build (我使用的是docker-Composit1.27.4)时,输出如下所示

代码语言:javascript
复制
λ docker-compose build
Building server
Step 1/24 : FROM node:12.19.0 as web-client-builder
 ---> 1f560ce4ce7e
... etc ...
Step 6/24 : RUN npm run test:ci
 ---> Running in e9189b2bff1d
... Runs tests ...
... etc ...
Step 24/24 : ENTRYPOINT ["java","-jar","/app/app.jar"]
 ---> Using cache
 ---> 2ebe48e3b06e

Successfully built 2ebe48e3b06e
Successfully tagged server:latest
Building web-client
Step 1/11 : FROM node:12.19.0 as web-client-builder
 ---> 1f560ce4ce7e
... etc ...
Step 6/11 : RUN npm run test:ci
 ---> Using cache
 ---> 0f205b9549e0
... etc ...
Step 11/11 : COPY --from=web-client-builder /workspace/build /var/www/
 ---> Using cache
 ---> 31c4eac8c06e

Successfully built 31c4eac8c06e
Successfully tagged web-client:latest

注意,我的测试(npm run test:ci)运行了两次(步骤6/24对服务器目标运行,然后在步骤6/11运行web客户端目标)。我想了解为什么会发生这种情况,但我想这不是什么大问题,因为至少到了第二次测试时,它就被缓存了。

当我尝试并行运行我的构建时,这将成为一个更大的问题。现在我得到了这样的输出:

代码语言:javascript
复制
λ docker-compose build --parallel
Building server     ...
Building web-client ...
Building server
Building web-client
Step 1/11 : FROM node:12.19.0 as web-client-builderStep 1/24 : FROM node:12.19.0 as web-client-builder
 ---> 1f560ce4ce7e
... etc ...
Step 6/24 : RUN npm run test:ci
 ---> e96afb9c14bf
Step 6/11 : RUN npm run test:ci
 ---> Running in c17deba3c318
 ---> Running in 9b0faf487a7d

> web-client@0.1.0 test:ci /workspace
> react-scripts test --ci --coverage --reporters=default --reporters=jest-junit --watchAll=false


> web-client@0.1.0 test:ci /workspace
> react-scripts test --ci --coverage --reporters=default --reporters=jest-junit --watchAll=false
... Now my tests run in parallel twice, and the output is interleaved for both parallel runs ...

很明显,测试现在运行了两次,因为现在我正在并行运行构建,所以它们没有机会缓存。

有人能帮我理解这个吗?我认为docker多阶段构建的优点之一是它们是可并行的,但是这种行为对我来说没有意义。我误会什么了?

注意到我也尝试了使BuildKit的对接-撰写。我很难理解输出的意义。我不认为它运行了两次,但我也不确定它是否具有并行性。我需要更深入地研究它,但我的主要问题是:我希望理解为什么没有BuildKit的情况下,多阶段构建不会以我预期的方式并行运行。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-22 11:30:28

您可以将其分成两个独立的Dockerfile。我可以编写一个包含前两个阶段的web-client/Dockerfile (将相对COPY路径更改为./),并保留根目录Dockerfile来构建服务器应用程序。然后,您的docker-compose.yml文件可以指向以下这些单独的目录:

代码语言:javascript
复制
services:
  server:
    build: . # equivalent to {context: ., dockerfile: Dockerfile}
  web-client:
    build: web-client

正如@Stefano在他们的回答中所指出的,多阶段构建是围绕构建一个单一的最终映像而进行的优化,而在“经典”构建器中,它们总是从一开始一直运行到指定的目标阶段,而没有任何特定的逻辑从哪里开始。

票数 1
EN

Stack Overflow用户

发布于 2020-10-22 09:01:35

为什么在没有BuildKit的情况下,多阶段构建不会以我预期的方式并行运行。

这是BuildKit的最高点。

Docker多级的主要目的是只保留应用程序正常工作所需的内容,从而产生较小的图像。例如:

代码语言:javascript
复制
FROM node as builder

COPY package.json package-lock.json
RUN npm ci

COPY . /app

RUN npm run build

FROM nginx
COPY --from=/app/dist --chown=nginx /app/dist /var/www

构建项目所需的所有开发工具都没有复制到最终映像中。这转化为较小的最终图像。

编辑:

来自BuildKit文档

BuildKit构建基于名为LLB的二进制中间格式,该格式用于为运行部分构建的进程定义依赖关系图。tl;dr: LLB之于Dockerfile,就像LLVM IR对于C.

换句话说,BuildKit能够评估每个阶段的依赖关系,从而允许并行执行。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64474478

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档