如何配置GitHub Actions仅构建修改的微服务并管理版本?
问题与解决方案:微服务镜像构建优化与版本管理
背景
我有一个将不同微服务托管在独立文件夹中的单体应用,目录结构示例:
/project/service1 /project/service2
已为每个服务创建独立AWS ECR仓库,编写了GitHub Actions代码,在GitHub创建Release时构建每个服务的Docker镜像并推送到对应ECR仓库。每个服务有独立的GitHub Actions代码,将GitHub Release版本号作为ECR镜像的版本标签。
问题
- 不想每次创建Release时都构建推送所有服务镜像,只想构建推送有修改的服务(文件夹),该如何实现?采用什么方案?
- 由于不再为每个服务都构建镜像,各服务会有不同版本,无法再使用Release中输入的版本号,该如何管理版本?
项目语言:NodeJS
单个服务的GitHub Actions YAML示例
name: Deploy core to Amazon ECS on: release: types: ["published"] env: AWS_REGION: eu-central-1 ECR_REPOSITORY: lake-core CONTAINER_NAME: core permissions: contents: read jobs: deploy: name: Deploy runs-on: ubuntu-latest environment: production steps: - name: Checkout uses: actions/checkout@v3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ env.AWS_REGION }} - name: Login to Amazon ECR id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Build, tag, and push image to Amazon ECR id: build-image env: ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} IMAGE_TAG: ${{ github.ref_name }} WORKSPACE: ${{ github.workspace }} run: | cd core cp -r ../shared/ ./shared sed 's/\.\.\/shared/\.\/shared/g' package.json > package-tmp.json docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -t $ECR_REGISTRY/$ECR_REPOSITORY:latest . docker push $ECR_REGISTRY/$ECR_REPOSITORY --all-tags rm -r ./shared rm package-tmp.json echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
解决方案
针对问题1:只构建推送有修改的服务
可以通过以下步骤实现:
合并为单份统一工作流
取消每个服务的独立工作流,在项目根目录创建deploy-services.yml,统一管理所有服务的构建逻辑。检测代码目录变化
拉取完整代码历史后,用路径过滤工具检测哪些服务目录或共享目录有修改:- name: Checkout full code history uses: actions/checkout@v3 with: fetch-depth: 0 - name: Detect changed services id: changes uses: dorny/paths-filter@v2 with: filters: | service1: - 'service1/**' service2: - 'service2/**' shared: - 'shared/**' # 共享代码修改时,所有依赖的服务都需要重新构建动态触发对应服务的构建
为每个服务定义单独的作业,通过条件判断决定是否执行:jobs: build-service1: if: steps.changes.outputs.service1 == 'true' || steps.changes.outputs.shared == 'true' runs-on: ubuntu-latest environment: production steps: # 复用原有的AWS配置、ECR登录、镜像构建推送逻辑,替换为service1对应的ECR仓库名等变量 build-service2: if: steps.changes.outputs.service2 == 'true' || steps.changes.outputs.shared == 'true' runs-on: ubuntu-latest environment: production steps: # service2对应的构建推送步骤
针对问题2:多服务版本管理方案
可以采用以下两种可行方式:
方式1:服务独立版本号
- 在每个服务目录的
package.json中维护独立的version字段,作为该服务的版本标识。 - 构建时读取该版本号作为镜像标签:
IMAGE_TAG=$(jq -r '.version' service1/package.json) - 发布Release时,自动更新所有有修改的服务的
package.json版本号(比如用npm version patch/minor/major命令),并提交到仓库。
方式2:复合版本号
- 保留GitHub Release的主版本号,附加服务专属标识,格式如
v1.0.0-service1-1,其中v1.0.0是Release版本,service1-1是该服务的修订次数。 - 或者用服务目录的最新提交哈希作为标签补充:
v1.0.0-abc123,其中abc123是服务目录的提交哈希,既关联Release版本,又能区分服务的具体修改。
额外建议:维护版本清单
在项目根目录创建versions.json文件,记录每个服务的当前镜像版本,每次构建后自动更新并提交:
{ "service1": "v1.2.0", "service2": "v1.1.3" }
方便统一查看所有服务的版本状态。
内容的提问来源于stack exchange,提问作者Gravis
相关产品推荐
相关产品推荐

