skip to content

Using kubectl, how do you find which API group and version a Kubernetes resource kind is served at, and which fields it accepts?

level: juniorimportance: should knowfreq 58%

answer

  1. ask the cluster, not the docs
  2. discovery behind three subcommands
  3. resources, versions, then fields
  4. core group name is empty
  5. --api-version picks a schema

basics

~10 s

Run kubectl api-resources to list each resource's group/version, kind, short name and scope, kubectl api-versions to list every served group/version, and kubectl explain to read the fields the cluster's published schema accepts.

solid answer

~40 s

Kubernetes clients discover the API from the running cluster, so kubectl asks the server rather than using a built-in list. `kubectl api-resources` prints `NAME`, `SHORTNAMES`, `APIVERSION`, `NAMESPACED` and `KIND` per resource: `deployments` is `apps/v1`, `pods` is plain `v1` because the core group's name is empty. `--api-group`, `--namespaced` and `-o wide` (adding verbs and categories) narrow or widen that list. `kubectl api-versions` prints every `group/version` the server serves, which is how you check that a version in a manifest still exists. `kubectl explain deployment.spec.strategy` prints field documentation from the server's OpenAPI schema, and `--api-version` selects a version when a kind is served at more than one. All three read the live cluster, so they include CRDs and aggregated APIs.

code

bash · 5 lines
bash
kubectl api-resources --api-group=autoscaling
kubectl api-resources --namespaced=false -o wide
kubectl api-versions | grep '^autoscaling/'
kubectl explain hpa.spec --api-version=autoscaling/v2
kubectl explain deployment.spec.strategy --recursive

go deeper

for a junior

Recall the three commands and what each prints, and be able to say why a Pod is v1 while a Deployment is apps/v1.

for a middle

Explain that the answers come from the cluster's discovery data and OpenAPI schema, so CRDs, aggregated APIs and disabled versions all show up differently per cluster.

for a senior

Use api-versions and explain --api-version as a pre-flight check in pipelines, so a manifest naming an unserved version fails before a deploy rather than during it.

for a principal

Treat discovery as the contract between platform and tenants: document which groups and versions the platform serves and how CRD groups are named across teams.

