在GitHub使用Rebase and Merge时,如何实现基于GCR/Cloud Run的不可变构建?
解决Rebase and Merge下复用PR阶段构建镜像的问题
核心问题是Rebase and Merge会生成新的提交SHA,导致main分支push工作流无法找到PR阶段用原SHA构建的镜像。以下是两种可行的解决方案:
方法一:为PR镜像添加PR编号标签
在PR工作流中给镜像额外打上PR编号的标签,合并到main后通过PR编号找到对应的镜像。
1. 修改PR工作流,添加PR编号标签
在构建推送镜像的步骤中,增加PR编号标签的推送:
on: pull_request: types: [opened, synchronize, reopened, edited] branches: [main] jobs: build-dev: runs-on: ubuntu-latest strategy: matrix: app: [your-app-name] steps: - name: Checkout code uses: actions/checkout@v4 # 省略身份验证、环境变量设置等步骤 - name: Build and push Docker image to GCR run: | # 构建并推送原SHA标签的镜像 docker build -t gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:${{ github.sha }} . docker push gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:${{ github.sha }} # 添加PR编号标签并推送 docker tag gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:${{ github.sha }} gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:pr-${{ github.event.number }} docker push gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:pr-${{ github.event.number }} # 省略Cloud Run dev环境部署步骤
2. 修改main分支push工作流,通过PR编号获取镜像
在main分支的push工作流中,用GitHub CLI找到当前提交对应的PR编号,再用该标签拉取镜像并重打test环境标签:
on: push: branches: [main] jobs: deploy-test: runs-on: ubuntu-latest strategy: matrix: app: [your-app-name] steps: - name: Install GitHub CLI run: | type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y) curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ && sudo apt update && sudo apt install gh -y - name: Authenticate GitHub CLI run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - name: Get merged PR number id: get-pr-number run: | PR_NUMBER=$(gh pr view --commit ${{ github.sha }} --json number --jq '.number') echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT - name: Tag Docker image for test run: | gcloud container images add-tag \ gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:pr-${{ steps.get-pr-number.outputs.pr_number }} \ gcr.io/${{ env.PROJECT_ID }}/test-${{ matrix.app }}:${{ github.sha }} # 省略Cloud Run test环境部署步骤
方法二:使用镜像Digest(更可靠)
镜像的Digest是唯一且不可变的标识,不会随标签或Rebase操作变化。在PR工作流中记录Digest,main工作流直接用Digest引用镜像。
1. PR工作流中记录镜像Digest
构建镜像后获取Digest,并存入GitHub提交状态:
# PR工作流中的构建步骤 - name: Build and push Docker image to GCR id: build-image run: | docker build -t gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:${{ github.sha }} . docker push gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:${{ github.sha }} # 获取镜像Digest IMAGE_DIGEST=$(gcloud container images describe gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}:${{ github.sha }} --format='value(image_summary.digest)') echo "image_digest=gcr.io/${{ env.PROJECT_ID }}/dev-${{ matrix.app }}@${IMAGE_DIGEST}" >> $GITHUB_OUTPUT - name: Save Digest to commit status run: | gh api repos/${{ github.repository }}/statuses/${{ github.sha }} \ -X POST \ -f state="success" \ -f context="built-image-digest" \ -f description="Dev environment image digest" \ -f output="{\"digest\": \"${{ steps.build-image.outputs.image_digest }}\"}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2. main工作流中获取Digest并部署
找到合并PR对应的原提交,取出Digest直接用于部署:
# main分支push工作流的部署步骤 - name: Install GitHub CLI run: | type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y) curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ && sudo apt update && sudo apt install gh -y - name: Authenticate GitHub CLI run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token - name: Get image Digest from PR commit id: get-digest run: | # 获取合并PR的原提交SHA PR_HEAD_SHA=$(gh pr view --commit ${{ github.sha }} --json headSha --jq '.headSha') # 从提交状态中取出Digest IMAGE_DIGEST=$(gh api repos/${{ github.repository }}/statuses/${PR_HEAD_SHA} --jq '.[] | select(.context == "built-image-digest") | .output.digest') echo "image_digest=${IMAGE_DIGEST}" >> $GITHUB_OUTPUT - name: Deploy to test environment run: | gcloud run deploy test-${{ matrix.app }} \ --image ${{ steps.get-digest.outputs.image_digest }} \ --platform managed \ --region your-gcp-region \ --env ENV=test
内容的提问来源于stack exchange,提问作者Safwan Parkar
相关产品推荐
相关产品推荐

