- 云原生
- 后端
- 前端
【免费下载链接】kubeapps
A web-based UI for deploying and managing applications in Kubernetes clusters
本文围绕 Kubeapps 的 Operator 支持概念验证(Proof of Concept)提案展开:先介绍其数据源选型(OperatorHub/OLM)、面向用户的 10 步交互流程,以及"Dashboard 直连 K8s API、无需后端"的实现设计;再对照仓库中的真实前端源码,验证提案中每一个设计点(OLM 检测、PackageManifest目录、ClusterServiceVersion聚合、alm-examples表单模板等)是如何落地的,并指出实现相对 PoC 的演进(例如安装方式从展示kubectl命令演进为直接创建Subscription)。读完本文,你将理解 Kubeapps 如何在纯前端架构下接入 Operator Lifecycle Manager(OLM),以及如何复用 OLM 的 CRD 体系来聚合、部署和管理 Operator 实例。
一、背景与目标:Kubeapps 为什么要支持 Operator
Operator 是 Kubernetes 生态中用于自动化运维有状态应用的主流范式。提案文档 operators-support-poc.md 开篇即明确了 PoC 的目标:
- 定义一套在 Kubeapps 中接入 Operator 的可能实现方案;
- 描述 Operator 服务的用户体验(UX)与部分实现细节;
- PoC 的定位是"启动功能、暴露潜在问题、收集用户反馈",为后续更完整的体验迭代提供依据。
需要强调的是,PoC 阶段做了一个关键的简化假设:使用 Kubeapps 的用户被默认为具备 admin 权限的集群管理员,因为 Operator 生命周期中的多个管理步骤(安装 OLM、部署 Operator)需要 cluster-admin 级别的权限。
二、Operator 数据源选型:Source of Truth
在写任何代码之前,提案首先要回答"Operator 从哪里来"。当时社区中有两个公开的 Operator 来源:
- Awesome-operators:operator-framework 组织维护的一个 GitHub 仓库,本质上只是一个 README 文件,任何人都可以提 PR 附上自家 Operator 的链接和简短描述,没有准入规则;
- OperatorHub:由 Red Hat 联合 Amazon、Microsoft、Google 发起的集中式 Operator 目录,当时收录约 110 个 Operator,基于Operator Lifecycle Manager(OLM)构建,包含元数据、图标、标准化的安装方式,性质上类似于 Kubeapps 现有的 Helm chart 仓库。
提案的结论是:以 OperatorHub 作为 Kubeapps 的 Operator 数据源,原因是其遵循标准、信息完整,可直接用于列表展示和部署;Awesome-operators 则可以作为应用内的补充链接供用户浏览。
此外,提案还区分了 Operator 的两类兼容性:仅兼容 OpenShift 的 Operator和兼容任意 Kubernetes 发行版的 Operator,两者都以列表形式发布在 community-operators 仓库中(其中后者位于upstream-community-operators目录)。Kubeapps 对接的是后者,即面向原生 Kubernetes 集群的 Operator 列表。
三、UX 设计:用户探索与部署 Operator 的 10 步流程
提案按用户视角完整定义了 10 个步骤。以下逐条梳理,并标注仓库中对应实现的落点。
步骤 1-2:进入 Operators 页面,检测 OLM 是否已安装
用户进入 Configuration > Operators 区域。若集群未安装 OLM,页面给出明确的错误提示,并提供 "Show Instructions" 按钮展示安装命令:
curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/0.14.1/install.sh | bash -s 0.14.1在仓库源码中,"OLM 未安装"状态由 OLMNotFound 组件渲染:展示 OLM Logo、"The Operator Lifecycle Manager (OLM) is not available" 标题,并引导管理员查看 OLM 安装文档。检测逻辑本身非常轻量——Operators.isOLMInstalled 只是请求一次packagemanifests资源,若 HTTP 状态码为 200 即认为 OLM 已安装:
public static async isOLMInstalled(cluster: string, namespace: string) { const { status } = await axiosWithAuth.get<any>( url.api.k8s.operators.operators(cluster, namespace), ); return status === 200; }OperatorList 组件在挂载时 dispatchcheckOLMInstalled,只有检测通过才会继续拉取 Operator 列表和 Subscription 列表;列表页顶部还会显示一条 "Operators integration is under heavy development and currently in beta state" 的警告横幅——这与提案"PoC 用于收集反馈"的定位一致。
步骤 3-4:Operator 目录与详情页
OLM 安装完成后,Kubeapps 列出 OperatorHub 中所有可用 Operator(类似 OperatorHub 官网的列表页);点击某个 Operator 则展示其详情,布局与 chart 详情视图类似。
对应实现:
- 列表页 OperatorList 支持搜索(按名称正则匹配)以及Category / Capability / Provider三维过滤,过滤值取自每个 Operator 默认 channel 的
currentCSVDesc.annotations(如categories、capabilities);同时通过对比当前命名空间的Subscription名称,把 Operator 分成 "Installed" 与 "Available Operators" 两组; - 详情页 OperatorView 展示 Operator 名称、Provider、默认 channel 的版本号与描述,并提供 "Deploy" 按钮跳转到安装表单。
步骤 5:安装 Operator——PoC 的 kubectl 命令方案
PoC 阶段对"安装"做了最小化设计:Kubeapps不实际执行安装,只展示一条可直接复制的kubectl命令,例如对 etcd Operator:
kubectl create -f https://operatorhub.io/install/etcd.yaml提案特别注明:有些 Operator 是 namespaced 的,即只在一个命名空间内可用,安装时需要感知这一点。
从当前仓库源码看,实现已经演进超过了 PoC 基线:Kubeapps 现在会直接创建 OLM 资源完成部署。Operators.createOperator 的流程是:先调用createOperatorGroupIfNotExists(若非operators命名空间且不存在OperatorGroup,则创建一个targetNamespaces指向当前命名空间的default-*OperatorGroup),然后 POST 一个Subscription:
{ apiVersion: "operators.coreos.com/v1alpha1", kind: "Subscription", metadata: { name, namespace }, spec: { channel, installPlanApproval, name, source: "operatorhubio-catalog", sourceNamespace: "olm", startingCSV: csv, }, },安装表单 OperatorNew 让用户选择三个参数:Update Channel(默认 channel 可切换)、Installation Mode("All namespaces on the cluster" 或当前命名空间,对应 PoC 中关于 namespaced Operator 的注意点;若 channel 不支持AllNamespaces安装模式,全局选项会被禁用,且禁止在operators命名空间内安装 namespaced Operator)、Approval Strategy(Automatic/Manual,即installPlanApproval字段)。全局安装时目标命名空间固定为operators,否则为当前命名空间。
步骤 6:命名空间中已安装 Operator 的展示
安装完成后,Operators 区域会列出当前命名空间内的 Operator;选择 "All Namespaces" 可跨命名空间查看全部 Operator,并标注其是否为全局(跨命名空间)可用。点击某个 Operator 进入其详情视图。从源码结构看,Operators.global(channel)工具函数(Operators.ts#L163-L165)正是通过判断 channel 的installModes中是否存在受支持的AllNamespaces模式来实现"是否全局可用"的判定,与提案描述一一对应。
步骤 7:实例类型进入 Catalog 目录
Operator 在命名空间中可用后,会暴露若干"operator instance"类型——即可以用该 Operator 创建的实例。以etcdOperator 为例,它暴露etcd Cluster、etcd Backup、etcd Restore三种实例类型。提案要求:这些类型要与 chart 一起列在 Catalog 视图中,附带标识它们来源的标签,并支持过滤以便发现。
实现落点是 OperatorCatalogItem:每张 InfoCard 使用tag2Content={"operator"}打上 "operator" 标签、tag1Content展示所属 CSV 名称(去掉版本号),背景图标由getPluginIcon("operator")渲染,链接指向创建实例的表单路由。Catalog 组件在命名空间确定后 dispatchactions.operators.getCSVs拉取该命名空间的全部ClusterServiceVersion并展开其 owned CRD 生成这些卡片。
步骤 8:创建实例的表单
点击某个实例类型后渲染创建表单,用户可以在给出的示例 YAML 基础上任意修改。
表单的数据来源正是提案中提到的alm-examples注解。parseCSV 函数从 CSV 的spec.customresourcedefinitions.owned中找到目标 CRD,然后解析metadata.annotations["alm-examples"]中的 JSON 示例数组,匹配kind后将对应示例序列化为 YAML 作为表单默认值——若某资源没有示例,则渲染空模板,与提案"an empty template will be rendered"完全一致。部署时,表单把crd.name拆出复数形式(crd.name.split(".")[0]),通过 K8s API 直接创建该 CustomResource。
步骤 9-10:实例列表与实例详情页
实例运行后,Operators 区域列出当前命名空间中的实例:
点击实例进入详情页。提案指出第一版只需展示部署该实例所用的 YAML即可,未来若实例生成的资源带有OwnerReference,应能在该视图中检测并列出(至少覆盖 Deployment、Service 等常见资源)。OperatorInstance 组件即实现了这一"展示 YAML + 可 Update/Delete"的最小视图,并预留了跳转更新表单(operators-instances/.../update路由)的入口。
四、实现设计:为什么 PoC 不需要后端
这是提案中最核心的架构决策:
所有与 Operator 相关的实体(PackageManifest、CSV、实例 CR)都作为CRD表示并存储在集群中,因此 Dashboard 可以直接查询不同的 K8s API 端点并渲染结果,无需任何后端功能。
这一点在当前代码中得到明确印证。shared/url.ts 中有一组专门标注"accessing the k8s API server directly"的端点构造函数:
| 资源 | API 路径 |
|---|---|
| Operator 目录 | apis/packages.operators.coreos.com/v1/.../packagemanifests |
| 单个 Operator | apis/packages.operators.coreos.com/v1/namespaces/{ns}/packagemanifests/{name} |
| CSV 列表/单个 | apis/operators.coreos.com/v1alpha1/.../clusterserviceversions |
| OperatorGroup | apis/operators.coreos.com/v1/namespaces/{ns}/operatorgroups |
| Subscription | apis/operators.coreos.com/v1alpha1/namespaces/{ns}/subscriptions |
| 任意实例 CR | apis/{apiVersion}/namespaces/{ns}/{resource}[/{name}] |
所有读写都由 Operators 类封装(getOperators、getCSVs、createResource、listResources、getResource、updateResource、deleteResource),经 actions/operators.ts 的 thunk 分发到 Redux store,组件只消费状态。
4.1 检查 OLM 是否可用
提案原文:"检查 OLM 是否安装非常简单,有一些资源只有在 OLM 安装后才存在,例如可以检查 CRDclusterserviceversions.operators.coreos.com是否存在。"
实现上选择了同等思路:请求packagemanifests列表资源,200 即视为已安装(该资源同样只在 OLM 存在时才可访问)。actions/operators.ts 中的 checkOLMInstalled 在请求成功时 dispatchOLMInstalled,失败则记录errorOLMCheck并返回 false。
4.2 Operator Catalog:查询packagemanifests
提案:Operator 目录视图通过查询packagemanifests.packages.operators.coreos.com(非命名空间资源)构建,返回的列表包含渲染卡片列表所需的全部信息。
从 IPackageManifest 类型定义可以看到,Kubeapps 实际消费了status中的catalogSource、provider、defaultChannel与channels(每个 channel 携带currentCSV和完整的currentCSVDesc:描述、版本、installModes、owned CRD 列表等注解信息)。getOperators 拉取后按名称排序存入 store,供列表页与详情页复用。
4.3 Operator 图标:K8s API 聚合层的"障眼法"
提案中有一段值得单独展开的实现细节:packages.operators.coreos.com这个 API group 实际上是一个通过 Kubernetes API 聚合层 扩展的APIService——发往该 group 的请求会被 API Server 代理到 OLM 管理的后端服务。因此 Kubeapps 查询:
apis/packages.operators.coreos.com/v1/namespaces/olm/packagemanifests/<operator>/icon看起来是标准 K8s 端点,实际命中的是 OLM 服务。当前代码保留了这一用法(api.operators.operatorIcon),同时 CSV 侧的图标(spec.icon的 base64 数据,见 getIcon)也被用于实例卡片等场景,无图标时回退到占位符。
4.4 Catalog 聚合:通过 CSV 的 owned CRD 找到实例类型
提案:"要向现有 Catalog 视图加入给定命名空间中可用的 Operator 类型。为了聚合不同实例类型,需要查询该命名空间的全部 ClusterServiceVersion;每个 CSV 包含其'拥有'的 CRD 列表,这些就是我们要展示的实例类型。"
getResources 完整实现了这段"两级遍历"逻辑,也是整个 Operator 支持中最典型的实现:
const csvs = await dispatch(getCSVs(cluster, namespace)); const csvPromises = csvs.map(async csv => { const crds = get(csv, "spec.customresourcedefinitions.owned", []); const crdPromises = crds.map(async (crd) => { const { plural, group } = parseCRD(crd.name); // "etcdclusters.etcd.database.coreos.com" -> {plural, group} const csvResources = await Operators.listResources( cluster, csv.metadata.namespace, `${group}/${crd.version}`, plural, ); resources = resources.concat(csvResources.items); }); await Promise.all(crdPromises); });其中parseCRD把 CRD 名xxx.group.version拆成复数名与 group,再按group/version组装出动态 API 路径去列举实例。这个"先拿 CSV 清单、再逐个 CRD 拉实例"的策略,正是提案"Application list 中没有单一端点可查全部实例,必须先枚举实例类型再逐个查询"这一结论的代码化。
4.5 实例详情的数据模型
IClusterServiceVersionCRD 类型还保留了specDescriptors/statusDescriptors及x-descriptors字段——这些是 OLM 用于描述实例字段语义的元数据,为提案中"未来丰富实例视图"预留了数据结构。
五、路由与功能开关:一个容易忽略的适用前提
从 Routes 可以看到 Operators 相关的完整路由表:
| 路由 | 组件 |
|---|---|
/c/:cluster/ns/:namespace/operators | OperatorList |
/c/:cluster/ns/:namespace/operators/:operator | OperatorView |
/c/:cluster/ns/:namespace/operators/new/:operator | OperatorNew |
/c/:cluster/ns/:namespace/operators-instances/new/:csv/:crd | OperatorInstanceForm |
/c/:cluster/ns/:namespace/operators-instances/:csv/:crd/:instanceName | OperatorInstance |
/c/:cluster/ns/:namespace/operators-instances/:csv/:crd/:instanceName/update | OperatorInstanceUpdateForm |
需要注意的是,这些路由只在featureFlags.operators为 true 时注册;路由表中的注释明确写道:"Operators support has been deactivated by default for Kubeapps. It can be enabled in values configuration."——也就是说,Operator 支持默认关闭,需要通过 Helm values 配置开启,且前提是集群已安装 OLM。使用本文方案前应确认这两点。
六、测试佐证:e2e 用例验证完整闭环
仓库中的 Playwright 集成测试 06-operator-deployment.spec.js 端到端地验证了提案描述的完整用户旅程:登录 → 打开 Operators 页面 → 搜索并筛选prometheusOperator → 点击 Deploy 部署 → 切换到 Catalog 并勾选 Operators 过滤 → 创建 Prometheus 实例(断言出现 "Installation Values" 表单)→ 执行 Update → 执行 Delete。该用例(超时设置为 3600 秒,因为 OLM 部署本身耗时较长)是"提案 UX 步骤 3-10 在真实集群上可走通"的直接证据。
七、小结:PoC 设计的价值与演进脉络
回顾整份提案,其工程价值在于三个可复用的设计判断:
- 数据源标准化:选择基于 OLM/OLM 目录的 OperatorHub 而非自由 README 列表,使"列表 + 元数据 + 图标 + 安装"形成闭环,这一决策直接决定了后续所有视图的数据形状;
- 零后端的可行性论证:由于 OLM 将一切实体建模为 CRD,Dashboard 前端借助 K8s API(含聚合层)即可完成读取、创建与更新,PoC 因此避免了后端改造成本;
- 渐进式视图策略:实例详情页第一版只展示 YAML,把
OwnerReference关联资源展示留给后续迭代——这与代码中保留specDescriptors等元数据、预留 update 路由的做法互相印证。
而当前仓库源码也展示了 PoC 之后的自然演进:安装方式从"展示kubectl命令"升级为直接创建OperatorGroup+Subscription(含 channel、安装模式与审批策略的可视化选择),列表页增加了已安装/可用分组与三维过滤,实例操作补齐了 Update/Delete 与 e2e 覆盖。理解了这份提案与上述源码,就掌握了 Kubeapps 中 Operator 支持的完整技术图景。
- 云原生
- 后端
- 前端
【免费下载链接】kubeapps
A web-based UI for deploying and managing applications in Kubernetes clusters
相关推荐
解密WinDiskWriter:3大创新技术架构实现macOS上Windows启动盘制作
解密WinDiskWriter:3大创新技术架构实现macOS上Windows启动盘制作 WinDiskWriter是一款专为macOS设计的开源Windows
桌面应用Operator SDK 命令行用户体验演进:`alpha olm init` 与 `olm up` 的设计提案、实现落地与源码印证
Operator SDK 命令行用户体验演进: alpha olm init 与 olm up 的设计提案、实现落地与源码印证 本文以仓库内设计提案 propo
云原生后端开发工具微服务Kubeapps 多集群支持:设计提案与实现落地指南
Kubeapps 多集群支持:设计提案与实现落地指南 本文基于 Kubeapps 官方设计提案( multi cluster support.md https:
云原生后端前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考