Setting up EKS with Bazel, Jsonnet and Terraform

Overview In this document, I’ll describe my solution from the following parts: Part1 Architecture: describe the desired state of the architecture Part2 Implementation: Code Structure Introduce How to Build it Deploy Nginx Controller using Helm Part1: Architecture We assume that the project has a project named: health. Here’s the architecture graph, which draw by Excalidraw Network Architecture I created 4 subnets that are evenly distributed to 2 Availability Zones. Each availability zone has 2 subnets, one is public subnet,and another one is private subnet. The public subnet goes out through the Internet gateway and the private subnet goes out through the NAT gateway. ...

2024-01-20 · 7 min · 1300 words · 翟志军 Jack Zhai

Bazel使用案例:构建Springboot工程

本文是关于如何使用Bazel搭建Springboot 3.1.0工程(基于JDK17)。为什么使用Bazel,而不是使用Maven或者Gradle?可以看我之前关于Bazel的介绍文章。 前期准备 在根目录加入.bazelversion文件,并加入6.2.0,指定当前工程使用的Bazel的版本。这样,Bazel命令自动使用该版本的Bazel进行构建。 在根目录加入.bazelrc文件,并指定构建和测试时使用JDK17,内容如下: build --java_language_version=17 --java_runtime_version=17 --tool_java_language_version=17 --tool_java_runtime_version=17 test --java_language_version=17 --java_runtime_version=17 --tool_java_language_version=17 --tool_java_runtime_version=17 外部依赖准备 在根目录中创建以下两个文件: WORKSPACE:在Bazel中,所有的外部依赖统一定义WORKSPACE文件中; BUILD.bazel:内容留空即可,用于告诉Bazel当前目录也是一个Package。 Bazel本身是支持多语言的。所以,我们需要特定语言的rule来帮助我们在WORKSPACE中定义外部依赖。 对于Java工程,我们使用rules_jvm_external进行外部依赖的管理。它的使用步骤如下: 步骤1:在WORKSPACE中增加rules_jvm_external配置 以下配置指定了rules_jvm_external的下载位置,并进行rule的初始化: load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") RULES_JVM_EXTERNAL_TAG = "4.5" RULES_JVM_EXTERNAL_SHA = "<sha hash value>" http_archive( name = "rules_jvm_external", strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG, sha256 = RULES_JVM_EXTERNAL_SHA, url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG, ) load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps") rules_jvm_external_deps() load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup") rules_jvm_external_setup() load("@rules_jvm_external//:defs.bzl", "maven_install") maven_install( artifacts = [ # The project's dependencies "junit:junit:4.12", "org.hamcrest:hamcrest-library:1.3", ], repositories = [ # Private repositories are supported through HTTP Basic auth # "http://username:password@localhost:8081/artifactory/my-repository", "https://maven.aliyun.com/repository/public", ], ) 以上采用了非Bzlmod的管理rule。 ...

2024-01-19 · 3 min · 461 words · 翟志军 Jack Zhai

Bazel作为构建工具之王,将会颠覆你对CI的认知

