Bazel - 在 Monorepo 中构建、推送、部署 Docker 容器到 Kubernetes



我有一个带有一些后端(Node.js)和前端(Angular)服务的monorepo。目前我的部署过程如下所示:

  1. 检查测试是否通过
  2. 为我的服务构建 docker 映像
  3. 将 docker 映像推送到容器注册表
  4. 使用 kubectl 将更改应用于 Kubernetes 集群 (GKE)

我的目标是在Bazel和Cloud Build的帮助下自动化所有这些步骤。但我真的很难开始使用 Bazel:

要使其正常工作,我可能需要添加一个包含外部依赖项的WORKSPACE文件,并为我自己的包/服务添加多个BUILD文件?我需要实际实施方面的帮助:

  1. 如何使用 Bazel 构建我的 Dockerfiles?
  2. 如何将这些映像推送到注册表(最好是 GCR)中?
  3. 如何自动将更改应用于Google Kubernetes Engine?
  4. 如何将此工具链与Google Cloud Build集成?

有关该项目的更多信息

我整理了一个很小的样本 monorepo 来展示我的用例

结构

├── kubernetes
├── packages
│   ├── enums
│   ├── utils
└── services
├── gateway

常规

  • Gateway服务取决于enumsutils
  • 一切都是用打字稿写的
  • 每个服务/包都是一个节点模块
  • gateway文件夹中有一个Dockerfile,我想构建它
  • Kubernetes 配置位于kubernetes文件夹中。
  • 请注意,我不想发布任何npm包!

我们想要的是一个可移植的Docker容器,它包含我们的Angular应用程序及其服务器以及它所需的任何机器映像,我们可以在任何云提供商上启动它,我们将创建一个完整的管道来增量。 "码头工人规则"很快。从本质上讲,它通过添加新的 Docker 层来提供工具性,因此您对应用程序所做的更改是唯一通过网络发送到云主机的内容。此外,由于 Docker 映像使用 SHA 标记,因此我们仅重新部署已更改的映像。为了管理我们的生产部署,我们将使用 Kubernetes,其中 Bazel 规则也存在。据我所知,使用 Bazel 从 Dockerfile 构建 docker 镜像是不可能的,因为 由于 Dockerfile 的非密封性质,这是设计不允许的。(资料来源: 使用 Bazel 构建确定性的 Docker 镜像)

作为源代码的一部分所做的更改将部署在 Kubernetes 集群中,这是使用 Bazel 实现以下目标的一种方法。

  1. 我们必须将 Bazel 置于监视模式,部署替换告诉 Kubernetes 集群更新应用程序的已部署版本。 一个。

    命令 : ibazel run :d eploy.replace

  2. 如果有任何源代码更改,请以角度进行。

  3. Bazel 仅以增量方式重新构建依赖于更改文件的构建图部分,在本例中,这包括已更改的ng_module、包含该模块的 Angular 应用程序以及保存服务器的 Docker nodejs_image。正如我们要求更新部署一样,在构建完成后,它将新的 Docker 容器推送到 Google Container Registry,Kubernetes Engine 实例开始为其提供服务。Bazel 理解构建图,它只重建更改的内容。

这里有一些代码段级别的提示,它们实际上可以提供帮助。

工作区文件:

创建一个 Bazel 工作区文件,WORKSPACE 文件告诉 Bazel 这个目录是一个"工作区",就像一个项目根目录。下面列出了在 Bazel 工作区中要做的事情。 • 工作区的名称应与我们发布的 npm 包匹配,以便在引用已发布的包时这些导入也有意义。 • 使用"http_archive"提及 Bazel 工作区中的所有规则,因为我们使用的是角度和节点,因此应该提及 rxjs、角度、angular_material、io_bazel_rules_sass、角度版本、build_bazel_rules_typescript、build_bazel_rules_nodejs 的规则。 • -接下来,我们必须使用"加载"加载依赖项。 sass_repositories, ts_setup_workspace,angular_material_setup_workspace,ng_setup_workspace, • 也加载 docker 基础映像,在我们的例子中是它的"@io_bazel_rules_docker//nodejs:image.bzl", • 不要忘记提及浏览器和 Web 测试存储库 web_test_repositories() browser_repositories( 铬 = 真, 火狐 = 真, )

"BUILD.bazel"文件。

