Kubernetes Search adds five search commands. Four of them - k8s, k8slogs, k8sevents, and k8sdescribe - are generating commands: they start a search (they go first, after the leading |) and produce rows from the live Kubernetes API. The fifth, k8syaml, is a streaming formatter you pipe results into.
All four generating commands require the run_k8s_search capability. See Access control.
Conventions shared by all commands
A few arguments and behaviors work the same everywhere, so they’re documented once here.
Resource kinds (kind=). Anywhere a kind is accepted you can use the canonical name (Pod, Deployment), lowercase (pod), plural (pods, deployments), or the short name (po, deploy). The command resolves the kind and its API version through the cluster’s discovery API, so you rarely need api_version=. Append /<name> to address a single object: kind=pods/payments-api-7d9f8.
Namespaces (namespace=). Accepts an exact name (payments), * for all namespaces, or a glob (prod-*, *-system). A glob or * is expanded client-side into one query per namespace, so a wide pattern over many namespaces means more API calls.
Clusters (context=). Targets the cluster you registered under that name. A glob (prod-*) or * fans out to every matching cluster in parallel, and every result row carries a cluster field naming the one it came from. Without context=, the command uses your single registered cluster (or errors if you have several and didn’t pick one). See Clusters.
concurrency= (default 8) caps how many clusters are queried at once during a fan-out.
cache= overrides the freshness of the on-disk result cache for this search: cache=0 bypasses it and always hits the API; cache=5m accepts a result up to five minutes old. Rows from | k8s, | k8sevents, and | k8sdescribe report _cache_hit (true/false) and, on a hit, _cache_age_seconds (| k8slogs reads log content live, so its rows don’t carry them). See Concepts - caching.
Errors are per-cluster. During a fan-out, a cluster that fails (unreachable, expired credential, RBAC denial) emits a single error row and the search continues against the others, so one bad cluster never sinks the whole query.
| k8s - list and get resources
Use k8s whenever you’d reach for kubectl get. It lists resources of a kind, or fetches one object by name, and emits one row per object with the full JSON in _raw.
| k8s kind=<kind>[/<name>]
[api_version=<group/version>]
[namespace=<name|*|glob>]
[labels=<selector>] [fields=<selector>]
[view=metadata] [limit=<int>]
[context=<name|*|glob>] [concurrency=<int>] [cache=<duration>]| Argument | Description |
|---|---|
kind= | Required. Resource kind, optionally /<name> for a single object. |
api_version= | Pin the API version (e.g. apps/v1). Defaults to what discovery reports. |
namespace= | Namespace, *, or glob. Required for namespaced kinds in list form. |
labels= | Server-side label selector, e.g. app=payments,tier=api. |
fields= | Server-side field selector, e.g. status.phase=Running. |
view=metadata | Return the object’s metadata only - no spec or status - lighter and faster when you don’t need them. |
limit= | Cap the total number of rows emitted across all namespaces and clusters. |
Key fields on each row: kind, name, namespace, and _raw (the full object JSON, ready for spath).
List pods in a namespace:
| k8s kind=pods namespace=paymentsGet one object:
| k8s kind=pods/payments-api-7d9f8 namespace=paymentsFilter server-side with a label selector, then summarize:
| k8s kind=pods namespace=payments labels=app=payments-api
| spath path=status.phase output=phase
| stats count by phaseFind pods that aren’t Running, cluster-wide:
| k8s kind=pods namespace=* fields=status.phase!=Running
| table namespace nameCheap inventory across every cluster (metadata only):
| k8s kind=deployments namespace=* view=metadata context=*
| stats count by clusterRead a custom resource (discovery resolves the group automatically):
| k8s kind=certificates namespace=webportal| k8slogs - pod logs
Use k8slogs like kubectl logs. It returns a snapshot of container logs at query time - one row per log line, with the line text in _raw. There is no live follow; re-run to see newer lines.
| k8slogs namespace=<name> pods=<pattern>
[containers=<pattern>]
[tail=<int>] [since=<duration>] [previous=<bool>]
[context=<name|*|glob>] [concurrency=<int>]| Argument | Description |
|---|---|
namespace= | Required. The namespace to read from. |
pods= | Required. Wildcard pattern matching pod names, e.g. payments-api-* or *proxy*. |
containers= | Wildcard pattern for container names (default *). Matches init, regular, and ephemeral containers. |
tail= | Return only the last N lines per container (like kubectl --tail). |
since= | Only lines newer than this. Go duration: 30s, 5m, 2h. |
previous= | true returns the log of the previous, crashed instance of the container (like kubectl --previous). |
Key fields: pod, container, _time (the log line’s own timestamp), and _raw (the line).
Last 200 lines from every pod of a deployment:
| k8slogs namespace=payments pods=payments-api-* tail=200Why did it crash - read the previous container’s log:
| k8slogs namespace=payments pods=payments-api-7d9f8 previous=trueErrors in the last 15 minutes across a whole namespace:
| k8slogs namespace=webportal pods=* since=15m
| search "ERROR" OR "panic"
| table _time pod container _rawJust the gateway sidecar across both clusters:
| k8slogs namespace=payments pods=payments-api-* containers=*gateway* context=prod-* tail=100| k8sevents - cluster events
Kubernetes events explain why things happened: why a pod won’t schedule, why an image pull failed, why a deployment rolled. k8sevents lists them, with server-side filtering by type, reason, and the object they target.
| k8sevents [namespace=<name|*|glob>]
[type=<Normal|Warning>] [reason=<string>]
[for=<kind>[/<name>]]
[context=<name|*|glob>] [concurrency=<int>]| Argument | Description |
|---|---|
namespace= | Namespace, * for cluster-wide, or glob. Defaults to the cluster’s configured namespace. |
type= | Normal or Warning. Omit for both. |
reason= | Event reason code, e.g. Failed, BackOff, FailedScheduling, SuccessfulCreate. |
for= | Restrict to events about one object: Pod/payments-api-7d9f8, or a bare kind like Node for all events of that kind. |
Key fields: type, reason, message, involved_kind, involved_name, involved_namespace, count, first_timestamp, last_timestamp.
Kubernetes keeps events for about an hour by default.
k8seventsreturns what the API server still has, not a full history.
All warnings in a namespace:
| k8sevents namespace=payments type=WarningCluster-wide scheduling failures right now:
| k8sevents namespace=* reason=FailedScheduling
| table involved_namespace involved_name message countEverything Kubernetes has to say about one pod:
| k8sevents for=Pod/payments-api-7d9f8 namespace=paymentsWarnings across every cluster, grouped:
| k8sevents namespace=* type=Warning context=*
| stats count by cluster reason| k8sdescribe - object and its events
k8sdescribe mirrors kubectl describe: it fetches a single object and the events that reference it, in one search. It always addresses one object, so kind= takes the Kind/Name form.
| k8sdescribe kind=<kind>/<name> [namespace=<name>]
[api_version=<group/version>]
[context=<name|*|glob>] [concurrency=<int>]| Argument | Description |
|---|---|
kind= | Required. A single object as Kind/Name, e.g. pod/payments-api-7d9f8 or deploy/payments-api. |
namespace= | Required for namespaced kinds. Ignored for cluster-scoped kinds (Node, Namespace, PersistentVolume). |
api_version= | Pin the API version. Defaults to discovery. |
Rows carry a _describe_section field: object for the resource itself and event for each related event. Event rows have the same fields as | k8sevents, plus target_kind, target_name, and target_namespace naming the object they describe. Split them with where:
| k8sdescribe kind=pod/payments-api-7d9f8 namespace=payments
| where _describe_section="event"
| table _time type reason messageDescribe a node (cluster-scoped, no namespace):
| k8sdescribe kind=node/ip-10-2-14-7Describe the same deployment across clusters:
| k8sdescribe kind=deploy/payments-api namespace=payments context=*| k8syaml - format JSON as YAML
The generating commands return JSON in _raw. Pipe through k8syaml to read it the way kubectl get -o yaml shows it. This is a streaming command - it transforms rows, it doesn’t fetch anything.
... | k8syaml [field=<field>] [output=<field>]| Argument | Description |
|---|---|
field= | Input field holding the JSON (default _raw). |
output= | Field to write the YAML to (default: rewrite the input field in place). |
Rows whose field is empty or isn’t JSON pass through untouched.
Read a pod as YAML:
| k8s kind=pods/payments-api-7d9f8 namespace=payments
| k8syamlKeep the JSON, add a YAML column:
| k8s kind=pods namespace=payments
| k8syaml field=_raw output=yamlRecipes
A few patterns that combine the commands with everyday SPL.
Pods stuck pending, with the reason:
| k8s kind=pods namespace=* fields=status.phase=Pending view=metadata
| eval key=namespace.":".name
| join key
[ | k8sevents namespace=* reason=FailedScheduling
| eval key=involved_namespace.":".involved_name ]
| table namespace name messageRestart counts across a cluster, worst first:
| k8s kind=pods namespace=*
| spath path=status.containerStatuses{}.restartCount output=restarts
| stats sum(restarts) as restarts by namespace name
| sort - restartsCorrelate ingested logs with live state during an incident - search what Monitoring Kubernetes already stored, then describe the offending pod as it is right now, in the same session:
index=kubernetes namespace=payments "OOMKilled" earliest=-1h
| stats count by pod_name| k8sdescribe kind=pod/payments-api-7d9f8 namespace=paymentsThis pairing - history from ingestion, current state from Kubernetes Search - is the heart of why you’d run both.