app-sdk-concepts
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGrafana App SDK Concepts
Grafana App SDK 核心概念
The grafana-app-sdk is a CLI and Go library for building schema-centric applications on the Grafana App Platform. Apps define resource types using CUE schemas ("kinds"), generate Go and TypeScript code from those schemas, and implement business logic via admission control (ingress validation/mutation) and reconcilers (async processing).
grafana-app-sdk是一款CLI工具和Go库,用于在Grafana App Platform上构建以Schema为核心的应用。应用通过CUE schema(即“kinds”)定义资源类型,基于这些schema生成Go和TypeScript代码,并通过准入控制(入口验证/修改)和协调器(异步处理)实现业务逻辑。
Prerequisites
前置条件
Install the CLI:
bash
go install github.com/grafana/grafana-app-sdk/cmd/grafana-app-sdk@latestVerify installation:
bash
grafana-app-sdk version安装CLI:
bash
go install github.com/grafana/grafana-app-sdk/cmd/grafana-app-sdk@latest验证安装:
bash
grafana-app-sdk versionDeployment Modes
部署模式
The available deployment modes depend on the repository context:
Inside the Grafana repo ( or a fork — identified by the presence of and at the repo root):
github.com/grafana/grafanaapps/pkg/registry/apps/- Only grafana/apps mode is available.
Outside the Grafana repo:
- Standalone operator or Frontend-only are available. grafana/apps is not applicable.
| Mode | Description | Context |
|---|---|---|
| Standalone operator | Single binary, runs as a Kubernetes operator with its own webhook server | Outside Grafana repo |
| grafana/apps | Submodule inside | Inside Grafana repo only |
| Frontend-only | No backend code; CUE kinds and generated types only | Outside Grafana repo |
The app business logic (admission handlers, reconcilers) is identical across modes — only the runtime embedding differs.
可用的部署模式取决于仓库上下文:
在Grafana仓库内(或其分支——可通过仓库根目录是否存在和来识别):
github.com/grafana/grafanaapps/pkg/registry/apps/- 仅支持grafana/apps模式。
在Grafana仓库外:
- 支持独立operator或仅前端模式。grafana/apps模式不适用。
| 模式 | 描述 | 适用上下文 |
|---|---|---|
| 独立operator | 单二进制文件,作为Kubernetes operator运行,自带webhook服务器 | Grafana仓库外 |
| grafana/apps | 作为子模块位于 | 仅Grafana仓库内 |
| 仅前端 | 无后端代码;仅包含CUE kinds和生成的类型 | Grafana仓库外 |
应用的业务逻辑(准入处理器、协调器)在各模式下完全一致——仅运行时嵌入方式不同。
Project Init Workflow
项目初始化流程
Standalone operator
独立operator模式
bash
undefinedbash
undefined1. Initialize the project (use the Go module path)
1. 初始化项目(使用Go模块路径)
grafana-app-sdk project init github.com/example/my-app
grafana-app-sdk project init github.com/example/my-app
2. Add operator scaffolding (prompt the user before running)
2. 添加operator脚手架(运行前需提示用户确认)
grafana-app-sdk project component add operator
The `project component add operator` command creates an App, watcher stubs for all kinds, and the main operator binary. Always confirm with the user before running it — they may prefer to write these from scratch against the `app.App` interface.grafana-app-sdk project component add operator
`project component add operator`命令会创建一个App、所有kinds的监听器存根,以及主operator二进制文件。运行前务必与用户确认——他们可能更倾向于基于`app.App`接口从头编写这些代码。grafana/apps-style app
grafana/apps风格应用
Only available when working inside the Grafana repo (or a fork). The init command detects this automatically by checking for and at the repo root.
apps/pkg/registry/apps/bash
undefined仅在Grafana仓库(或其分支)内工作时可用。初始化命令会通过检查仓库根目录是否存在和自动识别此上下文。
apps/pkg/registry/apps/bash
undefined1. Create the app subdirectory and init inside it
1. 创建应用子目录并在其中初始化
mkdir -p apps/my-app
cd apps/my-app
grafana-app-sdk project init github.com/grafana/grafana/apps/my-app
mkdir -p apps/my-app
cd apps/my-app
grafana-app-sdk project init github.com/grafana/grafana/apps/my-app
2. Clean up — keep ONLY these directories/files:
2. 清理——仅保留以下目录/文件:
kinds/ pkg/ go.mod go.sum
kinds/ pkg/ go.mod go.sum
Delete everything else generated by project init.
删除project init生成的所有其他内容。
3. Copy the Makefile from apps/example (run from repo root)
3. 从apps/example复制Makefile(在仓库根目录运行)
cp apps/example/Makefile apps/my-app/Makefile
cp apps/example/Makefile apps/my-app/Makefile
4. Copy the codegen config from apps/example (run from repo root) (ALWAYS OVERWRITE)
4. 从apps/example复制代码生成配置(在仓库根目录运行)(务必覆盖原有文件)
cp apps/example/kinds/config.cue apps/my-app/kinds/config.cue
cp apps/example/kinds/config.cue apps/my-app/kinds/config.cue
5. Update the go workspace to use the new app
5. 更新Go工作区以使用新应用
go work use ./apps/my-app
Then wire the app into Grafana:
- Register in `pkg/registry/apps/apps.go` (`ProvideAppInstallers` WireSet)
- Add `register.go` under `pkg/registry/apps/my-app/`
See `apps/example/README.md` in the repo for the full registration walkthrough.go work use ./apps/my-app
随后将应用接入Grafana:
- 在`pkg/registry/apps/apps.go`(`ProvideAppInstallers` WireSet)中注册
- 在`pkg/registry/apps/my-app/`下添加`register.go`
查看仓库中的`apps/example/README.md`获取完整的注册流程说明。Frontend-only app
仅前端应用
bash
grafana-app-sdk project init github.com/example/my-appbash
grafana-app-sdk project init github.com/example/my-appSkip operator and backend component scaffolding entirely
完全跳过operator和后端组件脚手架
Run generate to produce TypeScript types, then build frontend
运行generate命令生成TypeScript类型,然后构建前端
undefinedundefinedOverall Development Workflow
整体开发流程
1. project init → scaffolds module, Makefile, kinds/ dir
2. project kind add → adds CUE kind scaffold to kinds/
3. Edit kinds/*.cue → define schemas, validation, versions
4. grafana-app-sdk generate → produces Go types, clients, TS types,
AppManifest, CRD files
5. Implement logic → fill in reconciler and admission stubs
6. (optional) add frontend → grafana-app-sdk project component add frontend1. project init → 生成模块、Makefile、kinds/目录
2. project kind add → 向kinds/目录添加CUE kind脚手架
3. 编辑kinds/*.cue → 定义schema、验证规则、版本
4. grafana-app-sdk generate → 生成Go类型、客户端、TS类型、
AppManifest、CRD文件
5. 实现逻辑 → 填充协调器和准入控制存根
6. (可选)添加前端 → grafana-app-sdk project component add frontendProject Structure (standalone)
项目结构(独立模式)
my-app/
├── cmd/
│ └── operator/ # Build target package for the operator, contains the `main` package
├── kinds/ # CUE kind definitions (source of truth)
│ ├── manifest.cue # App-level manifest and version declarations
│ ├── mykind.cue # kind metadata for MyKind
│ └── mykind_v1alpha1.cue # version schema for MyKind version v1alpha1
├── pkg/
│ ├── generated/ # Generated Go code — do NOT edit manually
│ ├── watchers/ # Watcher stubs generated by `project component add operator`
│ └── app/
│ └── app.go # Entry point; implement app.App interface here
├── definitions/ # Generated CRD and manifest files — do NOT edit manually
├── local/
│ ├── additional/ # Folder for specifying additional YAML manifests for local deployment
│ ├── generated/ # Folder where generated manifests for a local deployment live (don't commit)
│ ├── mounted-files/ # Folder that gets mounted to the k3d cluster (don't commit)
│ ├── scripts/ # Generated scripts (don't commit)
│ ├── Tiltfile # Tiltfile for standing up local resources
│ └── config.yaml # configuration file for local setup
├── go.mod
└── Makefilemy-app/
├── cmd/
│ └── operator/ # operator的构建目标包,包含`main`包
├── kinds/ # CUE kind定义(唯一可信源)
│ ├── manifest.cue # 应用级清单和版本声明
│ ├── mykind.cue # MyKind的kind元数据
│ └── mykind_v1alpha1.cue # MyKind版本v1alpha1的版本schema
├── pkg/
│ ├── generated/ # 生成的Go代码——请勿手动编辑
│ ├── watchers/ # `project component add operator`生成的监听器存根
│ └── app/
│ └── app.go # 入口点;在此实现app.App接口
├── definitions/ # 生成的CRD和清单文件——请勿手动编辑
├── local/
│ ├── additional/ # 用于指定本地部署的额外YAML清单的文件夹
│ ├── generated/ # 本地部署生成的清单所在文件夹(无需提交)
│ ├── mounted-files/ # 挂载到k3d集群的文件夹(无需提交)
│ ├── scripts/ # 生成的脚本(无需提交)
│ ├── Tiltfile # 用于启动本地资源的Tiltfile
│ └── config.yaml # 本地设置的配置文件
├── go.mod
└── MakefileApp-Specific Configuration (SpecificConfig)
应用特定配置(SpecificConfig)
Apps can pass structured configuration through . This is how the registration layer () passes feature flags or runtime settings into the function:
app.Config.SpecificConfigregister.goNewgo
// pkg/app/config.go
type AppSpecificConfig struct {
EnableReconciler bool
SomeFeatureFlag bool
}
// pkg/app/app.go — read it in New()
func New(cfg app.Config) (app.App, error) {
appCfg, _ := cfg.SpecificConfig.(*AppSpecificConfig)
if appCfg != nil && appCfg.EnableReconciler {
// wire up reconciler
}
// ...
}
// pkg/registry/apps/<name>/register.go — populate from Grafana config
specificConfig := &app.AppSpecificConfig{
EnableReconciler: features.IsEnabled(featuremgmt.FlagMyAppReconciler),
}
provider := simple.NewAppProvider(manifestdata.LocalManifest(), specificConfig, app.New)Use for anything that varies by environment or feature flag rather than hardcoding it in .
SpecificConfigNew应用可通过传递结构化配置。这是注册层()将功能标志或运行时设置传入函数的方式:
app.Config.SpecificConfigregister.goNewgo
// pkg/app/config.go
type AppSpecificConfig struct {
EnableReconciler bool
SomeFeatureFlag bool
}
// pkg/app/app.go — 在New()中读取配置
func New(cfg app.Config) (app.App, error) {
appCfg, _ := cfg.SpecificConfig.(*AppSpecificConfig)
if appCfg != nil && appCfg.EnableReconciler {
// 连接协调器
}
// ...
}
// pkg/registry/apps/<name>/register.go — 从Grafana配置中填充
specificConfig := &app.AppSpecificConfig{
EnableReconciler: features.IsEnabled(featuremgmt.FlagMyAppReconciler),
}
provider := simple.NewAppProvider(manifestdata.LocalManifest(), specificConfig, app.New)对于任何因环境或功能标志而异的配置,请使用,而非在中硬编码。
SpecificConfigNewKey CLI Commands Reference
核心CLI命令参考
bash
undefinedbash
undefinedProject management
项目管理
grafana-app-sdk project init <module>
grafana-app-sdk project kind add <KindName> --overwrite
grafana-app-sdk project component add operator
grafana-app-sdk project component add frontend
grafana-app-sdk project init <module>
grafana-app-sdk project kind add <KindName> --overwrite
grafana-app-sdk project component add operator
grafana-app-sdk project component add frontend
Code generation
代码生成
grafana-app-sdk generate
undefinedgrafana-app-sdk generate
undefined