说到构建工具,不同语言技术栈的人,想起的构建工具不同。 Java程序员想到的是Maven,前端程序员想的是NPM或者Webpack、Android程序员想到的是Gradle、Rust程序想到的是Cargo、C++程序员想到的是Make等等。 然而这些工具在Bazel面前,层次有些低。所以,我愿称Bazel是构建工具之王。 P.S. Android平台的构建,2020年已经开始了迁移到Bazel的工作。 具体地址:https://blog.bazel.build/2020/11/12/aosp_migrating_to_bazel.html Bazel介绍 Bazel是Google在2015年开源的一款构建工具。 目前使用Bazel的知名公司有:Esty、Canva、Databricks、Dropbox、Huawei、Line、LinkedIn、Stripe、Twitter、Tinder、Uber、VMware、Wix等。具体可以看:https://bazel.build/community/users 。 其中Twitter是从自家的Pants迁移到的Bazel的,具体迁移过程介绍:https://opensourcelive.withgoogle.com/events/bazelcon2020/watch?talk=day1-talk2 Facebook使用的是其自研的Buck2,但是,其与Bazel使用的是相同的远程执行的API。 除了公司,某些著名的开源软件也使用Bazel构建,包括自动化测试领域的Selenium,AI领域的TensorFlow,容器编排领域的Kubernetes等。具体还有:https://bazel.build/community/users#open-source-projects-using-Bazel 相对于其它构建工具,它的显著的特点有: 支持多语言; 支持远程分布式构建; 支持增量构建; 支持强大的密闭性; 支持构建缓存; 支持并行构建。 假设存在一个复杂的软件工程 假设存在一个软件工程中,它包含5部分:Web前端、Android端、Java后端、Go后端、嵌入式端。 作为Java后端的程序员,他们修改了一个API。但是他作为个人,他无法预知到底发生了哪些影响。 所以,他把这个问题交给了持续集成(CI),让它去发现集成问题。 在过去很长一段时间里,行业里只有一种CI模式,我称之为传统的CI模式。 殊不知,还有另一种模式。 传统的CI模式 目前行业里比较传统的CI架构,通常如下: 在这样的架构下,实现CI的步骤如下: 开发人员提交代码; Gitlab检测到开发人员提交代码,然后触发Jenkins controller执行; Jenkins controller根据该代码仓库预先设计的pipeline执行; Jenkins controller根据pipeline中的任务所需要的构建环境,将任务分配给不同的Jenkins agent; 在agent构建完成后,将制品release到制品仓库中。 如果开发者希望验证自己写的代码,就必须将代码commit到Gitlab中。因为整个验证环境被定义在CI环境的Pipeline中。而且这个过程,越大的工程,集成速度越慢。开发者也无法在本地进行全量验证。 作为Pipeline的维护者,他需要清楚知道哪些任务是可以并行执行的,并手工配置并行,这样才能加快构建速度。比如前端构建和后端构建可以并行进行。 也就是说在传统的CI模式下,开发者的效率会随着软件的规模越大而降低。换句话,这样的模式,开发效率无法scale。 案例 希望以下案例可以给你一个感性的认知。下图是Google在2010年到2015年的周commit数量。绿线代表commit总数,黄线是人数。我们取离我们最近的2015年的数据来讨论。2015年的代码量如下: 在这个代码量下,每周能达到300左右的commit。如下图: 根据持续集成的原则,每一个commit都必须构建通过。20亿行代码一次全量构建需要多久? 我们以一个开源项目作参考。apitable是一个开源的数据表格项目,它有200万左右的代码,全量构建一次需要20分钟左右。那么,根据不准确的类推,20亿行代码,全量构建一次需要:20/2,000,000 * 2000,000,000=200,000,000分钟,也就是13天左右。 在传统的CI模式下,是尽量避免执行全量构建这样庞大的代码量的。所以,传统CI模式下,通常是多仓库模式管理代码。 那么Bazel呢?Bazel如果真要构建这样庞大的代码量,估计也够呛。但是由于Bazel天然支持并行构建、构建缓存和增量构建,所以,Bazel通常不会遇到真正意义的全量构建的情况。 为什么其它公司不使用Bazel 也许有人会问:为什么阿里2018年新增的代码行(https://zhuanlan.zhihu.com/p/54435171)就有12亿,不也没有使用Bazel吗? 这个是一个好问题。 但是,无法简单的回答这个问题,而是需要深入到各自组织内部才能分析清楚。个人觉得可以从以下维度分析: 在代码仓库上工作的人员的规模:同样的代码量,不同的组织需要不同数量的人维护; 代码管理方式:阿里使用多仓库的管理办法,不需要统一的版本号; 持续集成的程度不同:阿里可能不需要对每一个commit跑一次全量。 为什么Bazel会颠覆你对CI的认知 Bazel是如何解决传统CI模式下开发效率无法scale的问题呢?其主要通过它的六个特性来解决。 首先,Bazel支持远程分布式构建。 在一个使用Bazel构建的仓库中,开发者写好代码后,不用commit代码到Git仓库,只要在本地命令行执行bazel run --remote_executor=grpc://localhost:8980 //... ,代码仓库中所有构建和测试任务都将运行在远程执行服务器。远程执行服务器越多,构建速度越快。 这一特性可以明显地提高开发者本地的开发效率。因为开发者在本地就可以执行全量构建和全量测试。 传统CI模式下,无法提升开发者本地的开发效率。 第二,Bazel支持增量构建和增量测试(精准测试)。 开发者在本地执行build命令时,Bazel检测出修改了a.java文件,所以,Bazel只将构建a.java的任务及其相关的构建任务给远程执行服务器执行。这就是增量构建。 如果开发者执行test命令,Bazel则能检测出被影响的测试,然后只运行这些测试。其实这就是精准测试了。在Bazel中,精准测试实现起来并不难。 传统CI模式下,它是不关心增量构建和增量测试的。所以,每次运行都是全量。这是一种极大的浪费。 ...

