Skip to main content

· 阅读需要 1 分钟

Jsonnet 是什么

Jsonnet 是一种域特定语言(Domain Specific Language, DSL),设计用于简化 JSON 数据的创建、管理和维护。它最初由 Google 的员工 Dave Cunningham 在大约 10 年前作为 20% 项目设计并开发,其设计受到 Google 内部几种配置语言的影响,初衷是为了提高配置文件的可读性、可维护性和可编程性,同时保持与 JSON 的兼容性。Jsonnet 通过引入变量、函数、条件语句、循环以及代码注释等功能,使得编写复杂的数据结构变得更加容易和直观。

Jsonnet 代码目前仍归属 Google 所有,就在上月,因为 Jsonnet 的创始人 Dave Cunningham 离开 Google 从事新的事业,目前交由谷歌内部的 Rohit Jangid 负责继续管理项目。

KCL 是什么

KCL 是一个开源的基于约束的记录及函数语言,作为沙盒项目托管在 CNCF 基金会。KCL 通过成熟的编程语言技术和实践来改进对大量繁杂配置比如云原生 Kubernetes 配置场景的编写,致力于构建围绕配置的更好的模块化、扩展性和稳定性,更简单的逻辑编写,以及更简单的自动化和生态工具集成。

Jsonnet 和 KCL 的区别

设计理念

Jsonnet 致力于提升配置文件的可读性和简洁性。通过引入编程语言特性,如变量、函数、运算符和控制结构,Jsonnet 允许用户以更接近自然语言的方式编写配置,从而降低了复杂配置的管理难度,Jsonnet 保证了与 JSON 的完全兼容性。这意味着 Jsonnet 文件可以被编译成标准的 JSON 输出,无需更改即可被现有的 JSON 处理工具和系统识别和处理。但是, Jsonnet 并没有将类型和验证等特性对配置和策略领域也比较重要的特性纳入其考虑范围内,在稳定性和工程效率上的考量有所缺失。

在设计层面,KCL 更加 “通用” 和 “现代”,这不仅体现在语言设计元素上,还体现在具体的语言特性上。此外,KCL 不仅仅定位于是一个简化 JSON/YAML 数据的创建、管理和维护的工具,更聚焦在云原生领域中的具体场景问题比如复杂性和安全风险等问题,对于非领域内的问题尽可能收敛语言自身的设计。在满足功能以及开发者使用简单的基础上,尽可能参考一些使用起来比较简单的语言如 Python, Go 等语法语义风格,排除非预期的特性和副作用,比如从语言技术和 GitOps 结合两个方面加强对稳定性和一致性的保证,通过语言的自动化 API 来提升效率,通过强不可变性、冲突监测保证配置的确定性,通过代码复用和抽象结合默认值填充的方式屏蔽用户侧细节感知,通过自定义的校验表达式支持对配置数据的业务校验等,通过与更多的云原生工具或者项目集成比如 Crossplane, Helm, Kustomize 和 KPT 等项目来完成更多的场景功能支持。

语言特性

综合来看,KCL 和 Jsonnet 都支持变量定义、引用、函数定义,配置合并等功能,但支持程度和语法语义有差异;基本都支持支持常用的算术、逻辑、循环推导式、条件、函数、标准库和导入第三方模块等编程语言特性,支持方式及语法也各不相同,但都有从通用编程语言借鉴吸收。另外,Jsonnet 没有类型定义支持,它的值在运行时可变,可能会导致潜在的拼写错误,这带来了一定的风险,KCL 支持用户自定义类型、面向对象的特性上部分支持或混合支持、不可变性等特性在工程层面保证稳定性;在数据文件集成方面,KCL 和 Jsonnet 都可以直接导入 JSON/YAML 数据类型和 Kubernetes CRD 等类型定义。

此外,KCL 还在配置操作 Patch, 数据验证和安全合规层面内置了许多语言特性满足配置的场景需求,比如支持配置的自动合并特性以及字段范围,类型,正则表达式等检查特性,可以使得 KCL 提供更多的静态分析能力满足 IDE 或者其他工具链需要并或者组合约束检查的能力,且开发者友好,可以使用更丰富的 IDE 功能提升开发效率。

开发者工具

在开发者工具方面,Jsonnet 和 KCL 社区都提供了非常多的语言工具包括测试,格式化和包管理工具等支持。

