Kubernetes preferred vs storage API versions

Preferred Version

This is the version Kubernetes serves by default when a client queries the API (like with kubectl get).

To determine the preferred version of resources in a cluster:

kubectl proxy 8001 &
curl localhost:8001/apis/<api-group>

Example output:

{
  "kind": "APIGroup",
  "apiVersion": "v1",
  "name": "<api-group>",
  "versions": [
    {
      "groupVersion": "<api-group>",
      "version": "v1"
    }
  ],
  "preferredVersion": {
    "groupVersion": "<api-group>",
    "version": "v1"  <-- preferred version
  }
}

Storage Version

This is the version that Kubernetes uses to persist (store) an object in the cluster database (i.e. etcd).

Internally, no matter what version a client used to create or update the object, Kubernetes will convert the object to the storage version before saving it.

The storage version is not currently available via kubectl commands. To determine the storage version of resources in a cluster, it is instead necessary to query the etcd database itself:

ETCDCTL_API=3 etcdctl \
 --endpoints=https://127.0.0.1:2379 \
 --cacert=/etc/kubernetes/pki/etcd/server.crt \
 --cert=/etc/kubernetes/pki/etcd/server.key \
 get "/registry/<resource>/<namespace>/<name>" \
 --print-value-only 

Example output:

k8s

apps/v1  <-- storage version
<resource>

<...>

References

Mannambeth, M., & Palazhi, V. (2024, December). Kubernetes Certified Application Developer (CKAD) with Tests. Udemy.

When you have multiple versions enabled and you run the kubectl get deployment command which version is the command going to query? That's defined by the preferred version... Also, when multiple versions are present, only one version can be the storage version. This means if any object is created with the API version set to anything other than the storage version... then those will be converted to the storage version.