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

Cloud Build+Cloud Run:安全运行测试且仅执行一次npm install

问题

我的Cloud Build执行流程如下:

  1. 从Dockerfile构建镜像
  2. 将镜像推送到Container Registry
  3. 更新Cloud Run中的服务

当前遇到的核心问题:
构建阶段运行测试必须使用MONGODB_URI密钥,但通过--build-arg传递密钥存在泄露风险;若在Cloud Build容器中单独执行npm install和npm run test,又会导致npm install重复执行,拉长构建时长。需要找到一种既能仅执行一次npm install,又不暴露密钥的方案。

当前使用的Dockerfile:

FROM node:16
COPY . ./
WORKDIR /
RUN npm install 

ARG env
ARG mongodb_uri

ENV ENVIRONMENT=$env
ENV DB_REMOTE_PROD=$mongodb_uri

RUN npm run test
RUN npm run build
CMD ["node", "./build/index.js"]

当前的cloudbuild.yaml配置:

steps:
  - name: gcr.io/cloud-builders/docker
    args:
      - '-c'
      - >-
        docker build --no-cache -t
        $_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
        --build-arg ENVIRONMENT=staging --build-arg mongodb_uri=$$MONGODB_URI -f
        Dockerfile .
    id: Build
    entrypoint: bash
    secretEnv:
      - MONGODB_URI
  - name: gcr.io/cloud-builders/docker
    args:
      - push
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
    id: Push
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
    args:
      - '-c'
      - >-
        gcloud run services update $_SERVICE_NAME --platform=managed
        --image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
        --labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID
        --region=$_DEPLOY_REGION --update-env-vars=ENVIRONMENT=staging
        --update-env-vars=DB_REMOTE_PROD=$$MONGODB_URI --quiet
    id: Deploy
    entrypoint: bash
    secretEnv:
      - MONGODB_URI
images:
  - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
options:
  substitutionOption: ALLOW_LOOSE
  logging: CLOUD_LOGGING_ONLY
substitutions:
  _TRIGGER_ID: 44b16efe-0219-41af-b32b-9b98438728c3
  _GCR_HOSTNAME: eu.gcr.io
  _PLATFORM: managed
  _SERVICE_NAME: app-staging
  _DEPLOY_REGION: europe-southwest1
availableSecrets:
  secretManager:
    - versionName: projects/PROJECT_ID/secrets/mongodb_app_staging/versions/1
      env: MONGODB_URI

当前方案的弊端:

  • build-arg传递的密钥会留存于镜像构建历史中,存在泄露风险
  • Cloud Run服务配置中用明文环境变量存储密钥,所有拥有服务访问权限的用户都能看到
解决方案

方法1:拆分构建步骤,利用Cloud Build工作目录缓存

将依赖安装、测试、代码构建放在Cloud Build容器中完成,仅把最终产物复制到镜像,避免重复执行npm install:

修改cloudbuild.yaml

添加Node.js步骤完成依赖安装和测试,再用精简的Dockerfile构建最终镜像:

steps:
  # 第一步:在Cloud Build容器内完成依赖安装、测试、代码构建
  - name: node:16
    args: ['npm', 'install']
    id: InstallDependencies
    secretEnv: ['MONGODB_URI']
    env:
      - 'ENVIRONMENT=staging'
      - 'DB_REMOTE_PROD=$MONGODB_URI'
  - name: node:16
    args: ['npm', 'run', 'test']
    id: RunTests
    secretEnv: ['MONGODB_URI']
    env:
      - 'ENVIRONMENT=staging'
      - 'DB_REMOTE_PROD=$MONGODB_URI'
  - name: node:16
    args: ['npm', 'run', 'build']
    id: BuildApp

  # 第二步:构建仅包含运行时所需文件的最终镜像
  - name: gcr.io/cloud-builders/docker
    args:
      - build
      - '-t'
      - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
      - '-f'
      - Dockerfile.final
      - '.'
    id: BuildFinalImage

  # 推送镜像(原步骤不变)
  - name: gcr.io/cloud-builders/docker
    args: ['push', '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA']
    id: Push
  
  # 部署Cloud Run,改用Secret Manager传递密钥
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:slim'
    args:
      - '-c'
      - >-
        gcloud run services update $_SERVICE_NAME --platform=managed
        --image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
        --labels=managed-by=gcp-cloud-build-deploy-cloud-run,commit-sha=$COMMIT_SHA,gcb-build-id=$BUILD_ID,gcb-trigger-id=$_TRIGGER_ID
        --region=$_DEPLOY_REGION --update-env-vars=ENVIRONMENT=staging
        --update-secrets=DB_REMOTE_PROD=mongodb_app_staging:latest --quiet
    id: Deploy
    entrypoint: bash

