Docker 多平台在 Gitlab CI 上针对 ARM64 构建速度极慢

Rab*_*nge 7 node.js gitlab docker arm64

我有以下 Node.js 应用程序的 dockerfile

# ---> Build stage
FROM node:18-bullseye as node-build

ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY . /usr/src/app/
RUN yarn install --silent --production=true --frozen-lockfile
RUN yarn build --silent

# ---> Serve stage
FROM nginx:stable-alpine
COPY --from=node-build /usr/src/app/dist /usr/share/nginx/html
Run Code Online (Sandbox Code Playgroud)

到目前为止,我专门为 AMD64 构建,但现在我也需要为 ARM64 构建。

我编辑了 .gitlab-ci.yml 如下所示

image: docker:20

variables:
    PROJECT_NAME: "project"
    BRANCH_NAME: "main"
    IMAGE_NAME: "$PROJECT_NAME:$CI_COMMIT_TAG"

services:
    - docker:20-dind

build_image:
    script:
      # Push to Gitlab registry
      - docker login $CI_REGISTRY -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
      - docker context create builder-context
      - docker buildx create --name builderx --driver docker-container --use builder-context
      - docker buildx build --tag $CI_REGISTRY/mygroup/$PROJECT_NAME/$IMAGE_NAME --push --platform=linux/arm64/v8,linux/amd64 .
Run Code Online (Sandbox Code Playgroud)

对于 AMD64 来说,一切都相对正常,但对于 ARM64 来说,速度非常慢。几乎比 AMD64 慢 10 倍,导致我的 Gitlab 作业超时。

有什么办法可以加快这个过程吗?

Wil*_*ltz 5

我猜测您的管道正在 amd64 硬件上执行,并且docker buildx正在执行模拟来构建 arm64 目标。build_image如果您分成两个作业(一个用于 amd64,一个用于 arm64),然后将它们发送到两个不同的 gitlab 运行程序,以便它们每个都可以在其本机硬件上执行,您可能会看到很大的改进。

即使您不能或不想停止使用模拟,您仍然可以将作业build_image分成两个作业(每个构建的图像一个),希望并行运行它们能够让作业在超时限制之前完成。

通过更改 Dockerfile 和使用映像缓存,您可以使后续的某些构建速度更快,但在构建初始映像(可用作缓存)之前,这些更改不会对您有帮助。

更新Dockerfile:

# ---> Build stage
FROM node:18-bullseye as node-build

ENV NODE_ENV=production
WORKDIR /usr/src/app
# only COPY yarn.lock so not to break cache if dependencies have not changed
COPY . /usr/src/app/yarn.lock 
RUN yarn install --silent --production=true --frozen-lockfile
# once the dependencies are installed, then copy in the frequently changing source code files
COPY . /usr/src/app/
RUN yarn build --silent

# ---> Serve stage
FROM nginx:stable-alpine
COPY --from=node-build /usr/src/app/dist /usr/share/nginx/html
Run Code Online (Sandbox Code Playgroud)

更新gitlab-ci.yml:

# ---> Build stage
FROM node:18-bullseye as node-build

ENV NODE_ENV=production
WORKDIR /usr/src/app
# only COPY yarn.lock so not to break cache if dependencies have not changed
COPY . /usr/src/app/yarn.lock 
RUN yarn install --silent --production=true --frozen-lockfile
# once the dependencies are installed, then copy in the frequently changing source code files
COPY . /usr/src/app/
RUN yarn build --silent

# ---> Serve stage
FROM nginx:stable-alpine
COPY --from=node-build /usr/src/app/dist /usr/share/nginx/html
Run Code Online (Sandbox Code Playgroud)

和build_amd64作业build_arm64各自提取构建的最后一个映像(其架构的),并将其用作 docker 映像层的缓存。然后,这两个构建作业将其结果推送回新的缓存。

该push阶段docker buildx ...再次运行,但他们实际上不会构建任何新的东西,因为他们只会从两个构建作业中提取缓存的结果。这允许您分解构建,但仍然可以使用单个推送命令,从而导致两个不同的映像最终出现在单个多平台 Docker 清单中。