如何在GitHub Action作业中复用同一ID的步骤(两步复用)
嘿,我来帮你搞定GitHub Action里复用步骤的问题!首先得说清楚:GitHub Actions要求同一个作业里的步骤ID必须唯一,所以不能直接复制粘贴带相同ID的步骤,但我们可以复用步骤的核心逻辑,同时给每个执行实例分配不同的ID,或者用矩阵、复合动作的方式来实现。结合你提供的ECR镜像构建步骤,我给你几个实用的方案:
方案一:用YAML锚点在同一作业里复用步骤逻辑
如果只是在同一个Workflow文件里复用步骤逻辑,YAML的锚点和引用语法就很方便。我们可以先定义一个步骤模板,然后多次引用它,同时覆盖必要的参数(比如app-name)和设置唯一ID。
示例代码:
jobs: build-images: runs-on: ubuntu-latest steps: # 先完成前置步骤(比如ECR登录、版本号获取) - name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Get package version id: package-version run: echo "current-version=1.0.0" >> $GITHUB_OUTPUT # 定义可复用的步骤锚点 - &build-push-template name: Build, tag, and push image to Amazon ECR env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: ${{ env.RESOURCES_NAME }} IMAGE_TAG: ${{ steps.package-version.outputs.current-version }}-${{ github.sha }} PHONES_DATABASE_URL: ${{ secrets.PHONES_DATABASE_URL }} run: | docker build --build-arg PHONES_DATABASE_URL=$PHONES_DATABASE_URL -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -f $DOCKERFILE_PATH . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT # 第一次复用:构建app1,设置唯一ID - <<: *build-push-template id: build-image-app1 env: <<: *build-push-template.env DOCKERFILE_PATH: ./docker/Dockerfile.app1-cloud name: Build, tag, and push app1 image to Amazon ECR # 第二次复用:构建app2,设置唯一ID - <<: *build-push-template id: build-image-app2 env: <<: *build-push-template.env DOCKERFILE_PATH: ./docker/Dockerfile.app2-cloud name: Build, tag, and push app2 image to Amazon ECR
这里用&build-push-template定义了步骤模板,再用<<: *build-push-template引用模板,同时覆盖ID、名称和Dockerfile路径,既复用了核心逻辑,又满足了ID唯一性要求。
方案二:封装成可复用的Composite Action
如果需要在多个Workflow里复用这个步骤,把它封装成独立的Composite Action会更灵活。你可以在仓库里创建一个actions/build-push-ecr/action.yaml文件,内容如下:
name: 'Build, Tag, Push to ECR' description: 'Builds a Docker image, tags it, and pushes to Amazon ECR' inputs: app-name: description: 'Name of the application to build' required: true ecr-registry: description: 'ECR registry URL' required: true ecr-repository: description: 'ECR repository name' required: true image-tag: description: 'Tag for the Docker image' required: true phones-database-url: description: 'Database URL for phones service' required: true runs: using: 'composite' steps: - name: Build, tag, and push image to Amazon ECR id: build-image shell: bash env: DOCKERFILE_PATH: ./docker/Dockerfile.${{ inputs.app-name }}-cloud PHONES_DATABASE_URL: ${{ inputs.phones-database-url }} ECR_REGISTRY: ${{ inputs.ecr-registry }} ECR_REPOSITORY: ${{ inputs.ecr-repository }} IMAGE_TAG: ${{ inputs.image-tag }} run: | docker build --build-arg PHONES_DATABASE_URL=$PHONES_DATABASE_URL -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -f $DOCKERFILE_PATH . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
之后在任意Workflow里,就可以多次调用这个Action,每次设置唯一ID:
jobs: build-images: runs-on: ubuntu-latest steps: - name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Get package version id: package-version run: echo "current-version=1.0.0" >> $GITHUB_OUTPUT # 第一次调用:构建app1,ID为build-image-app1 - name: Build app1 image id: build-image-app1 uses: ./actions/build-push-ecr with: app-name: app1 ecr-registry: ${{ steps.login-ecr.outputs.registry }} ecr-repository: ${{ env.RESOURCES_NAME }} image-tag: ${{ steps.package-version.outputs.current-version }}-${{ github.sha }} phones-database-url: ${{ secrets.PHONES_DATABASE_URL }} # 第二次调用:构建app2,ID为build-image-app2 - name: Build app2 image id: build-image-app2 uses: ./actions/build-push-ecr with: app-name: app2 ecr-registry: ${{ steps.login-ecr.outputs.registry }} ecr-repository: ${{ env.RESOURCES_NAME }} image-tag: ${{ steps.package-version.outputs.current-version }}-${{ github.sha }} phones-database-url: ${{ secrets.PHONES_DATABASE_URL }}
这种方式把步骤逻辑完全封装起来,复用性更强,适合跨Workflow使用。
方案三:在可复用Workflow中用矩阵策略批量执行
如果你已经有一个用on.workflow_call定义的可复用Workflow,想让调用方可以一次性触发多次步骤执行,可以用矩阵策略。
可复用Workflow文件(.github/workflows/reusable-build.yml)示例:
name: Reusable ECR Build Workflow on: workflow_call: inputs: app-names: description: 'List of application names to build (JSON array)' type: string required: true jobs: build-image: runs-on: ubuntu-latest strategy: matrix: app-name: ${{ fromJSON(inputs.app-names) }} steps: - name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Get package version id: package-version run: echo "current-version=1.0.0" >> $GITHUB_OUTPUT - name: Build, tag, and push image to Amazon ECR id: build-image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} ECR_REPOSITORY: ${{ env.RESOURCES_NAME }} IMAGE_TAG: ${{ steps.package-version.outputs.current-version }}-${{ github.sha }} DOCKERFILE_PATH: ./docker/Dockerfile.${{ matrix.app-name }}-cloud PHONES_DATABASE_URL: ${{ secrets.PHONES_DATABASE_URL }} run: | docker build --build-arg PHONES_DATABASE_URL=$PHONES_DATABASE_URL -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -f $DOCKERFILE_PATH . docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
调用这个可复用Workflow时,传入多个app名称:
name: Main Workflow on: [push] jobs: build-all-apps: uses: ./.github/workflows/reusable-build.yml with: app-names: '["app1", "app2"]' secrets: inherit
矩阵策略会自动为每个app名称创建一个作业实例,每个实例里的步骤ID都是build-image,但因为属于不同的矩阵实例,不会产生冲突,完美实现了逻辑复用。
备注:内容来源于stack exchange,提问作者Tal Rofe

