如何在cloudbuild.yaml中实现动态版本控制并解决替换报错?
从package.json自动获取版本号并用于Cloud Build构建
问题场景
当前Cloud Build配置(cloudbuild.yaml)需要手动填写${_VERSION}作为应用版本号,尝试从package.json读取版本号自动赋值时,触发错误:
Your build failed to run: generic::invalid_argument: invalid value for 'build.substitutions': key in the template "VERSION" is not a valid built-in substitution.
原手动配置内容:
steps: # Step 1: Build the Docker image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'demo-backend', '-f', 'backend/Dockerfile', 'backend'] # Step 2: Tag the Docker image - name: 'gcr.io/cloud-builders/docker' args: ['tag', 'demo-backend', 'location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:${_VERSION}'] # Step 3: Push the Docker image to Google Container Registry (GCR) - name: 'gcr.io/cloud-builders/docker' args: ['push', 'location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:${_VERSION}'] # Step 4: Deploy the container image to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: - 'run' - 'deploy' - 'demo-backend' - '--image=location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:${_VERSION}' - '--platform=managed' - '--region=location' - '--allow-unauthenticated' substitutions: _VERSION: '1.0.0' options: defaultLogsBucketBehavior: 'REGIONAL_USER_OWNED_BUCKET'
原尝试的自动版本方案(报错):
steps: # Step 1: Fetch version from package.json and store it in an environment variable - name: 'ubuntu' entrypoint: 'bash' args: - '-c' - | VERSION=$(jq -r .version package.json) echo "VERSION=${VERSION}" > /workspace/version.env # Step 2: Load the version from the environment file and export it as a substitution - name: 'ubuntu' entrypoint: 'bash' args: - '-c' - | source /workspace/version.env gcloud builds submit --substitutions=_VERSION=${VERSION} . # Step 3: Build the Docker image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'demo-backend', '-f', 'backend/Dockerfile', 'backend'] # Step 4: Tag the Docker image - name: 'gcr.io/cloud-builders/docker' args: ['tag', 'demo-backend', 'location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:${_VERSION}'] # Step 5: Push the Docker image to Google Container Registry (GCR) - name: 'gcr.io/cloud-builders/docker' args: ['push', 'location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:${_VERSION}'] # Step 6: Deploy the container image to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: gcloud args: - 'run' - 'deploy' - 'demo-backend' - '--image=location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:${_VERSION}' - '--platform=managed' - '--region=location' - '--allow-unauthenticated' substitutions: _VERSION: '1.0.0' # Default value, will be overridden by the fetched version options: defaultLogsBucketBehavior: 'REGIONAL_USER_OWNED_BUCKET'
错误原因
- Cloud Build的替换变量(如
${_VERSION})在构建启动前就已完成解析,构建步骤内无法动态修改或覆盖替换变量的值。 - 原方案中步骤2调用
gcloud builds submit递归触发新构建,不仅会重复执行流程,还因替换变量传递方式错误导致报错。
正确解决方案
不需要递归提交构建,直接在需要版本号的步骤中读取package.json的版本,或者将版本号写入文件后在后续步骤中引用。以下是两种可行方案:
方案1:直接在步骤中读取版本号
使用bash脚本直接读取package.json的版本,并在docker命令和gcloud命令中使用:
steps: # Step 1: Build Docker image(无需版本号) - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'demo-backend', '-f', 'backend/Dockerfile', 'backend'] # Step 2: Tag & Push Docker image,同时读取版本号 - name: 'ubuntu' entrypoint: 'bash' args: - '-c' - | VERSION=$(jq -r .version package.json) docker tag demo-backend location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:$VERSION docker push location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:$VERSION # Step 3: Deploy to Cloud Run,使用读取到的版本号 - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: 'bash' args: - '-c' - | VERSION=$(jq -r .version package.json) gcloud run deploy demo-backend \ --image=location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:$VERSION \ --platform=managed \ --region=location \ --allow-unauthenticated options: defaultLogsBucketBehavior: 'REGIONAL_USER_OWNED_BUCKET'
方案2:将版本号写入文件,后续步骤引用
先将版本号写入文件,后续步骤通过读取文件获取版本,避免重复解析package.json:
steps: # Step 1: 读取版本号并写入文件 - name: 'ubuntu' entrypoint: 'bash' args: - '-c' - | jq -r .version package.json > /workspace/VERSION # Step 2: Build Docker image - name: 'gcr.io/cloud-builders/docker' args: ['build', '-t', 'demo-backend', '-f', 'backend/Dockerfile', 'backend'] # Step 3: Tag Docker image - name: 'ubuntu' entrypoint: 'bash' args: - '-c' - | VERSION=$(cat /workspace/VERSION) docker tag demo-backend location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:$VERSION # Step 4: Push Docker image - name: 'ubuntu' entrypoint: 'bash' args: - '-c' - | VERSION=$(cat /workspace/VERSION) docker push location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:$VERSION # Step 5: Deploy to Cloud Run - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' entrypoint: 'bash' args: - '-c' - | VERSION=$(cat /workspace/VERSION) gcloud run deploy demo-backend \ --image=location-docker.pkg.dev/demo/demo-backend-repository/demo-backend:$VERSION \ --platform=managed \ --region=location \ --allow-unauthenticated options: defaultLogsBucketBehavior: 'REGIONAL_USER_OWNED_BUCKET'
注意事项
- 确保构建环境中已安装
jq工具(ubuntu镜像默认包含,若使用其他镜像需自行安装)。 - 如果package.json不在代码根目录,需调整
jq命令的路径(如backend/package.json)。
内容的提问来源于stack exchange,提问作者Rishav Kumar
相关产品推荐
相关产品推荐

