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

Cloud Build等待制品上传后执行步骤及构建失败标记问题

解决Cloud Build部署Compute Engine的两个关键问题

问题1:确保Cloud Build等待制品上传完成后再执行后续步骤

Cloud Build的步骤默认是串行执行的,理论上gsutil cp完成后才会进入下一个步骤,但由于Cloud Storage的最终一致性,可能出现上传完成后短时间内无法读取文件的情况,导致实例启动脚本拉取失败。

解决方法是在上传制品后添加一个文件存在验证步骤,通过重试机制确保文件确实可访问后,再执行创建实例模板的操作:

steps:
  # 构建、归档二进制文件的步骤(你的原有步骤)
  - name: 'golang:1.21'
    args: ['go', 'build', '-o', 'app', './cmd']
  - name: 'ubuntu'
    args: ['tar', '-czf', 'app.tar.gz', 'app']
  
  # 上传制品到Cloud Storage
  - name: 'gcr.io/cloud-builders/gsutil'
    args: ['cp', 'app.tar.gz', 'gs://bucket-name/deploy/service-name/${COMMIT_SHA}/']
  
  # 验证文件存在(带重试,适配最终一致性)
  - name: 'gcr.io/cloud-builders/gsutil'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        RETRIES=5
        DELAY=10
        FILE_PATH="gs://bucket-name/deploy/service-name/${COMMIT_SHA}/app.tar.gz"
        for ((i=0; i<RETRIES; i++)); do
          if gsutil stat "$FILE_PATH"; then
            echo "制品已确认存在,继续后续步骤"
            exit 0
          fi
          echo "制品暂不可访问,$DELAY秒后重试(第$((i+1))次)"
          sleep "$DELAY"
        done
        echo "重试$RETRIES次后仍无法访问制品,构建失败"
        exit 1
  
  # 创建实例模板的步骤(你的原有步骤)
  - name: 'gcr.io/cloud-builders/gcloud'
    args: ['compute', 'instance-templates', 'create', 'TEMPLATE_NAME', ...]

这个验证步骤会循环检查文件状态,直到成功或重试耗尽,确保后续步骤执行时制品已经可以被实例的启动脚本读取。

问题2:启动脚本失败时标记Cloud Build为失败,阻止实例组更新

启动脚本在实例内部执行,默认不会反馈状态到Cloud Build,导致构建成功但实例启动异常。可以通过两种方式实现状态反馈:

方式1:利用实例组健康检查等待稳定状态

如果你的实例组配置了健康检查(推荐配置),可以在Cloud Build中添加步骤,等待实例组更新完成并进入稳定状态:

# 创建实例模板后,更新实例组的步骤(你的原有步骤)
- name: 'gcr.io/cloud-builders/gcloud'
  args: ['compute', 'instance-groups', 'managed', 'rolling-action', 'start-update', 'INSTANCE_GROUP_NAME', '--template', 'TEMPLATE_NAME', '--zone', 'ZONE']

# 等待实例组进入稳定状态
- name: 'gcr.io/cloud-builders/gcloud'
  args:
    - 'compute'
    - 'instance-groups'
    - 'managed'
    - 'wait-until-stable'
    - 'INSTANCE_GROUP_NAME'
    - '--zone'
    - 'ZONE'
    - '--timeout'
    - '300s' # 5分钟超时,可根据实际调整

如果启动脚本执行失败,实例会无法通过健康检查,wait-until-stable命令会返回非零退出码,导致整个Cloud Build标记为失败,从而阻止后续的实例组更新。

方式2:启动脚本主动上报执行状态到Cloud Storage

在启动脚本中添加状态上报逻辑,将执行结果写入Cloud Storage的指定文件,然后Cloud Build轮询该文件获取状态:

启动脚本片段:

# 执行部署与初始化逻辑
./deploy_and_init.sh

# 上报执行状态
STATUS=$?
STATUS_FILE="/tmp/startup_status"
REMOTE_STATUS_PATH="gs://bucket-name/deploy/service-name/${COMMIT_SHA}/startup_status"

if [ $STATUS -eq 0 ]; then
  echo "SUCCESS" > "$STATUS_FILE"
  gsutil cp "$STATUS_FILE" "$REMOTE_STATUS_PATH"
else
  echo "FAILED" > "$STATUS_FILE"
  gsutil cp "$STATUS_FILE" "$REMOTE_STATUS_PATH"
  exit $STATUS
fi

Cloud Build中添加轮询步骤:

# 更新实例组后,添加轮询步骤
- name: 'gcr.io/cloud-builders/gsutil'
  entrypoint: 'bash'
  args:
    - '-c'
    - |
      RETRIES=10
      DELAY=30
      STATUS_FILE="gs://bucket-name/deploy/service-name/${COMMIT_SHA}/startup_status"
      for ((i=0; i<RETRIES; i++)); do
        if gsutil stat "$STATUS_FILE" 2>/dev/null; then
          STATUS=$(gsutil cat "$STATUS_FILE")
          if [ "$STATUS" = "SUCCESS" ]; then
            echo "启动脚本执行成功"
            exit 0
          else
            echo "启动脚本执行失败"
            exit 1
          fi
        fi
        echo "等待启动脚本状态上报,$DELAY秒后重试(第$((i+1))次)"
        sleep "$DELAY"
      done
      echo "超时未收到启动脚本状态,构建失败"
      exit 1

这种方式不需要依赖健康检查,适合无法配置健康检查的场景,但需要确保实例的服务账号有写入Cloud Storage的权限。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:30:41