Install any skill in seconds. Free to start, no credit card required.
Get Started Free →KubeSphere OpenKruise management Skill. Use when user asks to install or enable OpenKruise, check OpenKruise status, view kruise pods/logs/CRDs, create or update SidecarSet, manage sidecar injection, create or update CloneSet, perform in-place update or batch rollout, uninstall or remove OpenKruise, or troubleshoot Kruise Pod, CRD, and webhook issues in KubeSphere.
.claude/skills/kubesphere-kubesphere-openkruise/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 242% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 852% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 1668% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 111% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 415% | 0% |
Use this skill for the full OpenKruise lifecycle in KubeSphere:
InstallPlanSidecarSet manifests for sidecar injection and rolling updatesCloneSet manifests for advanced stateless workloads, in-place updates, and batch rolloutOut of scope by default:
BroadcastJob, NodeImage, UnitedDeployment, or AdvancedPodAutoscalerIf the user explicitly asks for those CRDs, acknowledge that they are OpenKruise capabilities but treat them as a follow-up task instead of assuming they belong in the default workflow.
InstallPlan YAML, SidecarSet YAML, CloneSet YAML, kubectl commands, or a short ordered procedure.InstallPlan.openkruise only if the user context or cluster output does not expose a different resource name.1.0.31.4.0InstallPlan:spec.extension.versionspec.extension.version: 1.0.3.InstallPlan.metadata.name MUST equal InstallPlan.spec.extension.name.InstallPlan is cluster-scoped in KubeSphere. Do not add a namespace to kubectl get|describe|delete installplan.upgradeStrategy: Manual unless the user explicitly asks for something else.SidecarSet or CloneSet, prefer checking the installed API versions:bashkubectl api-resources --api-group apps.kruise.io
SidecarSet: apps.kruise.io/v1alpha1CloneSet: apps.kruise.io/v1alpha1Treat the 1.0.3 -> 1.4.0 mapping as environment evidence, not a universal rule. When the user asks for precision, prove it first:
bash# Discover KubeSphere extension version kubectl get extensionversions.kubesphere.io -l kubesphere.io/extension-ref=openkruise kubectl get extensionversion openkruise-1.0.3 -o yaml # Discover deployed runtime image or controller version kubectl get pods -n kruise-system -o wide kubectl get deploy -n kruise-system kruise-manager -o jsonpath='{.spec.template.spec.containers[*].image}' kubectl describe pod -n kruise-system <kruise-manager-pod>
If these commands disagree with the assumed mapping, prefer cluster output over the baked-in default.
This section provides two approaches for querying OpenKruise status:
Use curl with environment variables for querying KubeSphere extension status and multi-cluster resources.
Environment Variables:
bashexport KS_HOST="http://<kubesphere-host>" # KubeSphere console URL (required) export KS_USERNAME="admin" # Username (default: admin) export KS_PASSWORD="<password>" # Password (required)
Helper Functions (add to ~/.bashrc or use directly):
bash# Get OAuth token ks_token() { curl -s -X POST "$KS_HOST/oauth/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password&username=${KS_USERNAME:-admin}&password=$KS_PASSWORD&client_id=kubesphere&client_secret=kubesphere" | jq -r '.access_token' } # Make API call: ks_api GET/POST/PUT/DELETE <path> [body] ks_api() { local method=${1:-GET} local path=$2 local body=$3 local token=$(ks_token) curl -s -X "$method" \ -H "Authorization: Bearer $token" \ -H "Content-Type: application/json" \ ${body:+-d "$body"} \ "$KS_HOST$path" }
Query Commands:
bash# List all clusters (host + member clusters) ks_api GET /kapis/cluster.kubesphere.io/v1alpha1/clusters | jq -r '.items[].metadata.name' # List installed extensions ks_api GET /kapis/kubesphere.io/v1alpha1/extensions | jq -r '.items[].metadata.name' | grep -i kruise # List available extension versions ks_api GET /kapis/kubesphere.io/v1alpha1/extensionversions | jq -r '.items[].metadata.name' | grep -i kruise # Get OpenKruise extension details ks_api GET /kapis/kubesphere.io/v1alpha1/extensions/openkruise | jq # Get cluster connection status (for member clusters) ks_api GET /kapis/cluster.kubesphere.io/v1alpha1/clusters/member-4/status | jq '.conditions'
bash# Get pods in host cluster ks_api GET /clusters/host/api/v1/namespaces/kruise-system/pods | jq -r '.items[].metadata.name' # Get SidecarSets in host cluster (cluster-wide) ks_api GET /clusters/host/kapis/apps.kruise.io/v1alpha1/users/admin/sidecarsets | jq -r '.items[].metadata.name' # Get CloneSets in host cluster (cluster-wide) ks_api GET /clusters/host/kapis/apps.kruise.io/v1alpha1/users/admin/clonesets | jq -r '.items[].metadata.name' # Get SidecarSets in specific namespace ks_api GET /clusters/host/kapis/apps.kruise.io/v1alpha1/namespaces/default/sidecarsets | jq -r '.items[].metadata.name' # Get namespaces where a SidecarSet is applied ks_api GET /clusters/host/kapis/apps.kruise.io/v1alpha1/users/admin/sidecarsetname/side1 | jq -r '.items[].metadata.name' # Get specific SidecarSet details ks_api GET /clusters/host/kapis/apps.kruise.io/v1alpha1/users/admin/sidecarsets/side1 | jq # Get CRDs in host cluster ks_api GET /clusters/host/apis/apiextensions.k8s.io/v1/customresourcedefinitions | jq -r '.items[] | select(.metadata.name | contains("kruise")) | .metadata.name'
bash# Get pods in member cluster ks_api GET /clusters/member-4/api/v1/namespaces/kruise-system/pods | jq -r '.items[].metadata.name' # Get SidecarSets in member cluster (cluster-wide) ks_api GET /clusters/member-4/kapis/apps.kruise.io/v1alpha1/users/admin/sidecarsets | jq -r '.items[].metadata.name' # Get CloneSets in member cluster (cluster-wide) ks_api GET /clusters/member-4/kapis/apps.kruise.io/v1alpha1/users/admin/clonesets | jq -r '.items[].metadata.name' # Get CRDs in member cluster ks_api GET /clusters/member-4/apis/apiextensions.k8s.io/v1/customresourcedefinitions | jq -r '.items[] | select(.metadata.name | contains("kruise")) | .metadata.name'
API Path Format:
# For KubeSphere extension management:
/kapis/kubesphere.io/v1alpha1/extensions
/kapis/cluster.kubesphere.io/v1alpha1/clusters
# For cluster-wide OpenKruise resources (SidecarSet, CloneSet):
/clusters/{cluster}/kapis/apps.kruise.io/v1alpha1/users/admin/{resources}
/clusters/{cluster}/kapis/apps.kruise.io/v1alpha1/users/admin/{resources}/{name}
/clusters/{cluster}/kapis/apps.kruise.io/v1alpha1/users/admin/sidecarsetname/{sidecarsetName}
/clusters/{cluster}/api/v1/namespaces/{namespace}/{resources}
/clusters/{cluster}/apis/apiextensions.k8s.io/v1/customresourcedefinitionsQuery Parameters:
page - Page number (default: 1)limit - Items per pageascending - Sort direction (default: false)sortBy - Sort field (e.g., createTime)Use kubectl for direct Kubernetes resource operations on the host cluster.
bash# Extension and version discovery in KubeSphere kubectl get extensions.kubesphere.io | grep -i kruise kubectl get extensionversions.kubesphere.io | grep -i kruise kubectl get extensionversions.kubesphere.io -l kubesphere.io/extension-ref=openkruise # InstallPlan and extension status kubectl get installplans.kubesphere.io kubectl get installplan openkruise -o yaml kubectl describe extension openkruise kubectl describe extensionversion openkruise-<version> # OpenKruise runtime resources kubectl api-resources --api-group apps.kruise.io kubectl get crd | grep -E 'clonesets.apps.kruise.io|sidecarsets.apps.kruise.io' kubectl get pods -A | grep -i kruise kubectl get sidecarsets.apps.kruise.io -A kubectl get clonesets.apps.kruise.io -A
For querying member clusters, extract the kubeconfig from the Cluster resource:
bash# Get kubeconfig for a member cluster CLUSTER_NAME=member-4 KUBECONFIG_ENCODED=$(kubectl get cluster.cluster.kubesphere.io $CLUSTER_NAME -o jsonpath='{.spec.connection.kubeconfig}') echo "$KUBECONFIG_ENCODED" | base64 -d > /tmp/${CLUSTER_NAME}-kubeconfig # Query member cluster export KUBECONFIG=/tmp/${CLUSTER_NAME}-kubeconfig kubectl get pods -n kruise-system kubectl get sidecarsets.apps.kruise.io -A kubectl get clonesets.apps.kruise.io -A # Switch back to host cluster export KUBECONFIG=""
| Scenario | Recommended Approach | |----------|---------------------| | Query KubeSphere extension status | KubeSphere API (curl) | | List available clusters | KubeSphere API (curl) | | Query host cluster Kubernetes resources | kubectl | | Query member cluster Kubernetes resources | kubeconfig extraction | | Create/apply InstallPlan/SidecarSet/CloneSet | kubectl | | Get extension version info | KubeSphere API (curl) |
bashkubectl get extension openkruise kubectl get extensionversions.kubesphere.io -l kubesphere.io/extension-ref=openkruise kubectl describe extensionversion openkruise-<exact-version>
Check:
1.0.3 maps to OpenKruise runtime 1.4.0Use this when the user has already confirmed the extension name and version.
Note:
clusterScheduling.placement.clusters specifies which clusters the extension agent components should be installed to (host, member-4, etc.)yamlapiVersion: kubesphere.io/v1alpha1 kind: InstallPlan metadata: name: openkruise spec: enabled: true extension: name: openkruise version: <exact-version> upgradeStrategy: Manual # config: | # featureGates: "PreDownloadImageForInPlaceUpdate=true" clusterScheduling: placement: clusters: - host - member-4 # overrides: # host: |- # featureGates: "PreDownloadImageForInPlaceUpdate=true"
Fields:
clusterScheduling.placement.clusters: List of clusters to install the extension agent (e.g., host, member-4). The OpenKruise agent will be deployed to these clusters.clusterScheduling.overrides: Cluster-specific config overrides (optional)Apply and verify:
bashkubectl apply -f installplan-openkruise.yaml kubectl get installplan openkruise -w kubectl describe installplan openkruise kubectl get extension openkruise -o yaml
Check installation status per cluster:
bashkubectl get installplan openkruise -o jsonpath='{.status.clusterSchedulingStatuses}'
spec.config is a YAML string block, not a nested object. Only include it when the user asks for non-default settings.
yamlspec: config: | featureGates: "PreDownloadImageForInPlaceUpdate=true"
Rules:
config: | must itself be valid YAMLUseful discovery commands:
bashkubectl describe extensionversion openkruise-<extension-version> kubectl get extensionversion openkruise-<extension-version> -o yaml
bashTARGET_NS=$(kubectl get installplan openkruise -o jsonpath='{.status.targetNamespace}') JOB_NAME=$(kubectl get installplan openkruise -o jsonpath='{.status.jobName}') kubectl get pods -n "${TARGET_NS:-kruise-system}" kubectl logs -n "${TARGET_NS:-kruise-system}" -l job-name="$JOB_NAME" --tail=200 kubectl logs -n "${TARGET_NS:-kruise-system}" deploy/kruise-manager --tail=200 kubectl get crd | grep -E 'clonesets.apps.kruise.io|sidecarsets.apps.kruise.io'
Use SidecarSet when the user wants cluster-level sidecar injection and separate lifecycle management for sidecars.
yamlapiVersion: apps.kruise.io/v1alpha1 kind: SidecarSet metadata: name: log-agent spec: selector: matchLabels: app: demo namespaceSelector: matchLabels: kubernetes.io/metadata.name: demo-project containers: - name: log-agent image: fluent/fluent-bit:2.2 imagePullPolicy: IfNotPresent env: - name: LOG_LEVEL value: info volumeMounts: - name: varlog mountPath: /var/log podInjectPolicy: BeforeAppContainer volumes: - name: varlog hostPath: path: /var/log updateStrategy: type: RollingUpdate maxUnavailable: 1
Common operations:
bashkubectl apply -f sidecarset.yaml kubectl get sidecarset log-agent -o yaml kubectl describe sidecarset log-agent kubectl delete sidecarset log-agent
Verify injection:
bashkubectl get pods -n demo-project -l app=demo kubectl get pod <pod-name> -n demo-project -o jsonpath='{.spec.containers[*].name}' kubectl describe pod <pod-name> -n demo-project
SidecarSet troubleshooting checks:
spec.selector matches the workload Pod labelsnamespaceSelector matches the target namespace labelskruise-manager webhook is healthyUse CloneSet when the user wants an enhanced workload with in-place image updates, batch rollout, or richer update controls than Deployment.
yamlapiVersion: apps.kruise.io/v1alpha1 kind: CloneSet metadata: name: sample-app namespace: demo-project spec: replicas: 3 selector: matchLabels: app: sample-app template: metadata: labels: app: sample-app spec: containers: - name: app image: nginx:1.25 imagePullPolicy: IfNotPresent ports: - containerPort: 80 updateStrategy: type: InPlaceIfPossible partition: 0% maxUnavailable: 1
Common operations:
bashkubectl apply -f cloneset.yaml kubectl get cloneset sample-app -n demo-project kubectl describe cloneset sample-app -n demo-project kubectl delete cloneset sample-app -n demo-project
Verify rollout state:
bashkubectl get pods -n demo-project -l app=sample-app -o wide kubectl get events -n demo-project --sort-by=.lastTimestamp
When the user asks for "in-place update" or an in-place image update:
spec.updateStrategy.type: InPlaceIfPossiblespec.template.spec.containersbashkubectl get cloneset sample-app -n demo-project -o yaml > cloneset.yaml # edit image and, if needed, updateStrategy.partition kubectl apply -f cloneset.yaml kubectl describe cloneset sample-app -n demo-project kubectl get pods -n demo-project -l app=sample-app -o wide
Use partition to keep part of the Pods on the old revision during a rollout.
partition: 100% means keep all replicas on the old revisionpartition: 50% means only half of the replicas move to the new revisionpartition: 0% means finish the rolloutExample rollout sequence:
partition: 100%partition: 50%partition: 0%At each step, verify Pod revision movement:
bashkubectl get cloneset sample-app -n demo-project -o yaml kubectl get pods -n demo-project -l app=sample-app -o wide
updateStrategy.type is InPlaceIfPossible or InPlaceOnlybashkubectl describe cloneset sample-app -n demo-project kubectl get pods -n demo-project -l app=sample-app -o wide kubectl get events -n demo-project --sort-by=.lastTimestamp
Check whether workloads still depend on OpenKruise resources before uninstalling the extension:
bashkubectl get sidecarsets.apps.kruise.io -A kubectl get clonesets.apps.kruise.io -A
If these resources still exist, tell the user to migrate or remove them first.
bashkubectl delete installplan openkruise kubectl get installplan openkruise kubectl get pods -n kruise-system | grep -i kruise
If the user wants full cleanup, remind them to handle application resources first:
SidecarSet and CloneSet resources that are still in usebashkubectl describe installplan openkruise kubectl get installplan openkruise -o jsonpath='{.status.conditions}' kubectl get extension openkruise -o yaml kubectl get extensionversion openkruise-<version> -o yaml
bashkubectl get pods -A | grep -i kruise kubectl describe pod -n kruise-system <pod-name> kubectl logs -n kruise-system deploy/kruise-manager --tail=200 kubectl get events -n kruise-system --sort-by=.lastTimestamp
bashkubectl get crd clonesets.apps.kruise.io sidecarsets.apps.kruise.io kubectl describe crd clonesets.apps.kruise.io kubectl describe crd sidecarsets.apps.kruise.io kubectl api-resources --api-group apps.kruise.io
Likely causes:
Safe next actions:
InstallPlan state and conditionskruise-manager logsbashkubectl get mutatingwebhookconfigurations,validatingwebhookconfigurations | grep -i kruise kubectl describe mutatingwebhookconfiguration | grep -i -A5 kruise kubectl describe validatingwebhookconfiguration | grep -i -A5 kruise kubectl logs -n kruise-system deploy/kruise-manager --tail=200
Likely causes:
kruise-manager Pod is not ReadySidecarSet selectorsSafe next actions:
kruise-manager Pod readiness and recent restartsSidecarSetbashkubectl get sidecarset -A kubectl get sidecarset <name> -o yaml kubectl get pod <pod-name> -n <namespace> -o yaml kubectl get namespace <namespace> --show-labels
bashkubectl describe cloneset <name> -n <namespace> kubectl get pods -n <namespace> -l app=<label> -o wide kubectl get events -n <namespace> --sort-by=.lastTimestamp
Match the answer to the user intent:
InstallPlan manifestkubectl commands, grouped by purposeSidecarSet request: one executable manifest plus apply, verify, and delete commandsCloneSet request: one executable manifest plus rollout guidance for in-place update or partition-based rollout| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-20 | fail→fail | 15,449 | 10,071 | -35% | 1 | 1 | 0% | 2,956 | 7,978 | +170% | 0 | 0 | — |
case-01 | fail→pass | 11,542 | 6,361 | -45% | 1 | 1 | 0% | 2,184 | 7,474 | +242% | 0 | 0 | — |
case-02 | fail→fail | 11,214 | 8,809 | -21% | 1 | 1 | 0% | 2,149 | 7,868 | +266% | 0 | 0 | — |
case-03 | fail→fail | 36,363 | 10,222 | -72% | 1 | 1 | 0% | 572 | 8,117 | +1319% | 0 | 0 | — |
case-04 | fail→pass | 4,117 | 6,988 | +70% | 1 | 1 | 0% | 771 | 7,343 | +852% | 0 | 0 | — |
case-05 | fail→pass | 2,399 | 4,031 | +68% | 1 | 1 | 0% | 376 | 6,649 | +1668% | 0 | 0 | — |
case-06 | pass→pass | 68,914 | 6,775 | -90% | 1 | 1 | 0% | 2,578 | 7,257 | +181% | 0 | 0 | — |
case-21 | fail→fail | 11,577 | 9,690 | -16% | 1 | 1 | 0% | 2,209 | 7,980 | +261% | 0 | 0 | — |
case-07 | fail→pass | 18,665 | 9,624 | -48% | 1 | 1 | 0% | 3,772 | 7,942 | +111% | 0 | 0 | — |
case-08 | pass→pass | 10,763 | 7,887 | -27% | 1 | 1 | 0% | 1,884 | 7,586 | +303% | 0 | 0 | — |
case-09 | fail→pass | 6,476 | 5,739 | -11% | 1 | 1 | 0% | 1,372 | 7,062 | +415% | 0 | 0 | — |
case-10 | pass→pass | 10,732 | 4,431 | -59% | 1 | 1 | 0% | 1,949 | 6,986 | +258% | 0 | 0 | — |
case-11 | fail→pass | 13,746 | 5,187 | -62% | 1 | 1 | 0% | 2,488 | 6,962 | +180% | 0 | 0 | — |
case-12 | fail→pass | 10,189 | 6,772 | -34% | 1 | 1 | 0% | 1,661 | 7,365 | +343% | 0 | 0 | — |
case-13 | fail→pass | 11,588 | 6,581 | -43% | 1 | 1 | 0% | 2,075 | 6,953 | +235% | 0 | 0 | — |
case-14 | fail→pass | 10,809 | 13,374 | +24% | 1 | 1 | 0% | 1,858 | 7,598 | +309% | 0 | 0 | — |
case-15 | fail→pass | 13,442 | 5,736 | -57% | 1 | 1 | 0% | 2,144 | 7,004 | +227% | 0 | 0 | — |
case-16 | pass→pass | 11,990 | 6,331 | -47% | 1 | 1 | 0% | 2,105 | 7,246 | +244% | 0 | 0 | — |
case-17 | fail→pass | 10,616 | 3,945 | -63% | 1 | 1 | 0% | 1,794 | 6,708 | +274% | 0 | 0 | — |
case-18 | pass→pass | 15,618 | 11,980 | -23% | 1 | 1 | 0% | 2,590 | 7,959 | +207% | 0 | 0 | — |
case-19 | pass→pass | 12,306 | 9,651 | -22% | 1 | 1 | 0% | 2,324 | 7,345 | +216% | 0 | 0 | — |
case-22 | fail→fail | 13,802 | 10,426 | -24% | 1 | 1 | 0% | 2,318 | 7,767 | +235% | 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. The headline lift of +50 percentage points is the difference between those two pass rates over the 22 comparable cases.
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.