## Why Kubernetes makes clients discover the API A Kubernetes cluster does not serve a fixed, universal list of object types. Which resources exist, and at which **API versions**, depends on the release, on which versions the operator switched on with kube-apiserver's `--runtime-config` flag, on the **CustomResourceDefinitions** (CRDs) installed and on any **aggregated APIs** registered. So `kubectl` and client libraries ask the running cluster, through a mechanism called **discovery**, before they send a manifest. Three `kubectl` subcommands expose that discovery data to a person: `api-resources`, `api-versions` and `explain`. ## Group, version and kind in one manifest Every object names its type with two top-level fields: - `apiVersion` holds `group/version`, for example `apps/v1`. - `kind` holds the type name, for example `Deployment`. The **core group** is the original API. Its name is the empty string, so its `apiVersion` is written as just `v1`, and it is served under the `/api/v1` URL prefix. Every other group is a **named group**, served under `/apis/<group>/<version>`. | Kind | apiVersion | Group | URL prefix | |---|---|---|---| | Pod, Service, ConfigMap | `v1` | core (`""`) | `/api/v1` | | Deployment, StatefulSet | `apps/v1` | `apps` | `/apis/apps/v1` | | Job, CronJob | `batch/v1` | `batch` | `/apis/batch/v1` | | Ingress, NetworkPolicy | `networking.k8s.io/v1` | `networking.k8s.io` | `/apis/networking.k8s.io/v1` | A **kind** is singular and CamelCase (`Deployment`); a **resource** is the lowercase plural used in URLs and in `kubectl get` (`deployments`). Discovery is what maps one onto the other. ## kubectl api-resources `kubectl api-resources` prints one row per resource with the columns `NAME`, `SHORTNAMES`, `APIVERSION`, `NAMESPACED` and `KIND`. For a team running a loyalty-points accrual service it answers questions such as "is HorizontalPodAutoscaler namespaced, and what is its short name?" in one line. Useful flags: - `--api-group=apps` lists only one group; the core group is selected with an empty value. - `--namespaced=false` lists cluster-scoped resources such as Nodes and PersistentVolumes. - `-o wide` adds the `VERBS` and `CATEGORIES` columns, showing whether a resource supports `watch`, `patch` and so on. - `--verbs=list` keeps only resources that support the named verbs. The `APIVERSION` column shows the version the server **prefers** for that group, not every version it serves. ## kubectl api-versions `kubectl api-versions` prints every `group/version` pair the server serves, one per line, such as `autoscaling/v1`, `autoscaling/v2` and `v1`. It is the quickest check before applying an old manifest: if the version in the file is not in this list, the apply fails with an error of the form `no matches for kind "HorizontalPodAutoscaler" in version "autoscaling/v2beta2"`. ## kubectl explain `kubectl explain` prints field documentation taken from the **OpenAPI schema** the API server publishes, so it describes exactly what this cluster accepts: 1. `kubectl explain deployment` shows the top-level fields and the group/version being described. 2. `kubectl explain deployment.spec.strategy.rollingUpdate` walks down a dotted field path. 3. `kubectl explain hpa --api-version=autoscaling/v1` picks a specific version when a kind is served at more than one, which matters because fields differ between versions. 4. `--recursive` prints the whole field tree, and `--max-depth` caps how deep it goes. Because the schema comes from the server, CRDs that publish a structural schema are explained the same way as built-in kinds. ## How group names are chosen The oldest named groups have short names: `apps`, `batch`, `autoscaling`, `policy`. Later built-in groups end in `k8s.io`, such as `networking.k8s.io`, `rbac.authorization.k8s.io` and `storage.k8s.io`. The `k8s.io` and `kubernetes.io` suffixes are reserved for the Kubernetes project: a CRD in such a group must carry the `api-approved.kubernetes.io` annotation. A CRD's group must be a domain with at least one dot, so a team uses its own domain, for example `loyalty.example.com`. ## Traps worth naming - Writing `apiVersion: core/v1`: there is no group called `core`; the core group is the empty string. - Reading a version from documentation for another release instead of asking the cluster. - Treating the `APIVERSION` column as the full list of served versions; use `api-versions` for that. - Forgetting that the lists include CRDs and aggregated APIs, so two clusters on the same release can differ. - Reading a `no matches for kind` error as a typo only: it also appears when a CRD is not installed yet, or when the version in the file is no longer served. ## A short routine before applying an unfamiliar manifest When a manifest for the loyalty-points service arrives from another team, three checks take seconds: confirm its `group/version` appears in `kubectl api-versions`, confirm the kind appears in `kubectl api-resources` with the expected scope, and run `kubectl explain` with `--api-version` on any field you do not recognise. Together they catch most apply failures before the pipeline reaches the cluster.

  • Why does a Pod manifest say apiVersion v1 while a Deployment says apps/v1?
    `apiVersion` is `group/version`. Pods belong to the **core group**, the original API, whose name is the empty string, so only the version is written and it is served under `/api/v1`. Deployments belong to the named group `apps`, served under `/apis/apps/v1`. `core/v1` is not a valid `apiVersion`; `core` is only an informal name.
  • How are built-in API group names chosen, and what does that mean for a CRD's group?
    Early groups have short names such as `apps`, `batch` and `policy`; later built-in groups end in `k8s.io`, such as `networking.k8s.io` and `storage.k8s.io`. The `k8s.io` and `kubernetes.io` suffixes are reserved for the project, and a CRD there needs the `api-approved.kubernetes.io` annotation. A CRD group must be a domain with at least one dot, so teams use their own domain.

saying these in an interview costs you the question

  • Believes kubectl ships a fixed list of resources and versions
  • Writes apiVersion core/v1 in a Pod manifest
  • Reads field names from docs for a different Kubernetes release
  • Thinks api-resources lists only built-in kinds, never CRDs
  • Confuses the resource name deployments with the kind Deployment