Skip to content

Commit

Permalink
CRD versioning Public Documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mbohlool committed Jun 6, 2018
1 parent 4691ee4 commit b57b3c5
Showing 1 changed file with 154 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
title: Extend the Kubernetes API with CustomResourceDefinitions
reviewers:
- mbohlool
- sttts
- liggitt
content_template: templates/task
---

{{% capture overview %}}
This page explains how
[CustomResourceDefinition](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#customresourcedefinition-v1beta1-apiextensions) versioning works and how to upgrade from one version to another.
{{% /capture %}}

{{% capture prerequisites %}}

{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}

* Make sure your Kubernetes cluster has a master version of 1.11.0 or higher.

* Read about [custom resources](/docs/concepts/api-extension/custom-resources/).

{{% /capture %}}

{{% capture body %}}
Kubernetes standard API types has versioning to let developers extend them and roll out new features. To extend kubernetes with
Custom Resources, you should be able to do the same by supporting multiple versions of Custom Resources. CustomResourceDefinition API supports a `versions` field that can be used to list all versions for that object. Note that previous `version` field is deprecated and optional but if it is not empty, it must be the first item in the `versions` field.

For example, a CustomResourceDefinition with two versions would look like this:

```yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: crontabs.stable.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: stable.example.com
# list of versions supported by this CustomResourceDefinition
versions:
- Name: v1
# Each version can be enabled/disabled by Served flag.
Served: true
# One and only one version must be marked as storage version.
storage: true
- Name: v2
Served: true
storage: false
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
plural: crontabs
# singular name to be used as an alias on the CLI and for display
singular: crontab
# kind is normally the CamelCased singular type. Your resource manifests use this.
kind: CronTab
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- ct
```
If you save the above definition to `my-versioned-crontab.yaml` and create it:

```shell
kubectl create -f my-versioned-crontab.yaml
```

By creating this CustomResourceDefinition, API server will add endpoints for each enabled version (e.g. /apis/stable.example.com/v1 and /apis/stable.example.com/v2).

## Version order
The version name in the CustomResourceDefiniton version list is used to compute the order of versions. If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
then optionally the string "alpha" or "beta" and another number (the minor version). These are sorted first
by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
major version, then minor version. This is an example of sorted versions list:

```
- v10
- v2
- v1
- v11beta2
- v10beta3
- v3beta1
- v12alpha1
- v11alpha2
- foo1
- foo10.
```

The order of the version defines a priority for each version. Most importantly the version that comes first in term of priority
will be used by kubectl as the default version to access objects. For `my-versioned-crontab.yaml` example, the version order would be v2, v1. That means any kubectl command will use v2 as default version unless the version can be infered from the provided object.

## Conversion
Currently API Server does not do any conversions on CustomResourceDefinition other than fixing apiVersion of the object. The stored object will always have the storage version's apiVersion and return objects will have the same apiVersion as the request version.

If you save the following YAML to `my-crontab-v1.yaml`:

```yaml
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
```

and create it:

```shell
kubectl create -f my-crontab.yaml
```

it will store the object with `stable.example.com/v1` API version. However when you access the object:

```shell
kubectl get my-new-cron-object -o yaml
```

you should see the object with `stable.example.com/v2` API version as `v2` is the prefered version.

```yaml
apiVersion: stable.example.com/v2
kind: CronTab
metadata:
clusterName: ""
creationTimestamp: 2017-05-31T12:56:35Z
deletionGracePeriodSeconds: null
deletionTimestamp: null
name: my-new-cron-object
namespace: default
resourceVersion: "285"
selfLink: /apis/stable.example.com/v1/namespaces/default/crontabs/my-new-cron-object
uid: 9423255b-4600-11e7-af6a-28d2447dc82b
spec:
cronSpec: '* * * * */5'
image: my-awesome-cron-image
```

## Stored Versions
It is possible to have different versions of Custom Resources in the storage. When changing the storage version, it is
desirable to update any old version of Custom Resources to the new version. To facilitate that, API Server will record any
Version with storage flag on in an status field called `storedVersion`. Note that we may not actually have objects with all versions listed in `storedVersion` stored in backend but the list has any version that has the storage flag on sometime.
The upgrade process on the storage should modify this field and remove a version after making sure no stored object has that version. For example, this is the recommended process to upgrade storage from `v1` to `v2`:

1. Set the `v2` as storage in the CustomResourceDefinition file and apply it using kubectl. The `storedVersions` would be `v1, v2` after this step.
2. Set the `served` flag of `v1` to `false`. This will make sure no client will write `v1` objects.
3. Write a controller loop to list all existing objects and touch them (write them with the same content). This will force the backend to write objects in `v2` (storage) version.
4. Update the CustomResourceDefinition by completely removing `v1` item. This step is important. As long as `v1` is in the version list, it cannot be removed from `storedVersions`.
5. Update CustomResourceDefinition `Status` by removing `v1` from `storedVersions` field.

{{% /capture %}}

0 comments on commit b57b3c5

Please sign in to comment.