Read-only GraphQL API over your local kubeconfig.
Binaries with the embedded UI are published on GitHub Releases for linux, macOS, and Windows (amd64 + arm64).
# linux amd64 — other assets: darwin/windows × amd64/arm64
curl -fsSL -o kubeql.tar.gz \
https://github.com/cdreier/kubeql/releases/latest/download/kubeql_linux_amd64.tar.gz
tar -xzf kubeql.tar.gz
sudo install -m 0755 kubeql /usr/local/bin/kubeql
kubeql serveOr build from source (make install builds the Vite SPA before go install):
make install
kubeql serve# GraphQL backend codegen (gqlgen) + frontend gqty client
make generate
# production binary (builds Vite SPA, embeds into Go)
make build
./bin/kubeql serve
# or install onto PATH (GOBIN / GOPATH/bin)
make install
kubeql serve
# or during development — two terminals:
make run # API :8080 (UI if you already built web/dist)
cd web && npm run dev # Vite :5173, proxies /query → :8080
# desktop-style window (Chrome --app on 127.0.0.1:17687; closes with the window)
kubeql serve --appOn Linux, --app detects browsers launched directly from /snap/bin and keeps
their dedicated kubeql profile under the browser's writable Snap data directory.
If an indirect Snap wrapper is not detected and Chromium reports that it cannot
create SingletonLock under ~/.cache/kubeql/chrome, use:
XDG_CACHE_HOME="$HOME/snap/chromium/common" kubeql serve --app| URL | What |
|---|---|
| http://localhost:8080/ | Embedded React UI |
| http://localhost:8080/playground | GraphQL Playground |
| http://localhost:8080/query | GraphQL HTTP/WS |
| http://localhost:5173/ | Vite dev UI (with proxy) |
Cluster clients are created lazily per kubeconfig context. The server starts even when no current-context is set.
Nest under contexts (one clientset per context name):
query listing {
contexts {
name
current
namespaces {
name
}
}
}Root fields require an explicit context argument:
query {
namespaces(context: "my-ctx", filter: { hasDeployment: { nameContains: "api" } }) {
name
context
deployments {
name
status
restarts
pods {
name
ready
restarts
}
}
}
}Deployments filtered by owned pods:
query {
deployments(context: "my-ctx", namespace: "prod", filter: { hasPod: { ready: false } }) {
name
status
pods(filter: { phase: "Running" }) {
name
ready
containers { name state restartCount }
}
}
}YAML + log subscription:
query {
pod(context: "my-ctx", namespace: "prod", name: "api-1") {
phase
yaml
}
}
subscription {
podLogs(context: "my-ctx", namespace: "prod", name: "api-1", tailLines: 50) {
timestamp
line
}
}cmd/kubeql/ CLI entrypoint
graph/
*.graphqls schema split by domain (context, namespace, deployment, pod, …)
*.resolvers.go matching resolvers (gqlgen follow-schema)
convert.go domain → GraphQL model mapping
internal/kube/ ClusterReader, Registry (per-context clients), Service, fake
internal/server/ chi router, playground, SPA
web/ Vite + React + TS + gqty (embedded via web/embed.go)
make testUnit tests use an in-memory fake cluster — no kubeconfig required.
Push a semver tag to trigger GitHub Actions (Vite build, embed into Go, publish archives):
git tag v0.1.0
git push origin v0.1.0Prerelease tags like v0.1.0-rc.1 are marked as prereleases automatically.
Local dry-run (needs GoReleaser on PATH):
make snapshot- Read-only: no mutations.
- Multi-context: nest under
contexts { ... }or passcontext:on root fields/subscriptions. - Metrics:
cpuUsage/memoryUsagecome from metrics-server (null if missing).cpuLimit/memoryLimitare the summed container limits from the pod spec. - Status subscriptions (
deploymentStatus,podStatus) poll every 2s and include resource usage; can be swapped for informers later.