images:
  - '$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA'
options:
  substitutionOption: ALLOW_LOOSE
  logging: CLOUD_LOGGING_ONLY
substitutions:
  _TRIGGER_ID: 44b16efe-0219-41af-b32b-9b98438728c3
  _GCR_HOSTNAME: eu.gcr.io
  _PLATFORM: managed
  _SERVICE_NAME: app-staging
  _DEPLOY_REGION: europe-southwest1
availableSecrets:
  secretManager:
    - versionName: projects/PROJECT_ID/secrets/mongodb_app_staging/versions/1
      env: MONGODB_URI

创建Dockerfile.final

仅复制运行时必需的文件,避免重复安装依赖:

FROM node:16
WORKDIR /
# 复制Cloud Build中已安装好的依赖
COPY package*.json ./
COPY node_modules ./node_modules/
# 复制构建完成的代码
COPY build ./build/
CMD ["node", "./build/index.js"]

优势:

  • npm install仅执行一次,利用Cloud Build工作目录缓存加速后续构建
  • 密钥仅在Cloud Build步骤中临时使用,不会进入镜像或Cloud Run配置
  • Cloud Run通过Secret Manager拉取密钥,避免明文暴露

方法2:使用Docker BuildKit临时挂载秘密

Docker BuildKit支持构建时临时挂载秘密,密钥不会写入镜像层,无需拆分构建步骤:

修改Dockerfile

启用BuildKit语法,挂载秘密用于测试:

# syntax=docker/dockerfile:1.4
FROM node:16
COPY . ./
WORKDIR /
RUN npm install

# 临时挂载秘密,仅在测试阶段可用,不会留存到镜像
RUN --mount=type=secret,id=mongodb_uri \
    export DB_REMOTE_PROD=$(cat /run/secrets/mongodb_uri) && \
    export ENVIRONMENT=staging && \
    npm run test

RUN npm run build
CMD ["node", "./build/index.js"]

修改cloudbuild.yaml的构建步骤

启用BuildKit并传递秘密:

steps:
  - name: gcr.io/cloud-builders/docker
    args:
      - '-c'
      - >-
        DOCKER_BUILDKIT=1 docker build --no-cache -t
        $_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA
        --secret id=mongodb_uri,env=MONGODB_URI -f Dockerfile .
    id: Build
    entrypoint: bash
    secretEnv:
      - MONGODB_URI
  # 推送和部署步骤同方法1,部署时用Secret Manager传递密钥

优势:

  • 无需拆分构建流程,保持Dockerfile的完整性
  • 密钥仅在测试阶段临时挂载,不会留存于镜像构建历史或最终镜像中
  • npm install仅执行一次,不增加构建时长

关键优化:Cloud Run密钥管理

部署Cloud Run时,务必使用--update-secrets替代--update-env-vars传递密钥:

gcloud run services update $_SERVICE_NAME \
  --platform=managed \
  --image=$_GCR_HOSTNAME/$PROJECT_ID/$REPO_NAME/$_SERVICE_NAME:$COMMIT_SHA \
  --region=$_DEPLOY_REGION \
  --update-env-vars=ENVIRONMENT=staging \
  --update-secrets=DB_REMOTE_PROD=projects/PROJECT_ID/secrets/mongodb_app_staging:latest

这样密钥仅存储在Secret Manager中,Cloud Run运行时自动拉取,服务配置中不会出现明文密钥,只有授权用户能访问Secret Manager中的内容。

内容的提问来源于stack exchange,提问作者Paul Serre

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:40:38