KubeSphere FrontendIntegration YAML 生成实战:用单菜单 JSON 一键产出规范 CRD 清单
【免费下载链接】kubesphereThe container platform tailored for Kubernetes multi-cloud, datacenter, and edge management ⎈ 🖥 ☁️项目地址: https://gitcode.com/GitHub_Trending/ku/kubesphere
导读
本文以 KubeSphere 仓库中的 frontend-integration-yaml 参考文档 为主线,讲解如何以一份"单菜单 + 多页面"的简化 JSON 为输入,通过官方生成器脚本快速产出可直接提交的规范FrontendIntegrationKubernetes 资源(API 组frontend-forge.kubesphere.io/v1alpha1)。读完本文,你将掌握输入 Schema 的完整字段语义、crdTable与iframe两类页面变体、字段映射与规范化规则、生成器命令行用法,以及产出 YAML 后如何接入 frontend-forge 扩展的运行时部署流程。
FrontendIntegration 与简化编写模型
FrontendIntegration(下称 FI)是 frontend-forge 扩展用于声明"前端集成"的规范资源:它把一组菜单项(spec.menus[])与一组页面(spec.pages[])绑定在一起,前端运行时据此渲染 KubeSphere 控制台中的导航菜单与页面。它的 API 版本与类型为:
apiVersion: frontend-forge.kubesphere.io/v1alpha1 kind: FrontendIntegration然而规范形态的spec.menus[]结构(含placement、type、children嵌套)手工编写冗长且容易出错。因此,frontend-integration-yaml skill 定义了一种故意比输出更简单的作者模型:只写一个顶层menu(单个菜单)加若干pages,再由生成器自动展开为规范的spec.menus[]数组。这正是本文要讲解的核心思路——"作者写简化 JSON,生成器产出规范 YAML"。
该 skill 的职责边界很明确(见 SKILL.md):
- 适用:生成 FI YAML、根据 CRD 快速创建集成清单、创建 iframe 型 FI 清单、把简化的单菜单配置转换为规范 YAML;
- 不适用:排查已有 FI 资源、管理 enable/disable/delete 生命周期、检查 JSBundle/Job/控制器/状态流转、编辑清单生成规则、处理多菜单作者模型。
输入 Schema:顶层字段
生成器从stdin或--input <path>读取 JSON。顶层结构如下:
{ "metadata": { "name": "required", "annotations": { "kubesphere.io/description": "optional" } }, "spec": { "enabled": true, "displayName": "optional", "builder": { "engineVersion": "optional" }, "locales": { "en": { "KEY": "Value" } } }, "menu": { "displayName": "required", "icon": "optional, defaults to GridDuotone", "placements": ["cluster"] }, "pages": [] }各部分的语义与生成器源码中的处理逻辑(generate_frontend_integration.py)对应如下:
metadata.name:必填,直接映射为资源名称;metadata.annotations可选,会被原样保留(sanitize_annotations会校验 key/value 均为非空字符串)。spec.enabled:可选布尔值,默认true(源码normalize_bool(..., default=True))。spec.displayName/spec.builder.engineVersion/spec.locales:可选透传字段,会被原样搬运到输出spec中,不参与展开逻辑。menu.displayName:必填,将成为所有展开后菜单子项的显示名来源之一。menu.icon:可选,缺省时使用GridDuotone(源码常量DEFAULT_MENU_ICON)。menu.placements[]:必填且至少一项,决定菜单挂在控制台的哪个层级(见下文"Placement 规则")。pages[]:必填且至少一项,页面列表。
页面变体:crdTable 与 iframe
pages[]中每个页面必须声明type,当前仅支持两种取值(源码VALID_PAGE_TYPES = {"crdTable", "iframe"})。
crdTable:把 CRD 渲染成表格页面
{ "displayName": "Bundles", "key": "optional", "type": "crdTable", "crdTable": { "authKey": "optional", "group": "extensions.kubesphere.io", "version": "v1alpha1", "scope": "Cluster", "names": { "kind": "JSBundle", "plural": "jsbundles" }, "columns": [] } }规则(与源码normalize_crd_page对应):
crdTable.group、crdTable.version、crdTable.scope、crdTable.names.plural必填;crdTable.names.kind可选,提供时原样透传;- 页面级
key缺省时默认为names.plural(例如jsbundles); crdTable.columns可选;缺省时按scope推导默认列(见下文"默认列");crdTable.authKey可选,透传为鉴权标识。
iframe:内嵌外部页面
{ "displayName": "Dashboard", "key": "dashboard", "type": "iframe", "iframe": { "src": "https://example.test/dashboard" } }规则:
key必填(iframe 无法从 CRD 推导 key);iframe.src必填,指向要内嵌的页面地址。
输出形态:规范 FrontendIntegration YAML
无论输入多么简化,生成器总是输出规范形态的FrontendIntegration:
apiVersion: frontend-forge.kubesphere.io/v1alpha1 kind: FrontendIntegration metadata: name: example spec: enabled: true menus: - key: example-cluster displayName: Operations icon: BoxDuotone placement: cluster type: organization children: - key: jsbundles displayName: Bundles pages: - key: jsbundles type: crdTable crdTable: group: extensions.kubesphere.io version: v1alpha1 scope: Cluster names: kind: JSBundle plural: jsbundles columns: - key: name title: NAME enableSorting: true render: type: text path: metadata.name - key: updateTime title: CREATION_TIME enableHiding: true enableSorting: true render: type: time path: metadata.creationTimestamp format: local-datetime注意输出中menus[0].key为example-cluster(metadata.name+-+placement),menus[0].type固定为organization,children由pages[]推导而来。这正是 SKILL.md 中"永远把menu.placements[]展开为spec.menus[]、永远从pages[]推导children"的落地结果。
自定义列的 render 能力
通过 validate_column 可以看到,自定义列render.type支持text、time、link三种(源码VALID_RENDER_TYPES),并可携带可选的format、pattern、link、payload字段;列级enableSorting、enableHiding均须为布尔值。例如时间列常配合format: local-datetime使用。
字段映射一览
参考文档 Field Mapping 给出的完整映射关系:
metadata.name直接映射为资源名称;metadata.annotations提供时原样保留;spec.enabled缺省为true;menu.icon缺省为GridDuotone;menu.displayName、menu.icon、menu.placements[]展开为spec.menus[];- 每个规范菜单 key 为
${metadata.name}-${placement}; - 每个菜单
type: organization; pages[].displayName成为对应菜单子项children[].displayName;pages[].key同时成为页面 key 与子项 key。
规范化规则
Placement 规则
- 支持的 placement 仅限
cluster、workspace、global(源码VALID_PLACEMENTS); - 重复的 placement 会被拒绝;
- 只要存在任一
workspaceplacement,所有crdTable.scope一律强制为Namespaced(源码normalize_pages中的force_namespaced逻辑)。
Scope 规则
pages[].crdTable.scope接受Cluster、cluster、Namespaced、namespaced、Namespace、namespace六种写法(源码normalize_scope先lower()再归并):namespaced 类取值统一归一化为Namespaced,cluster 类取值统一归一化为Cluster。
默认列
省略columns时按 scope 生成默认列。Cluster范围(源码 default_columns):
columns: - enableSorting: true key: name render: path: metadata.name type: text title: NAME - enableHiding: true enableSorting: true key: updateTime render: format: local-datetime path: metadata.creationTimestamp type: time title: CREATION_TIMENamespaced范围则在name之后、updateTime之前额外插入PROJECT(namespace)列:
columns: - enableSorting: true key: name render: path: metadata.name type: text title: NAME - enableHiding: true key: namespace render: path: metadata.namespace type: text title: PROJECT - enableHiding: true enableSorting: true key: updateTime render: format: local-datetime path: metadata.creationTimestamp type: time title: CREATION_TIME显式列的规范化
当用户显式提供columns时,生成器会先逐列校验(key/title/render 必填,render.type 合法),再按最终 scope 执行 normalize_columns:
- 最终 scope 为
Cluster时,删除所有已存在的namespace列; - 最终 scope 为
Namespaced时,确保恰好一个namespace列:若存在updateTime列,则插在updateTime之前;否则若存在name列,插在name之后;否则追加到末尾。
校验规则:生成器会拒绝什么
生成器在校验失败时会抛出ValidationError并以退出码 1 输出Error: ...到 stderr。被拒绝的场景包括(参考文档 Validation Rules 及源码各require_*/normalize_*函数):
- 缺少
metadata.name; - 缺少
menu.displayName或menu.placements(placements 为空数组同样报错); - placement 重复;
- 页面 key 重复;
crdTable必填字段缺失(group/version/scope/names.plural);- 缺少
iframe.src; - 输入不是合法 JSON、顶层不是对象、
type不属于crdTable/iframe、render.type 非法、scope 无法识别等也会被拒绝。
使用生成器脚本
生成器为纯 Python 3 脚本 generate_frontend_integration.py,无第三方依赖。命令行接口如下:
python3 scripts/generate_frontend_integration.py [--input <path>] [--output <path>]--input:JSON 作者清单路径,缺省为-,即从 stdin 读取;--output:生成 YAML 的输出路径,缺省输出到 stdout。
例如,把清单写入spec.json后生成:
python3 skills/frontend-integration-yaml/scripts/generate_frontend_integration.py --input spec.json --output fi.yaml或直接管道输入:
cat spec.json | python3 skills/frontend-integration-yaml/scripts/generate_frontend_integration.py生成器内置了一个轻量级 YAML 序列化器(dump_yaml及其配套的format_key/format_string),会为 YAML 保留字(null、true、yes等)、数字样字符串、含控制字符或特殊符号的字符串自动加引号,保证输出 YAML 始终可被解析。这也是官方工作流中"把生成器当作唯一真相来源、不要手工重建规范 YAML"(见 SKILL.md)的原因之一。
完整示例
示例一:纯 CRD 表格页
输入(bundles.json):
{ "metadata": { "name": "bundles" }, "menu": { "displayName": "Extensions", "icon": "BoxDuotone", "placements": ["cluster"] }, "pages": [ { "displayName": "Bundles", "type": "crdTable", "crdTable": { "group": "extensions.kubesphere.io", "version": "v1alpha1", "scope": "Cluster", "names": { "kind": "JSBundle", "plural": "jsbundles" } } } ] }生成结果要点:
- 输出规范
FrontendIntegration资源; menus[0].key = bundles-cluster;- 页面 key 由
names.plural推导为jsbundles; - 自动生成 Cluster 默认列(name + creationTimestamp)。
示例二:crdTable 与 iframe 混合
输入(ops.json):
{ "metadata": { "name": "ops" }, "menu": { "displayName": "Operations", "icon": "AppsGearDuotone", "placements": ["cluster", "workspace"] }, "pages": [ { "displayName": "Bundles", "type": "crdTable", "crdTable": { "group": "extensions.kubesphere.io", "version": "v1alpha1", "scope": "Cluster", "names": { "plural": "jsbundles" } } }, { "displayName": "Dashboard", "key": "dashboard", "type": "iframe", "iframe": { "src": "https://example.test/dashboard" } } ] }生成结果要点:
- 菜单展开为
ops-cluster与ops-workspace两个 organization 菜单; - 由于包含
workspaceplacement,crdTable 页面的 scope 被强制改为Namespaced(即便输入写的是Cluster); - 自动插入
PROJECT(namespace)列,使表格展示所属项目。
部署与后续运行时操作
生成出的规范 YAML 即为最终产物。将其应用进集群即可创建 FI 资源:
kubectl apply -f fi.yaml注意:FrontendIntegration是集群级资源,操作时不要加-n(参见 frontend-forge-fi-operations)。在创建、更新、启用、禁用、删除或排查 FI 之前,务必先做预检,确认 frontend-forge 扩展已就绪:
kubectl get extension frontend-forge kubectl get installplan frontend-forge -o yaml # 需要:extension 存在、installplan 存在、spec.enabled=trueFI 被控制器接管后,会触发构建 Job 并产出运行时JSBundle与 ConfigMap。排查时可参考 FI 运行时检查参考:
kubectl get fi <fi-name> -o yaml kubectl get jobs -n extension-frontend-forge -l frontend-forge.io/fi-name=<fi-name> kubectl get fi <fi-name> -o jsonpath='{.status.bundle_ref.name}{"\n"}' kubectl get jsbundle fi-<fi-name> -o yaml kubectl get configmap -n extension-frontend-forge fi-<fi-name>-config -o yaml常用标签与注解也是排查利器:标签frontend-forge.io/fi-name、frontend-forge.io/spec-hash、frontend-forge.io/manifest-hash、frontend-forge.io/enabled,注解frontend-forge.io/build-job、frontend-forge.io/manifest-content、frontend-forge.io/source-spec等,均可在 FI 及其衍生对象上查到。
小结
KubeSphere 的 frontend-integration-yaml 生成器把"声明前端集成"这一高频操作压缩成了三个动作:写一份单菜单 JSON → 运行生成器脚本 → apply 规范 YAML。生成器在展开菜单、推导 key、按 scope 生成默认列、规范化显式列、强制 workspace 范围 namespaced 等方面做了全部重活,同时用严格的校验保证产物合规。理解输入 Schema、页面变体、字段映射与规范化规则后,无论是为 CRD 快速生成表格页,还是混入 iframe 页嵌入外部面板,都可以做到一次生成、直接提交。
【免费下载链接】kubesphereThe container platform tailored for Kubernetes multi-cloud, datacenter, and edge management ⎈ 🖥 ☁️项目地址: https://gitcode.com/GitHub_Trending/ku/kubesphere
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考