2023-11-20 · 1 min · 108 words · 翟志军 Jack Zhai

基于Bazel + SQLFluff实现SQL lint

背景 SQL进行版本化控制后,我们希望为SQL加入lint步骤。这样做的好处是我们可以在真正执行SQL前发现问题。 本文中,我们通过Bazel执行SQLFluff以实现SQL的lint。 SQLFluff是一款使用Python语言使用的,支持SQL多方言的SQL lint工具。 它的特点是: 支持多方言。如:Snowflake、PostgreSQL、ClickHouse。所有支持的方言列表:https://docs.sqlfluff.com/en/stable/dialects.html; 可以输出正确的SQL,减少了我们手工修正SQL的工作; 同时支持命令行方式使用和API调用方式。 集成到CI/CD流水线中 在我看来,在CICD流水线中实现SQL lint有两种方式: 方式一:在流水线中增加一个SQL lint步骤; 方式二:将SQL lint的逻辑写在测试代码,执行测试步骤,就自动执行了SQL lint。 方式二是我最爱,我会在本文最后讲原因。 工程结构 . ├── BUILD.bazel ├── WORKSPACE ├── repository-hibernate-impl │ ├── BUILD.bazel │ └── src │ ├── main │ │ └── sql │ │ └── V1__runbook_table.sql │ └── test │ └── python │ ├── BUILD.bazel │ ├── requirements_lock.txt │ └── sql_test.py 步骤1: 在WORKSPACE中增加Python外部依赖 本文中我们使用的是Bazel 5.4.0,所以还在使用WORKSPACE定义外部依赖 http_archive( name = "rules_python", sha256 = "a644da969b6824cc87f8fe7b18101a8a6c57da5db39caa6566ec6109f37d2141", strip_prefix = "rules_python-0.20.0", url = "https://github.com/bazelbuild/rules_python/releases/download/0.20.0/rules_python-0.20.0.tar.gz", ) load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories() load("@rules_python//python:repositories.bzl", "python_register_toolchains") python_register_toolchains( name = "python3_11", python_version = "3.11", ) load("@python3_11//:defs.bzl", interpreter_3_11 = "interpreter") load("@rules_python//python:pip.bzl", "pip_parse") # Create a central repo that knows about the dependencies needed from # requirements_lock.txt. pip_parse( name = "pip_deps", python_interpreter_target = interpreter_3_11, requirements_lock = "//repository-hibernate-impl/src/test/python:requirements_lock.txt", ) # Load the starlark macro which will define your dependencies. load("@pip_deps//:requirements.bzl", "install_deps") # Call it to define repos for your requirements. install_deps() 步骤2: 定义SQLFluff依赖 requirements_lock.txt的内容如下: ...

2023-04-17 · 2 min · 315 words · 翟志军 Jack Zhai