app-sdk-concepts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Grafana 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@latest
Verify 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 version

Deployment Modes

部署模式

The available deployment modes depend on the repository context:
Inside the Grafana repo (
github.com/grafana/grafana
or a fork — identified by the presence of
apps/
and
pkg/registry/apps/
at the repo root):
  • Only grafana/apps mode is available.
Outside the Grafana repo:
  • Standalone operator or Frontend-only are available. grafana/apps is not applicable.
ModeDescriptionContext
Standalone operatorSingle binary, runs as a Kubernetes operator with its own webhook serverOutside Grafana repo
grafana/appsSubmodule inside
apps/<name>/
, admission auto-registered as a k8s plugin
Inside Grafana repo only
Frontend-onlyNo backend code; CUE kinds and generated types onlyOutside Grafana repo
The app business logic (admission handlers, reconcilers) is identical across modes — only the runtime embedding differs.
可用的部署模式取决于仓库上下文:
在Grafana仓库内
github.com/grafana/grafana
或其分支——可通过仓库根目录是否存在
apps/
pkg/registry/apps/
来识别):
  • 仅支持grafana/apps模式。
在Grafana仓库外
  • 支持独立operator仅前端模式。grafana/apps模式不适用。
模式描述适用上下文
独立operator单二进制文件,作为Kubernetes operator运行,自带webhook服务器Grafana仓库外
grafana/apps作为子模块位于
apps/<name>/
下,准入控制自动注册为k8s插件
仅Grafana仓库内
仅前端无后端代码;仅包含CUE kinds和生成的类型Grafana仓库外
应用的业务逻辑(准入处理器、协调器)在各模式下完全一致——仅运行时嵌入方式不同。

Project Init Workflow

项目初始化流程

Standalone operator

独立operator模式

bash
undefined
bash
undefined

1. 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
apps/
and
pkg/registry/apps/
at the repo root.
bash
undefined
仅在Grafana仓库(或其分支)内工作时可用。初始化命令会通过检查仓库根目录是否存在
apps/
pkg/registry/apps/
自动识别此上下文。
bash
undefined

1. 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-app
bash
grafana-app-sdk project init github.com/example/my-app

Skip operator and backend component scaffolding entirely

完全跳过operator和后端组件脚手架

Run generate to produce TypeScript types, then build frontend

运行generate命令生成TypeScript类型,然后构建前端

undefined
undefined

Overall 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 frontend
1. 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 frontend

Project 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
└── Makefile
my-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
└── Makefile

App-Specific Configuration (SpecificConfig)

应用特定配置(SpecificConfig)

Apps can pass structured configuration through
app.Config.SpecificConfig
. This is how the registration layer (
register.go
) passes feature flags or runtime settings into the
New
function:
go
// 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
SpecificConfig
for anything that varies by environment or feature flag rather than hardcoding it in
New
.
应用可通过
app.Config.SpecificConfig
传递结构化配置。这是注册层(
register.go
)将功能标志或运行时设置传入
New
函数的方式:
go
// 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)
对于任何因环境或功能标志而异的配置,请使用
SpecificConfig
,而非在
New
中硬编码。

Key CLI Commands Reference

核心CLI命令参考

bash
undefined
bash
undefined

Project 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
undefined
grafana-app-sdk generate
undefined

Resources

资源