在Monorepo中使用许多软件包构建条件云

时间:2019-11-07 19:26:55

标签: kubernetes google-cloud-platform build-automation google-cloud-build monorepo

动机

我想借助Google Cloud BuildGoogle Kubernetes Engine完全自动化许多服务的部署。这些服务位于 monorepo 内部,该文件夹具有一个名为services的文件夹。

因此,我为每个服务创建了一个cloudbuild.yaml并创建了一个构建触发器。 cloudbuild.yaml可以:

  1. 运行测试
  2. 构建新版本的Docker映像
  3. 推送新的Docker映像
  4. 将更改应用于Kubernetes集群

问题

随着服务数量的增加,构建触发器的数量也随之增加。即使它们没有更改,也构建了越来越多的服务。

因此,我需要一种机制,该机制只有一个生成触发器,并自动确定需要重建的服务。

示例

假设我有一个具有此文件结构的monorepo:

├── packages
│   ├── enums
│   ├── components
└── services
    ├── backend
    ├── frontend
    ├── admin-dashboard

然后,我在frontend服务中进行一些更改。由于frontendadmin-dashboard服务取决于components包,因此需要重新构建多个服务:

  • 前端
  • 管理仪表板

但是不是后端!

我尝试过的

(1)多个构建触发器

每个服务设置多个构建触发器。但是这些构建中的80%是冗余的,因为代码中的大多数更改仅与单个服务有关。管理许多看起来几乎相同的构建触发器也变得越来越复杂。单个cloudbuild.yaml文件如下所示:

steps:
  - name: "gcr.io/cloud-builders/docker"
    args:
      [
        "build",
        "-f",
        "./services/frontend/prod.Dockerfile",
        "-t",
        "gcr.io/$PROJECT_ID/frontend:$REVISION_ID",
        "-t",
        "gcr.io/$PROJECT_ID/frontend:latest",
        ".",
      ]
  - name: "gcr.io/cloud-builders/docker"
    args: ["push", "gcr.io/$PROJECT_ID/frontend"]

  - name: "gcr.io/cloud-builders/kubectl"
    args: ["apply", "-f", "kubernetes/gcp/frontend.yaml"]
    env:
      - "CLOUDSDK_COMPUTE_ZONE=europe-west3-a"
      - "CLOUDSDK_CONTAINER_CLUSTER=cents-ideas"

(2)遍历cloudbuild文件

This问题是关于一个非常相似的问题。因此,我尝试在项目的根目录中建立一个“入口” cloudbuild.yaml文件,并遍历所有服务:

steps:
- name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: 'bash'
  args:
  - '-c'
  - |
    for d in ./services/*/; do
      config="${d}cloudbuild.yaml"
      if [[ ! -f "${config}" ]]; then
        continue
      fi

      echo "Building $d ... "
      (
        gcloud builds submit $d --config=${config}
      ) &
    done
    wait

这将消除对多个构建触发器的需求。但是我也遇到了这种方法的问题:

每个服务都会发送到具有此特定服务文件范围的自己的构建过程中。这意味着,在构建期间,我只能访问/services/specific-service中的文件。这对我来说真是太可惜了(我需要访问父目录中的文件,例如packages和根目录中的配置文件)。

(3)仅构建更改的服务

由于我想要一种仅构建更改的服务的机制,因此我尝试确定需要重建的服务。在lerna的帮助下,这样做似乎很容易。正在运行

lerna changed --all --parseable

将返回列表文件路径,指向更改后的软件包,如下所示:

/home/username/Desktop/project/packages/components
/home/username/Desktop/project/services/frontend
/home/username/Desktop/project/services/admin-dashboard

但是,该列表还包含packages,我不知道如何在脚本中使用此列表来循环访问受影响的服务。另外:当我触发构建时(例如,通过标记提交),lerna将无法在构建过程中识别出已更改的软件包,因为更改已被提交。


我知道这很长。但是我认为这是一个重要的话题,因此我非常感谢您的帮助!

P.S。:This是实际项目的外观,如果您想仔细查看特定的用例。

1 个答案:

答案 0 :(得分:1)

要从 monorepo 进行构建,您真的想逐步进行构建(更改内容以及依赖于更改零件的零件)。为此,您的构建工具需要以某种方式处理依赖关系图。

您描述的

Lerna是为monorepos设计的。但是Bazel也是如此,它是Google Cloud Builder中的一个选项,cloud-builders/bazel包含与docker builder结合使用的文档。

但是,为monorepos设计的构建工具通常设置起来更复杂。