由于 Jsonnet 的动态特性,IDE 支持很难做的十分全面,虽然 Grafana 社区做了很多努力,但是目前仍然只能提供基本的高亮,跳转,诊断和简单的标准库补全功能,由于语言本身缺乏了静态类型的相关特性,诸如一些高级的补全、重构和自动化分析等高级功能无法很好的完成。

KCL 提供了官方的 Language Server 支持,因此可以比较容易扩展集成到除 VS Code 的 IDE 插件支持包括 NeoVim 以及一些其他新兴的支持 LSP 的 IDE 或者编辑器。并且 KCL 基于 Language Server 提供了完整的代码高亮、补全、跳转、重构、补全和快速修复等功能,且在快速发展当中。

多语言 SDK

为了将配置语言更好地集成到用户的应用中,Jsonnet 目前在社区提供了具备不同的四种多语言实现,包含 C++, Go 和 Rust 以及 Python 绑定。KCL 目前具备官方的 Rust 实现,并提供了 Go, Python, Java, Node.js, C#, C++, C 和 WASM 等多种绑定,这些所有多语言绑定均基于 Rust,不会由于不同语言的实现而带来意外的结果和不确定性。

性能

虽然 KCL 提供了更多且对开发者更友好的功能,这并不意味着 KCL 臃肿和性能差,经过测试,在代码规模较大或者计算量较高的场景情况下 KCL 比 Jsonnet 性能更好,开发体验也更佳,比如在下面的例子中 KCL 的最新版本 (开启 KCL_FAST_EVAL 模式)性能可以超过 Jsonnet 官方所有实现,与社区早期的 Rust 实现性能基本持平,而 KCL 做了更多额外的检查来保证代码类型正确。

  • KCL (test.k)
a = lambda name: str {
apiVersion = "apps/v1"
kind = "Deployment"
metadata = {
name = name
labels = {"app": "nginx"}
}
spec = {
replicas = 3
selector.matchLabels = {"app": "nginx"}
template.metadata.labels = {"app": "nginx"}
template.spec.containers = [
{
name = metadata.name
image = "${metadata.name}:1.14.2"
ports = [{ containerPort = 80 }]
}
]
}
}
temp = {"a${i}": a("nginx") for i in range(1000)}
  • Jsonnet (test.jsonnet)
local a(name) = {
apiVersion: "apps/v1",
kind: "Deployment",
metadata: {
name: name,
labels: {["app"]: "nginx"}
},
spec: {
replicas: 3,
selector: {
matchLabels: {["app"]: "nginx"}
},
template: {
metadata: {
labels: {["app"]: "nginx"}
},
spec: {
containers: [
{
name: name,
image: name + ":1.14.2",
ports: [{ containerPort: 80 }]
}
]
}
},
}
};
{
temp: {["a%d" % i]: a("nginx") for i in std.range(0, 1000)},
}

运行时间(考虑到生产环境的实际资源开销,本次测试以单核为准)

KCL v0.9.3Jsonnet v0.20.0 (C++ 版本)Jsonnet v0.20.0 (Go 版本)Jsonnet v0.5.0-pre96 (Rust 版本 jrsonnet)Jsonnet v0.1.2 (Rust 版本 rsjsonnet)
155 ms (kcl test.k)1460 ms (jsonnet test.jsonnet)400 ms (jsonnet test.jsonnet)153 ms (rsjsonnet test.jsonnet)142 ms (jrsonnet test.jsonnet)

小结

受限于篇幅,以上内容不足以描述全部的设计细节和功能对比,下面仅列出一个表格对比用于读者参考。

特性JsonnetKCL
开源协议Apache-2.0, AGPL-3.0 license 等Apache-2.0
开发语言C++, Go, Rust 等Rust
语言风格类 Json类 Python, Go
语言功能中等
运行性能中等中等
增量编译
标准库
包管理工具
格式化工具
文档工具
测试工具
调试工具✅ (简单的 ReplDebugger)
IDE 插件IntelliJ, NeoVim, VS CodeIntelliJ, NeoVim, VS Code
多语言 SDKC++, Go, Python, Rust, WASMGo, Python, Java, Node.js, C#, C++, C, WASM
多语言插件Go, Python, Java
Language Server
OCI Registry 支持
社区模型库
导出配置数据JSON, YAML, TOML, Ini 等JSON, YAML, TOML
从其他数据或 Schema 导入
Kubernetes 配置支持
云原生工具集成支持

