You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在GitHub Action自定义脚本构建Docker镜像时,如何缓存npm/yarn依赖与Docker层?

问题描述

我需要在GitHub Action的Docker镜像中编译React单页应用,希望优化缓存与构建时间,当前情况如下:

  • 通过自定义脚本在GitHub Action中执行docker build;
  • Dockerfile中调用yarn(yarn 1)安装node_modules。

我的GitHub Action配置:

name: Build and push docker image on AWS
on:
  push:

jobs:
  build:
    steps:
      [...]
      - name: Build docker images & push to AWS
        run: ./scripts/deploy/build_and_push_docker_image_to_aws.sh
        env:
          DOCKER_BUILDKIT: 1

注:不想直接通过GitHub Action构建Docker镜像(已有相关方案),因为需要完成重复镜像检查、推送到AWS等额外操作,且希望脚本可在GitHub Action外运行以提升可维护性。

我的build_and_push_docker_image_to_aws.sh脚本:

[...]
docker build \
  --file ./docker/nginx/Dockerfile \
  --build-arg FRIENDLY_TAG=$(./scripts/get_friendly_tag.sh) \
  --tag xxxx \
  docker/nginx/.
[...]

Dockerfile内容:

FROM node:15.14 as build-deps
COPY package.json yarn.lock .yarnrc ./
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc yarn

我的思路是完成两项操作:

  1. 在GitHub Action与docker build间共享Docker层缓存,实现docker/setup-buildx-action@v1+docker/build-push-action@v2的缓存效果,但通过bash脚本执行;
  2. 在GitHub Action运行器与Docker上下文间共享本地node_modules目录,并通过GitHub Action缓存该目录(类似docker build --secret的作用,但针对文件夹)。

请问我的思路是否正确?现有方案均直接通过特定GitHub Action构建Docker镜像,无法直接复用。

解决方案

你的思路完全正确,以下是具体实现步骤:

一、实现Docker层缓存(替代build-push-action的缓存效果)

因为你已启用Docker BuildKit(设置了DOCKER_BUILDKIT: 1),可以通过以下两种方式实现层缓存:

1. 用GitHub Cache存储Docker构建层

在GitHub Action的steps中添加缓存步骤,持久化Docker BuildKit的缓存目录:

- name: Cache Docker layers
  uses: actions/cache@v3
  with:
    path: /tmp/.buildx-cache
    key: ${{ runner.os }}-buildx-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-buildx-

修改build_and_push_docker_image_to_aws.sh中的docker build命令,添加BuildKit缓存参数:

docker build \
  --file ./docker/nginx/Dockerfile \
  --build-arg FRIENDLY_TAG=$(./scripts/get_friendly_tag.sh) \
  --tag xxxx \
  --cache-from type=local,src=/tmp/.buildx-cache \
  --cache-to type=local,dest=/tmp/.buildx-cache,mode=max \
  docker/nginx/.

2. 可选:用AWS ECR作为远程缓存

如果镜像最终推送到AWS ECR,可将缓存存储到ECR镜像中,规避GitHub Cache的空间限制:

# 尝试拉取已存在的缓存镜像
docker pull xxxx-cache || true

docker build \
  --file ./docker/nginx/Dockerfile \
  --build-arg FRIENDLY_TAG=$(./scripts/get_friendly_tag.sh) \
  --tag xxxx \
  --tag xxxx-cache \
  --cache-from type=registry,ref=xxxx-cache \
  --cache-to type=registry,ref=xxxx-cache,mode=max \
  docker/nginx/.

# 推送缓存镜像到ECR
docker push xxxx-cache

二、共享并缓存node_modules目录

1. 在GitHub Action中缓存node_modules

在GitHub Action steps中添加依赖缓存步骤:

- name: Cache node_modules
  uses: actions/cache@v3
  with:
    path: ./docker/nginx/node_modules
    key: ${{ runner.os }}-yarn-${{ hashFiles('./docker/nginx/yarn.lock') }}
    restore-keys: |
      ${{ runner.os }}-yarn-

2. 在Docker构建时复用本地node_modules

修改Dockerfile,通过bind挂载本地node_modules,仅在目录不存在时执行安装:

FROM node:15.14 as build-deps
COPY package.json yarn.lock .yarnrc ./
# 挂载本地node_modules,存在则复用,不存在则执行yarn安装
RUN --mount=type=bind,source=./node_modules,target=./node_modules \
    --mount=type=secret,id=npmrc,target=/root/.npmrc \
    if [ ! -d "node_modules" ]; then yarn; fi
# 执行后续构建步骤
COPY . ./
RUN yarn build

注意事项

  • 确保Docker BuildKit始终处于启用状态;
  • 依赖缓存的key基于yarn.lock生成,确保仅当依赖变更时才重新安装;
  • 本地缓存挂载需配合actions/cache,因为GitHub Action运行器环境是临时的,无法自动持久化数据。

内容的提问来源于stack exchange,提问作者Cyril Duchon-Doris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:12:48