[英]Docker multi platform builds extremely slow for ARM64 on Gitlab CI
对于 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
到目前为止,我一直专门为 AMD64 构建,但现在我还需要为 ARM64 构建。
我将 my.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 .
对于 AMD64,一切都相对良好,但对于 ARM64 却非常慢。 几乎比 AMD64 慢 10 倍,让我在 Gitlab 作业上超时。
有什么办法可以加快这个过程吗?
我猜您的管道正在 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
更新gitlab-ci.yml
:
image: docker:20
variables:
PROJECT_NAME: "project"
BRANCH_NAME: "main"
IMAGE_NAME: "$PROJECT_NAME:$CI_COMMIT_TAG"
REGISTRY_IMAGE_NAME: "$CI_REGISTRY/mygroup/$PROJECT_NAME/$IMAGE_NAME"
CACHE_IMAGE_NAME: "$CI_REGISTRY/mygroup/$PROJECT_NAME/$PROJECT_NAME:cache"
BUILDKIT_INLINE_CACHE: "1"
services:
- docker:20-dind
stages:
- build
- push
before_script:
- 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
build_amd64:
stage: build
script:
- docker buildx build --cache-from "$CACHE_IMAGE_NAME" --tag "$CACHE_IMAGE_NAME" --push --platform=linux/amd64 .
build_arm64:
stage: build
script:
- docker buildx build --cache-from "$CACHE_IMAGE_NAME" --tag "$CACHE_IMAGE_NAME" --push --platform=linux/arm64/v8 .
push:
stage: push
script:
- docker buildx build --cache-from "$CACHE_IMAGE_NAME" --tag "$REGISTRY_IMAGE_NAME" --push --platform=linux/arm64/v8,linux/amd64 .
build_amd64
和build_arm64
作业分别拉取最后构建的(其 arch 的)图像,并将其用作 docker 个图像层的缓存。 这两个构建作业然后将它们的结果作为新缓存推送回来。
push
阶段再次运行docker buildx...
,但它们实际上不会构建任何新内容,因为它们只会从两个构建作业中提取缓存结果。 这允许您分解构建,但仍然有一个单一的推送命令,该命令导致两个不同的图像最终出现在一个多平台 docker 清单中。
我在 Google Cloud Build 上运行构建缓慢的问题,最终使用原生arm64
硬件来加速构建的arm64
部分。
我为此写了一个详细的教程,它使用 Docker 上下文指向远程arm64
VM。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.