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

Turborepo构建时推送所有镜像,如何仅推送最终Runner镜像?

问题:Docker多阶段构建推送所有中间镜像,仅需推送最终Runner镜像

背景

我拥有一个使用Turborepo的npm monorepo,希望通过GitHub Actions将其构建为生产环境镜像。

问题

使用docker/build-push-action GitHub Action时,所有3个中间镜像都被推送到了我的制品仓库,仅有最终的Runner镜像标签正确。

预期结果

仅将最终的Runner镜像推送到制品仓库

我的Dockerfile

FROM node:alpine AS builder
RUN apk add --no-cache libc6-compat
RUN apk update
# Set working directory
WORKDIR /app
RUN npm install turbo --global
COPY . .
RUN turbo prune --scope=admin --docker
 
# Add lockfile and package.json's of isolated subworkspace
FROM node:alpine AS installer
RUN apk add --no-cache libc6-compat
RUN apk update
WORKDIR /app
 
# First install the dependencies (as they change less often)
COPY .gitignore .gitignore
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/package-lock.json ./package-lock.json
RUN npm ci
 
# Build the project
ARG MONOLITH_DOMAIN
ENV MONOLITH_DOMAIN=$MONOLITH_DOMAIN

COPY --from=builder /app/out/full/ .
COPY turbo.json turbo.json

RUN npx turbo run build --filter=admin
 
FROM node:alpine AS runner
WORKDIR /app
 
# Don't run production as root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
 
COPY --from=installer /app/apps/admin/next.config.js .
COPY --from=installer /app/apps/admin/package.json .
 
# Automatically leverage output traces to reduce image size
COPY --from=installer --chown=nextjs:nodejs /app/apps/admin/.next/standalone ./
COPY --from=installer --chown=nextjs:nodejs /app/apps/admin/.next/static ./apps/admin/.next/static
COPY --from=installer --chown=nextjs:nodejs /app/apps/admin/public ./apps/admin/public
 
CMD node apps/admin/server.js

此Dockerfile遵循Turborepo官方推荐的多阶段构建方式。

我的GitHub Action

name: Build and Push Docker Image

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      tag:
        required: true
        type: string
      monolith_domain:
        required: true
        type: string
    secrets:
      GOOGLE_CLOUD_SERVICE_ACCOUNT_JSON_TOKEN:
        required: true

jobs:
  build-and-push:
    runs-on: ubuntu-latest

    steps:
    - name: Check out code
      uses: actions/checkout@v3

    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2

    - id: auth
      name: Authenticate to Google Cloud
      uses: google-github-actions/auth@v1
      with:
        token_format: access_token
        credentials_json: ${{ secrets.GOOGLE_CLOUD_SERVICE_ACCOUNT_JSON_TOKEN }}

    - uses: 'docker/login-action@v2'
      with:
        registry: europe-west1-docker.pkg.dev
        username: oauth2accesstoken
        password: ${{ steps.auth.outputs.access_token }}

    - name: Build and push Docker image
      uses: docker/build-push-action@v4
      with:
        context: .
        file: ./apps/admin/Dockerfile
        push: true
        tags: europe-west1-docker.pkg.dev/xxxx/frontend/admin-frontend:${{ inputs.tag }}
        build-args: |
          MONOLITH_DOMAIN=${{ inputs.monolith_domain }}

解决方案

问题根源是Docker Buildx在push: true时默认会推送所有构建阶段的镜像(包括中间的builder、installer阶段)。只需在docker/build-push-action中指定target: runner,即可只构建并推送最终的runner阶段镜像。

修改后的GitHub Action构建步骤如下:

- name: Build and push Docker image
  uses: docker/build-push-action@v4
  with:
    context: .
    file: ./apps/admin/Dockerfile
    push: true
    target: runner  # 指定仅构建推送runner阶段
    tags: europe-west1-docker.pkg.dev/xxxx/frontend/admin-frontend:${{ inputs.tag }}
    build-args: |
      MONOLITH_DOMAIN=${{ inputs.monolith_domain }}

原理说明

多阶段构建中,每个FROM指令定义一个构建阶段。默认情况下,build-push-action会将所有阶段的镜像推送到仓库(即使没有显式标签)。通过target参数指定最终阶段后,Action会只执行到该阶段,并仅推送这个阶段的镜像,中间阶段不会被推送。

内容的提问来源于stack exchange,提问作者Rickard Liljeberg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:27:46