From ae2dec6eae2b1c3e7d4f54fb43b0cf1b01ed6318 Mon Sep 17 00:00:00 2001 From: Mehdy Bohlool Date: Thu, 31 May 2018 00:28:45 -0700 Subject: [PATCH] CRD versioning Public Documentation --- .../custom-resource-definition-versioning.md | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 content/en/docs/tasks/access-kubernetes-api/custom-resource-definition-versioning.md diff --git a/content/en/docs/tasks/access-kubernetes-api/custom-resource-definition-versioning.md b/content/en/docs/tasks/access-kubernetes-api/custom-resource-definition-versioning.md new file mode 100644 index 0000000000000..b30249817f74f --- /dev/null +++ b/content/en/docs/tasks/access-kubernetes-api/custom-resource-definition-versioning.md @@ -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: . + name: crontabs.stable.example.com +spec: + # group name to use for REST API: /apis// + 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/// + 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 %}}