Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when deploying KubeEye for cluster inspection, creating InspectRule/InspectPlan resources, or retrieving inspection results. Covers InstallPlan-based deployment, OPA/PromQL/FileChange/Sysctl/Systemd/NodeInfo/FileFilter/ServiceConnect/CustomCommand rule types, and report retrieval. Always consult this skill when the user mentions KubeEye, cluster inspection, InspectRule, InspectPlan, or inspection reports.
.claude/skills/kubesphere-kubeeye/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-15 | ✗→✓ | ▲ Improved | 169% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 146% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 158% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 148% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 145% | 0% |
KubeEye is a Kubernetes cluster inspection tool for KubeSphere. It detects issues in workloads, nodes, configurations, and components through OPA/Rego policies, PromQL queries, file integrity checks, kernel parameter validation, and systemd health checks. It is installed as a KubeSphere extension.
kspublish (push extension to KubeSphere)
|
v
Extension available in KubeSphere marketplace
|
v
kubectl apply -f installplan.yaml
|
v
KubeEye deployed (3 components)┌─────────────────────────────────────────────────────────────┐
│ KubeSphere Extension │
│ │
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
│ │ kubeeye-apiserver │ │ kubeeye-controller-manager │ │
│ │ (Gin REST API) │ │ (4 CRD Controllers) │ │
│ │ Port 9090 │ │ │ │
│ └──────────┬──────────┘ └──────────────┬──────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ CRDs │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ │
│ │ │InspectRule│ │InspectPlan│ │InspectTask│ │Inspect │ │ │
│ │ │ │ │ │ │ │ │Result │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ kubeeye-job (K8s Jobs) │ │
│ │ OPA ├─ PromQL ├─ FileChange ├─ Sysctl ├─ Systemd │ │
│ │ NodeInfo ├─ FileFilter ├─ ServiceConnect ├─ Cmd │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘> Note: Cmd in the diagram refers to the customCommand rule type.
| CRD | API Version | Scope | Purpose | |-----|-------------|-------|---------| | InspectRule | kubeeye.kubesphere.io/v1alpha2 | Cluster | Defines inspection rules (OPA, PromQL, file checks, etc.) | | InspectPlan | kubeeye.kubesphere.io/v1alpha2 | Cluster | Schedules inspection execution (cron or one-shot) | | InspectTask | kubeeye.kubesphere.io/v1alpha2 | Cluster | Tracks a single inspection execution (created by InspectPlan) | | InspectResult | kubeeye.kubesphere.io/v1alpha2 | Cluster | Stores inspection results (populated by InspectTask) |
User creates InspectRule ──────┐
├──> InspectPlan references InspectRules
User creates InspectPlan ──────┘ |
| (cron trigger or manual)
v
InspectTask created by InspectPlanReconciler
|
InspectTaskReconciler:
1. Fetches referenced InspectRules
2. Merges rules per type
3. Creates K8s Jobs (kubeeye-job)
4. Jobs execute rule checks
5. Results accumulated
|
v
InspectResult populated with findings
|
v
User views results via:
- kubectl get inspectresult
- API: HTML report / XLSX downloadCheck if the KubeEye extension is available:
bashkubectl get extensionversions | grep kubeeye
Expected output: kubeeye-{version} (e.g. kubeeye-1.0.1).
If nothing is shown, the extension hasn't been published to KubeSphere yet.
Check if KubeEye is already installed:
bashkubectl get installplans.kubesphere.io kubeeye --ignore-not-found
If the InstallPlan exists, upgrading is supported — just select a newer version.
KubeEye is installed as a KubeSphere extension. The extension must first be published to KubeSphere (via kspublish, assumed to be already available).
> Note: The ./scripts/ paths below assume you are running from the skills/kubeeye/ directory. Adjust the path if you are running from elsewhere.
bashALL_VERSIONS=$(kubectl get extensionversions.kubesphere.io \ -l kubesphere.io/extension-ref=kubeeye \ -o jsonpath='{range .items[*]}{.spec.version}{"\n"}{end}' | sort -V) LATEST_STABLE=$(echo "$ALL_VERSIONS" | tail -1) echo "Available versions:" echo "$ALL_VERSIONS" echo "" echo "Latest stable: $LATEST_STABLE"
This sets ALL_VERSIONS and LATEST_STABLE. Use SELECTED_VERSION for the version chosen.
bash./scripts/generate-installplan.sh "$SELECTED_VERSION"
This generates the YAML to /tmp/kubeeye-installplan.yaml, runs --dry-run=server, then prints the apply command.
Apply it:
bashkubectl apply -f /tmp/kubeeye-installplan.yaml
Tell the user "Installing". Then ask if they want to check status. If yes:
bash./scripts/check-status.sh poll
bashkubectl apply -f rules/
This applies all sample InspectRule files bundled in this skill's rules/ directory.
> Note: Set the correct prometheus.endpoint in kubeeye_promql_inspect.yaml before importing if using PromQL rules.
bash./scripts/generate-plan.sh
This creates an InspectPlan referencing all available InspectRules and applies it directly.
Once an InspectPlan is applied, the controller creates an InspectTask:
bash# Watch task status kubectl get inspecttask -w # Describe a task kubectl describe inspecttask {task-name}
When the InspectTask completes, an InspectResult is created:
bash# List results kubectl get inspectresult # View result details kubectl get inspectresult {result-name} -o yaml # Download HTML report kubectl get svc -n extension-kubeeye kubeeye-apiserver \ -o custom-columns=CLUSTER-IP:.spec.clusterIP,PORT:.spec.ports[*].port curl http://{svc-ip}:9090/kapis/kubeeye.kubesphere.io/v1alpha2/inspectresults/{result-name}?type=html -o report.html # Download XLSX report curl http://{svc-ip}:9090/kapis/kubeeye.kubesphere.io/v1alpha2/inspectresults/{result-name}/download -o report.xlsx
bashkubectl -n extension-kubeeye expose deploy kubeeye-apiserver --port=9090 --type=NodePort --name=ke-apiserver-node-port # http://{node-address}:{node-port}/kapis/kubeeye.kubesphere.io/v1alpha2/inspectresults/{result-name}?type=html
| Purpose | Command | |---------|---------| | Single snapshot | ./scripts/check-status.sh quick | | Wait until complete (5min timeout) | ./scripts/check-status.sh poll |
Logic:
Installed → ✓ successFailed → ✗ prints full statusAn InspectRule (kubeeye.kubesphere.io/v1alpha2) defines the inspection logic. A single rule file can combine multiple rule types.
Uses Rego policy language. Specify input.kind and input.apiVersion.
Sub-packages:
inspect.kubeeye — Standard K8s resources (Deployment, Pod, Node, ConfigMap, etc.)inspect.kubeeye.nodeStatsSummary — Node stats summary (input.pods[*] with ephemeral-storage)Example - Deployment imagePullPolicy check:
yamlspec: opas: - name: imagePullPolicyRule rule: |- package inspect.kubeeye import rego.v1 deny contains msg if { input.kind == "Deployment" input.apiVersion == "apps/v1" container := input.spec.template.spec.containers[_] container.imagePullPolicy != "IfNotPresent" msg := { "Name": input.metadata.name, "Namespace": input.metadata.namespace, "Type": input.kind, "Message": "ImagePullPolicyNotIfNotPresent", "Reason": sprintf("imagePullPolicy is %v, should be IfNotPresent", [container.imagePullPolicy]), "Level": "WARNING" } }
Example - Node ephemeral-storage check:
yamlspec: opas: - name: CheckEphemeralStorage rule: |- package inspect.kubeeye.nodeStatsSummary import rego.v1 threshold := 5 * 1024 * 1024 * 1024 deny contains msg if { pod := input.pods[_] bytes := pod["ephemeral-storage"].usedBytes bytes > threshold msg := { "Name": pod.podRef.name, "Namespace": pod.podRef.namespace, "Type": "Pod", "Level": "danger", "Message": sprintf("ephemeral-storage usage %.2f GB exceeds 5 GB", [bytes / 1073741824]), "Reason": "ephemeral-storage exceeds threshold" } }
yamlspec: prometheus: endpoint: http://prometheus-k8s.monitoring.svc.cluster.local:9090 promQL: - name: NodeMemory desc: Node memory usage > 30% rule: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 30 rawDataEnabled: true
yamlspec: fileChange: - name: kubelet-config path: /var/lib/kubelet/config.yaml level: warning
yamlspec: sysctl: - name: net.ipv4.ip_forward rule: net.ipv4.ip_forward = 1 level: warning
yamlspec: systemd: - name: kubelet rule: kubelet == "active" level: warning
Supported resourcesType: cpu, memory, filesystem, inode, load.
yamlspec: nodeInfo: - name: CpuUsage rule: cpu > 20 resourcesType: cpu desc: CPU usage > 20% level: warning
yamlspec: fileFilter: - name: systemLog path: /var/log/syslog rule: error level: warning
yamlspec: serviceConnect: - workspace: system-workspace level: warning
yamlspec: customCommand: - name: check-disk command: "df -h / | tail -1" rule: ".*5[0-9]%" level: warning
yamlspec: componentExclude: - "kube-system/kube-dns"
| Parameter | Type | Description | |-----------|------|-------------| | schedule | string | Cron expression (e.g. "*/30 * * * ?"). Remove for one-shot. | | suspend | bool | Pause periodic inspection | | timeout | string | Inspection timeout (default: "10m") | | ruleNames | array | List of InspectRule names. Supports nodeName/nodeSelector per rule. | | maxTasks | int | Max retained results (older ones cleaned up) | | once | timestamp | One-shot inspection at a specific time | | clusterName | array | Multi-cluster targets (KubeSphere multi-cluster) |
bashkubectl logs -n extension-kubeeye -l control-plane=controller-manager --tail=100 kubectl logs -n extension-kubeeye -l app=kubeeye-apiserver --tail=100
yamlapiVersion: v1 kind: Secret metadata: name: message-secret namespace: extension-kubeeye type: Opaque stringData: username: your-email@example.com password: your-password
Update ConfigMap kubeeye-config:
yamldata: config: |- job: autoDelTime: 30 backLimit: 5 image: kubespheredev/kubeeye-job:v1.0.6 imagePullPolicy: Always resources: limits: cpu: 2000m memory: 512Mi requests: cpu: 50m memory: 256Mi message: enable: true email: address: smtp.example.com port: 25 fo: sender@example.com to: - recipient@example.com secretKey: message-secret
> ⚠ Always confirm with the user before proceeding.
bashif ! kubectl get installplans.kubesphere.io kubeeye --ignore-not-found &>/dev/null; then echo "KubeEye is not installed." exit 0 fi
Confirm with the user, then delete:
bashkubectl delete installplans.kubesphere.io kubeeye --ignore-not-found
Verify cleanup:
bash./scripts/verify-uninstall.sh
Success criteria:
extension-kubeeyebashkubectl describe po -n extension-kubeeye
bashkubectl get inspectplan kubectl get inspectrule kubectl describe inspectplan inspectplan
bashkubectl get inspecttask kubectl get inspectresult kubectl get endpoints -n extension-kubeeye kubeeye-apiserver
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-15 | fail→pass | 10,044 | 5,665 | -44% | 1 | 1 | 0% | 1,754 | 4,720 | +169% | 0 | 0 | — |
case-20 | pass→fail | 9,902 | 9,756 | -1% | 1 | 1 | 0% | 1,751 | 5,476 | +213% | 0 | 0 | — |
case-21 | pass→pass | 8,655 | 6,482 | -25% | 1 | 1 | 0% | 1,779 | 4,802 | +170% | 0 | 0 | — |
case-01 | fail→fail | 6,771 | 2,834 | -58% | 1 | 1 | 0% | 331 | 4,052 | +1124% | 0 | 0 | — |
case-02 | fail→pass | 13,016 | 7,427 | -43% | 1 | 1 | 0% | 2,124 | 5,219 | +146% | 0 | 0 | — |
case-03 | fail→pass | 11,157 | 9,581 | -14% | 1 | 1 | 0% | 1,925 | 4,957 | +158% | 0 | 0 | — |
case-04 | fail→pass | 10,563 | 5,166 | -51% | 1 | 1 | 0% | 1,904 | 4,718 | +148% | 0 | 0 | — |
case-05 | fail→pass | 9,483 | 5,087 | -46% | 1 | 1 | 0% | 1,958 | 4,792 | +145% | 0 | 0 | — |
case-22 | pass→pass | 7,160 | 4,953 | -31% | 1 | 1 | 0% | 1,283 | 4,498 | +251% | 0 | 0 | — |
case-06 | fail→pass | 7,782 | 4,109 | -47% | 1 | 1 | 0% | 1,508 | 4,369 | +190% | 0 | 0 | — |
case-07 | fail→pass | 10,538 | 3,911 | -63% | 1 | 1 | 0% | 1,907 | 4,411 | +131% | 0 | 0 | — |
case-08 | fail→pass | 9,381 | 4,311 | -54% | 1 | 1 | 0% | 1,816 | 4,535 | +150% | 0 | 0 | — |
case-09 | fail→pass | 10,559 | 5,107 | -52% | 1 | 1 | 0% | 2,019 | 4,735 | +135% | 0 | 0 | — |
case-10 | fail→pass | 14,138 | 3,756 | -73% | 1 | 1 | 0% | 2,341 | 4,383 | +87% | 0 | 0 | — |
case-11 | fail→pass | 23,925 | 13,048 | -45% | 1 | 1 | 0% | 1,365 | 4,251 | +211% | 0 | 0 | — |
case-12 | fail→fail | 8,976 | 4,473 | -50% | 1 | 1 | 0% | 1,628 | 4,109 | +152% | 0 | 0 | — |
case-13 | fail→pass | 14,718 | 3,876 | -74% | 1 | 1 | 0% | 2,406 | 4,317 | +79% | 0 | 0 | — |
case-14 | pass→pass | 9,782 | 4,073 | -58% | 1 | 1 | 0% | 1,151 | 4,432 | +285% | 0 | 0 | — |
case-16 | fail→pass | 11,549 | 4,978 | -57% | 1 | 1 | 0% | 2,183 | 4,771 | +119% | 0 | 0 | — |
case-17 | fail→pass | 24,491 | 4,084 | -83% | 1 | 1 | 0% | 2,267 | 4,513 | +99% | 0 | 0 | — |
case-18 | pass→pass | 9,485 | 2,994 | -68% | 1 | 1 | 0% | 1,837 | 4,161 | +127% | 0 | 0 | — |
case-19 | pass→pass | 8,561 | 4,038 | -53% | 1 | 1 | 0% | 1,641 | 4,202 | +156% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +59 percentage points is the difference between those two pass rates over the 21 comparable cases. 2 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.