Get a specific apiVersion manifest from k8s
Tags: devops, kubernetes, k8s
Published: 2024-03-19 16:53:38

## TL;DR
> To get a manifest from k8s in any supported API version you can use an extended `kubectl get` notation like `kubectl get deployments.v1beta1.extensions mydeploy -o yaml`

## Briefly and with examples
Everybody knows how to get a resource manifest from Kubernetes. But do you know that you can put a manifest with one `apiVersion` set and get the same resource manifest with another `apiVersion` back?

### Imagine

1. You have a `deployment` in a cluster, that uses `api-version extensions/v1beta1` from a git repo.
1. You've updated the cluster (1.15 => 1.16). Old deployment works fine, but you can't deploy nothing new with the old manifest because in k8s 1.16 `api-version extensions/v1beta1` is absent.
1. You have two options:
   1. Rewrite it manually or
   1. Get it from the cluster in updated spec format (`apps/v1`)

To get manifest from k8s you can:
> below there is an example for v1.15, where extensions/v1beta1 is not removed yet

```bash
# from extensions
kubectl get deployments.extensions ext -o yaml
# from extensions, but for v1beta1
kubectl get deployments.v1beta1.extensions ext -o yaml
# from apps
kubectl get deployments.apps ext -o yaml
# from apps, but v1
kubectl get deployments.v1.apps ext -o yaml
```

Notice that if you do just `kubectl get deployments ext -o yaml`, you will get a manifest from `extensions/v1beta1` nevertheless you've even applied `apps/v1` before. Details [here](https://github.com/kubernetes/kubernetes/issues/58131#issuecomment-356823588).

## Prove it

1) Start 1.15

   ```bash
   minikube start --kubernetes-version=v1.15.12
   ```

2) Make 2 manifests for `deployments` with different versions. Note the absence of `spec.selector` in `extensions/v1beta1`

   ```yaml
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     creationTimestamp: null
     labels:
       run: apps
     name: apps
   spec:
     replicas: 1
     selector:
       matchLabels:
         run: apps
     template:
       metadata:
         creationTimestamp: null
         labels:
           run: apps
       spec:
         containers:
         - image: nginx
           name: apps
   ---
   apiVersion: extensions/v1beta1
   kind: Deployment
   metadata:
     labels:
       run: ext
     name: ext
   spec:
     replicas: 1
     template:
       metadata:
         creationTimestamp: null
         labels:
           run: ext
       spec:
         containers:
         - image: nginx
           name: ext
   ```
3) Apply

   ```bash
   ❯ minikube kubectl -- apply -f .
   deployment.apps/apps created
   deployment.extensions/ext created
   ```

4) Check that resources `apps` and `ext` are in `extensions/v1beta1` and in `apps/v1` too

   * The hard way - curl:

   ```bash
   ❯ minikube kubectl -- proxy
   Starting to serve on 127.0.0.1:8001
   ❯ curl -s 127.0.0.1:8001/apis/extensions/v1beta1/namespaces/default/deployments/apps | yq . --yaml-output
   kind: Deployment
   apiVersion: extensions/v1beta1
   # ...
   ❯ curl -s 127.0.0.1:8001/apis/extensions/v1beta1/namespaces/default/deployments/ext | yq . --yaml-output
   kind: Deployment
   apiVersion: extensions/v1beta1
   # ...
   ❯ curl -s 127.0.0.1:8001/apis/apps/v1/namespaces/default/deployments/apps | yq . --yaml-output
   kind: Deployment
   apiVersion: apps/v1
   # ...
   ❯ curl -s 127.0.0.1:8001/apis/apps/v1/namespaces/default/deployments/ext | yq . --yaml-output
   kind: Deployment
   apiVersion: apps/v1
   # ...
   ```

   * Or kubectl:

   ```bash
   # from extensions
   kubectl get deployments.extensions ext -o yaml
   # from extensions, but v1beta1
   kubectl get deployments.v1beta1.extensions ext -o yaml
   # from apps
   kubectl get deployments.apps ext -o yaml
   # from apps, but v1
   kubectl get deployments.v1.apps ext -o yaml
   ```

## Bonus: kubectl explain

If you do `kubectl explain deployment` than (surprise!) you'll get a description for `extensions/v1beta1`. Because `kubectl explain` [works the same way](https://github.com/kubernetes/kubernetes/issues/73062), just like `kubectl get`:

If you want a specific version, use an `--api-version` flag :

```bash
minikube kubectl -- explain deployment.spec --api-version apps/v1
minikube kubectl -- explain deployment.spec --api-version extensions/v1beta1
```