参考

· 阅读需要 1 分钟

简介

KCL 团队很高兴地宣布 KCL v0.9.0 新版本现在已经可用!本次发布为大家带来了三方面的重点更新

  • 使用性能更好、功能更完善和错误更少的 KCL 语言、工具链和 IDE 提升代码编写体验和效率
  • 更加全面丰富的标准库、三方库以及社区生态集成,涵盖不同应用场景和需求
  • 更丰富的多语言 SDK 和插件,无缝地集成不同编程语言和开发环境

KCL 是一个 CNCF 基金会托管的基于约束的记录及函数语言,期望通过成熟的编程语言技术和实践来改进对大量繁杂配置比如云原生 Kubernetes 配置场景的编写,致力于构建围绕配置的更好的模块化、扩展性和稳定性,更简单的逻辑编写,以及更简单的自动化和生态工具集成。

❤️ 特别鸣谢

感谢 KCL 在 v0.8 - v0.9 版本迭代过去 120 天中所有 120 位社区参与者,以下排名不分先后

@Shashank Mittal, @MattHodge, @officialasishkumar, @Gmin2, @Akash Kumar, @sfshumaker, @sanzoghenzo, @MOHAMED FAWAS, @bradkwadsworth-mw, @excalq, @Daksh-10, @metacoma, @Wes McNamee, @Stéphane Este-Gracias, @octonawish-akcodes, @zong-zhe, @shashank-iitbhu, @NAVRockClimber, @AkashKumar7902, @Petrosz007, @patrycju, @Korada Vishal, @selfuryon, @tvandinther, @vtomilov, @Peefy, @taylormonacelli, @Tertium, @Stefano Borrelli, @Bishal, @kukacz, @borgius, @steeling, @jheyduk, @HStéphane Este-Gracias, @userxiaosi, @folliehiyuki, @kubernegit, @nizq, @Alexander Fuchs, @ihor-hrytskiv, @Mohamed Asif, @reedjosh, @Wck-iipi, @evensolberg, @aldoborrero@ron18219, @rodrigoalvamat, @mproffitt, @karlhepler, @shruti2522, @leon-andria, @prahaladramji, @Even Solberg, @utnim2, @warjiang, @Asish Kumar, @He1pa, @Emmanuel Alap, @d4v1d03, @Yvan da Silva, @Abhishek, @DavidChevallier, @zargor, @Kim Sondrup, @SamirMarin, @Hai Wu, @MatisseB, @beholdenkey, @nestoralonso, @HAkash Kumar, @olinux, @liangyuanpeng, @ngergs, @Penguin, @ealap, @markphillips100, @Henri Williams, @eshepelyuk, @CC007, @mintu, @M Slane, @zhuxw, @atelsier, @aleeriz, @LinYunling, @YvanDaSilva, @chai2010, @Sergey Ryabin, @vfarcic, @vemoo, @riven-blade, @ibishal, @empath-nirvana, @bozaro, @jgascon-nx, @reckless-huang, @Sergei Iakovlev, @Blarc, @JeevaRamanathan, @dennybaa, @PrettySolution, @east4ming, @nkabir, @sestegra, @XiaoK29, @ricochet1k, @yjsnly, @umaher, @SjuulJanssen, @wilsonwang371, @Lukáš Kubín, @samuel-deal-tisseo, @blakebarnett, @Uladzislau Maher, @ytsarev, @Vishalk91-4, @Stephen C, @Tom van Dinther, @MrGuoRanDuo, @dopesickjam

📚 重点更新内容

⚡️ 性能提升

运行性能

在 KCL v0.9 新版本中,引入了一个新的快速运行模式,可以通过设置 KCL_FAST_EVAL=1 环境变量开启,从而提升启动速度和运行时性能。

对于使用 Schema 的配置(比如 k8s 三方库),相比于之前的版本可以获得 3 倍左右的性能提升。对于简单的不使用 Schema 的配置,输出 YAML 性能经测试超过 helm templatekustomize build 等使用 YAML 和 Go Template 的工具。

IDE 性能

KCL IDE 在大型项目上针对语义分析部分进行了进一步的增量编译和性能优化,对于 400 个文件左右的 KCL 项目, IDE 端到端响应时间可以减小为之前版本的 20%

