【问题标题】:Conditional Cloud Builds with Many Packages in a MonorepoMonorepo 中包含许多包的条件云构建
【发布时间】:2020-03-04 10:37:28
【问题描述】:

动机

我想在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 是我的实际项目的样子,如果你想仔细看看具体的用例的话。

【问题讨论】:

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


    【解决方案1】:

    要从 monorepo 构建,您确实希望增量构建(更改的内容和依赖于更改部分的部分)。为此,您的构建工具需要以某种方式处理依赖关系图。

    您描述的 Lerna 是为 monorepos 设计的。但Bazel 也是如此,它在 Google Cloud Builder 中作为一个选项提供,cloud-builders/bazel 带有与 docker builder 结合使用的文档。

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

    【讨论】:

    猜你喜欢
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 2019-04-20
    • 2020-07-10
    • 1970-01-01
    相关资源
    最近更新 更多