•加载ng_module下载的模块,项目模块等。 • 使用"default_visibility"设置默认可见性 •如果您有任何茉莉花测试,请使用ts_config并提及其中的缺点。• ng_module(此处应提及资产、来源和属性) • 如果您有任何延迟加载脚本,请将其作为捆绑包的一部分提及 • 在web_package中提及根目录。 •最后提及数据和欢迎页面/默认页面。

示例片段:

load("@angular//:index.bzl", "ng_module")
ng_module(
name = "src",
srcs = glob(["*.ts"]),
tsconfig = ":tsconfig.json",
deps = ["//src/hello-world"],
)
load("@build_bazel_rules_nodejs//:future.bzl", "rollup_bundle")
rollup_bundle(
name = "bundle",
deps = [":src"]
entry_point = "angular_bazel_example/src/main.js"
)

使用以下命令构建捆绑包。

bazel build :bundle

管道:通过 Jenkins

通过 Jenkins 创建管道并运行管道有几个阶段。每个阶段执行单独的任务,但在我们的例子中,我们使用阶段使用 BaZel 运行发布图像。

pipeline {
agent any
stages {
stage('Publish image') {
steps {
sh 'bazel run //src/server:push'
}
}
}
}

注意:

bazel run :dev.apply
  1. Dev Apply maps to kubectl apply,这将创建或替换现有配置。有关更多信息,请参阅 kubectl 文档。这将应用已解析的模板,其中包括重新发布映像。此操作旨在成为快速迭代开发(重新生成/重新发布/重新部署)的主力。

  2. 如果要使用 workpsace 文件拉取容器,请使用以下标记

    container_pull( 名称 = "debian_base", 摘要 = "SHA256:**", 注册表 ="gcr.io", 存储库 = "google-appengine/debian9", )

如果使用GKE,则需要安装gcloud sdk,并且由于我们使用GKE(Google Contianer Enginer),因此可以使用以下方法进行身份验证。

gcloud container clusters get-credentials <CLUSTER NAME>

部署mnet 对象应按以下格式提及:

load("@io_bazel_rules_k8s//k8s:object.bzl", "k8s_object")

k8s_object(
name = "dev",
kind = "deployment",
template = ":deployment.yaml",
images = {
"gcr.io/rules_k8s/server:dev": "//server:image"
},
)

来源:

  • https://docs.bazel.build/versions/0.19.1/be/workspace.html
  • https://github.com/thelgevold/angular-bazel-example
  • https://medium.com/@Jakeherringbone/deploying-an-angular-app-to-kubernetes-using-bazel-preview-91432b8690b5
  • https://github.com/bazelbuild/rules_docker
  • https://github.com/GoogleCloudPlatform/gke-bazel-demo
  • https://github.com/bazelbuild/rules_k8s#update
  • https://codefresh.io/howtos/local-k8s-draft-skaffold-garden/
  • https://github.com/bazelbuild/rules_k8s

几个月后,我在整个过程中走得比较远。 在这里发布每个细节都太多了!

所以这里是开源项目,它实现了大部分要求:https://github.com/flolu/fullstack-bazel

如有具体问题,请随时与我联系! :)

祝你好运

Flo,您是否考虑过使用terraform和makefile来自动构建集群?

在我最近的项目中,我用make和terraform端到端地自动化了基础设施。从本质上讲,这种方法在 3 到 5 分钟内使用一个命令构建整个集群、构建和部署整个项目。取决于 gcp 在给定日期的速度。

有一个谷歌示例项目显示了这个想法,尽管 terraform 配置已经过时,需要替换为遵循当前 0.13/0/14 语法的配置。

https://github.com/GoogleCloudPlatform/gke-bazel-demo#build--deploy-with-bazel

启用单命令端到端自动化的生成文件:

https://github.com/GoogleCloudPlatform/gke-bazel-demo/blob/master/Makefile

同样,替换或自定义项目的脚本;我实际上又写了两个脚本,一个用于检查/安装客户端上的要求,即git/kubctl和gcloud,另一个用于检查或配置和身份验证gcloud,以防尚未配置和身份验证。从那里,terraform 脚本接管并构建整个集群,一旦完成,通常的自动部署就会开始。

我发现分层制作在terraform和bazel上进行端到端自动化的想法非常出色。

最新更新