🔧 核心功能

语言

  • 字符串插值支持类似 Shell 的 \${} 转义功能取消插值
world = "world"
hello_world_0 = "hello ${world}" # hello world
hello_world_1 = "hello \${world}" # hello ${world}
  • typeof 函数新增 Schema 类型的支持用于区分 schema 类型和实例
schema Foo:
bar?: str

foo = Foo {}
type_schema = typeof(foo) # schema
type_type = typeof(Foo) # type
  • Schema 的 instances() 方法新增关键字参数 full_pkg 参数用于读取所有代码中对应 Schema 的实例
schema Person:
name: str

alice = Person {name = "Alice"}
all_persons = Person.instances(True)
  • 去除 bool 类型和 int 类型隐式比较的功能 0 < True
  • 去除 list 类型的比较功能 [0] < [1]
  • as 关键字增加类型断言失败功能
  • 优化 lambda 函数和配置代码块 {} 在不同作用域的闭包变量捕获逻辑,更符合直觉

工具链

  • kcl run 支持使用 --format toml 输出 TOML 格式的配置
  • kcl mod add 支持使用 --oci--git 添加私有三方 OCI Registry 和 Git 仓库的依赖
  • kcl import 支持从整个 Go Package 导入为 KCL Schema
  • kcl import 支持导入带 YAML Stream --- 格式的文件
  • kcl import 支持从 TOML 文件导入为 KCL 配置
  • kcl clean 支持清理外部依赖和编译缓存
  • kcl mod init 支持 --version 标签设置 KCL 新建模块的版本
  • kcl run, kcl mod addkcl mod pull 等命令支持通过本地 Git 对私有仓库进行访问

IDE

  • 支持多个 Quick Fix 修复选项
  • 支持 kcl.modkcl.mod.lock 文件的高亮
  • IDE 支持部分语法悬停高亮
  • 支持 import 对外部依赖的补全
  • 支持函数符号的高亮和 Inlay Hints 显示缺省的变量类型

inlayhint

API

  • Override API 支持设置配置覆盖时使用不同的属性运算符 :, =+=
  • Go API 支持 prototext 格式和 KCL schema 输出为 KCL 配置
  • Go API 支持任意 Go Type 和 Go Value 序列化为 KCL Schema 和配置

📦️ 标准库及三方库

标准库

  • 新增标准库 file 用于文件 IO 操作,比如从 YAML 读取配置并进行配置合并操作
import file
import yaml
import json_merge_patch as p

config = p.merge(yaml.decode(file.read("deployment.yaml")), {
metadata.name = "override_value"
})

其他更多 file 模块函数详见:https://www.kcl-lang.io/docs/reference/model/file

  • 新增标准库 template 用于模版配置编写
import template

_data = {
name = "handlebars",
v = [ { a = 1 }, { a = 2 } ],
c = { d = 5 },
g = { b = [ { aa = { bb = 55} }, { aa = { bb = 66} } ] },
people = [ "Yehuda Katz", "Alan Johnson", "Charles Jolley" ]
}

content = template.execute("""\
Hello world from {{name}}

{{#each v}}
{{this.a}}
{{/each}}
{{ c.d }}
{{#each people}}
{{ this }}
{{/each}}
{{#each g.b}}
{{this.aa.bb}}
{{/each}}
""", _data)
  • 新增标准库 runtime 可以用于捕获运行时异常,并用于 kcl test 工具测试异常用例
import runtime

schema Person:
name: str
age: int

check:
0 <= age <= 120, "age must be in [1, 120], got ${age}"

test_person_check_error = lambda {
assert runtime.catch(lambda {
p = Person {name = "Alice", age: -1}
}) == "age must be in [1, 120], got -1"
}

三方库

KCL 模型数量新增至 313 个, 主要包含如下更新:

  • k8s 发布 1.30 版本
  • argo-cd 发布 0.1.1 版本
  • argo-workflow 0.0.3 版本
  • istio 发布 1.21.2 版本
  • victoria-metrics-operator 发布 0.45.1 版本
  • cert-manager 发布 0.1.2 版本
  • cilium 发布 0.1.1 版本
  • Longhorn 发布 0.0.1 版本
  • jsonpatch 发布 0.0.5 版本,支持 rfc6901Decode
  • 新增 difflib 三方库,支持比较配置差异
  • 新增 argo-cd-order 用于排序 argocd 同步操作的资源顺序
  • 新增 cluster-api 相关的模型库:包括 cluster-api, cluster-api-provider-metal3, cluster-api-provider-gcp, cluster-api-addon-provider-helm, cluster-api-addon-provider-aws, cluster-api-provider-azure

☸️ 生态集成

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: example
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1beta1
kind: XR
mode: Pipeline
pipeline:
- step: basic
functionRef:
name: function-kcl
input:
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLInput
source: |
# Read the XR
oxr = option("params").oxr
# Patch the XR with the status field
dxr = oxr | {
status.dummy = "cool-status"
}
# Construct a AWS bucket
bucket = {
apiVersion = "s3.aws.upbound.io/v1beta1"
kind = "Bucket"
metadata.annotations: {
"krm.kcl.dev/composition-resource-name" = "bucket"
}
spec.forProvider.region = option("oxr").spec.region
}
# Return the bucket and patched XR
items = [bucket, dxr]
- step: automatically-detect-ready-composed-resources
functionRef:
name: function-auto-ready

此外,可以在这里找到更多的关于 KCL 和其他生态项目一起使用的真实用例

🧩 多语言 SDK 和插件

多语言 SDK

KCL 多语言 SDK 新增至 7 个, 目前主要支持 Rust, Go, Java, .NET, Python, Node.js 和 WASM,无需额外安装 KCL 命令行即可使用,安装体积优化为之前版本的 90%,且不需要复杂的系统依赖。

此外,不同的 SDK 均提供了相同的 API,主要包括代码运行,代码分析,类型解析和添加外部依赖等操作,下面以 Java 和 C# SDK 为例

  • Java
import com.kcl.api.API;
import com.kcl.api.Spec.ExecProgram_Args;
import com.kcl.api.Spec.ExecProgram_Result;

public class ExecProgramTest {
public static void main(String[] args) throws Exception {
API api = new API();
ExecProgram_Result result = api
.execProgram(ExecProgram_Args.newBuilder().addKFilenameList("path/to/kcl.k").build());
System.out.println(result.getYamlResult());
}
}
  • C#
namespace KclLib.Tests;

using KclLib.API;

public class KclLibAPITest
{
public static void Main()
{
var execArgs = new ExecProgram_Args();
execArgs.KFilenameList.Add("path/to/kcl.k");
var result = new API().ExecProgram(execArgs);
Console.WriteLine(result.YamlResult);
}
}

更多其他 SDK 安装和使用方式详见:https://github.com/kcl-lang/lib

多语言插件更新

KCL 多语言插件新增至 3 个,目前主要支持 Go, Python 和 Java, 仅需要基础的 SDK 依赖,可以实现通用语言和 KCL 的无缝互操作,下面以 Python 和 Java 插件为例

编写如下 KCL 代码 (main.k)

import kcl_plugin.my_plugin

result = my_plugin.add(1, 1)

使用 Python SDK 注册 Python 函数实现在 KCL 中调用

import kcl_lib.plugin as plugin
import kcl_lib.api as api

plugin.register_plugin("my_plugin", {"add": lambda x, y: x + y})

def main():
result = api.API().exec_program(
api.ExecProgram_Args(k_filename_list=["main.k"])
)
assert result.yaml_result == "result: 2"

main()

使用 Java SDK 注册 Java 函数实现在 KCL 中调用

package com.kcl;

import com.kcl.api.API;
import com.kcl.api.Spec.ExecProgram_Args;
import com.kcl.api.Spec.ExecProgram_Result;

import java.util.Collections;

public class PluginTest {
public static void main(String[] mainArgs) throws Exception {
API.registerPlugin("my_plugin", Collections.singletonMap("add", (args, kwArgs) -> {
return (int) args[0] + (int) args[1];
}));
ExecProgram_Result result = new API()
.execProgram(ExecProgram_Args.newBuilder().addKFilenameList("main.k").build());
System.out.println(result.getYamlResult());
}
}

更多其他多语言插件使用方式详见:https://www.kcl-lang.io/docs/reference/plugin/overview

此外,可以在这里找到更多的关于 KCL 多语言插件使用的真实用例

🌐 其他资源

🔥 查看 KCL 社区 加入我们 🔥

更多其他资源请参考: