mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			222 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
 | 
						|
 | 
						|
<!-- BEGIN STRIP_FOR_RELEASE -->
 | 
						|
 | 
						|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
 | 
						|
     width="25" height="25">
 | 
						|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
 | 
						|
     width="25" height="25">
 | 
						|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
 | 
						|
     width="25" height="25">
 | 
						|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
 | 
						|
     width="25" height="25">
 | 
						|
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
 | 
						|
     width="25" height="25">
 | 
						|
 | 
						|
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
 | 
						|
 | 
						|
If you are using a released version of Kubernetes, you should
 | 
						|
refer to the docs that go with that version.
 | 
						|
 | 
						|
<strong>
 | 
						|
The latest release of this document can be found
 | 
						|
[here](http://releases.k8s.io/release-1.1/docs/design/extending-api.md).
 | 
						|
 | 
						|
Documentation for other releases can be found at
 | 
						|
[releases.k8s.io](http://releases.k8s.io).
 | 
						|
</strong>
 | 
						|
--
 | 
						|
 | 
						|
<!-- END STRIP_FOR_RELEASE -->
 | 
						|
 | 
						|
<!-- END MUNGE: UNVERSIONED_WARNING -->
 | 
						|
 | 
						|
# Adding custom resources to the Kubernetes API server
 | 
						|
 | 
						|
This document describes the design for implementing the storage of custom API types in the Kubernetes API Server.
 | 
						|
 | 
						|
 | 
						|
## Resource Model
 | 
						|
 | 
						|
### The ThirdPartyResource
 | 
						|
 | 
						|
The `ThirdPartyResource` resource describes the multiple versions of a custom resource that the user wants to add
 | 
						|
to the Kubernetes API.  `ThirdPartyResource` is a non-namespaced resource; attempting to place it in a namespace
 | 
						|
will return an error.
 | 
						|
 | 
						|
Each `ThirdPartyResource` resource has the following:
 | 
						|
   * Standard Kubernetes object metadata.
 | 
						|
   * ResourceKind - The kind of the resources described by this third party resource.
 | 
						|
   * Description - A free text description of the resource.
 | 
						|
   * APIGroup - An API group that this resource should be placed into.
 | 
						|
   * Versions - One or more `Version` objects.
 | 
						|
 | 
						|
### The `Version` Object
 | 
						|
 | 
						|
The `Version` object describes a single concrete version of a custom resource.  The `Version` object currently
 | 
						|
only specifies:
 | 
						|
   * The `Name` of the version.
 | 
						|
   * The `APIGroup` this version should belong to.
 | 
						|
 | 
						|
## Expectations about third party objects
 | 
						|
 | 
						|
Every object that is added to a third-party Kubernetes object store is expected to contain Kubernetes
 | 
						|
compatible [object metadata](../devel/api-conventions.md#metadata).  This requirement enables the
 | 
						|
Kubernetes API server to provide the following features:
 | 
						|
   * Filtering lists of objects via label queries
 | 
						|
   * `resourceVersion`-based optimistic concurrency via compare-and-swap
 | 
						|
   * Versioned storage
 | 
						|
   * Event recording
 | 
						|
   * Integration with basic `kubectl` command line tooling
 | 
						|
   * Watch for resource changes
 | 
						|
 | 
						|
The `Kind` for an instance of a third-party object (e.g. CronTab) below is expected to be
 | 
						|
programmatically convertible to the name of the resource using
 | 
						|
the following conversion.  Kinds are expected to be of the form `<CamelCaseKind>`, and the
 | 
						|
`APIVersion` for the object is expected to be `<api-group>/<api-version>`. To
 | 
						|
prevent collisions, it's expected that you'll use a fully qualified domain
 | 
						|
name for the API group, e.g. `example.com`.
 | 
						|
 | 
						|
For example `stable.example.com/v1`
 | 
						|
 | 
						|
'CamelCaseKind' is the specific type name.
 | 
						|
 | 
						|
To convert this into the `metadata.name` for the `ThirdPartyResource` resource instance,
 | 
						|
the `<domain-name>` is copied verbatim, the `CamelCaseKind` is
 | 
						|
then converted
 | 
						|
using '-' instead of capitalization ('camel-case'), with the first character being assumed to be
 | 
						|
capitalized.  In pseudo code:
 | 
						|
 | 
						|
```go
 | 
						|
var result string
 | 
						|
for ix := range kindName {
 | 
						|
  if isCapital(kindName[ix]) {
 | 
						|
    result = append(result, '-')
 | 
						|
  }
 | 
						|
  result = append(result, toLowerCase(kindName[ix])
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
As a concrete example, the resource named `camel-case-kind.example.com` defines resources of Kind `CamelCaseKind`, in
 | 
						|
the APIGroup with the prefix `example.com/...`.
 | 
						|
 | 
						|
The reason for this is to enable rapid lookup of a `ThirdPartyResource` object given the kind information.
 | 
						|
This is also the reason why `ThirdPartyResource` is not namespaced.
 | 
						|
 | 
						|
## Usage
 | 
						|
 | 
						|
When a user creates a new `ThirdPartyResource`, the Kubernetes API Server reacts by creating a new, namespaced
 | 
						|
RESTful resource path.  For now, non-namespaced objects are not supported. As with existing built-in objects,
 | 
						|
deleting a namespace deletes all third party resources in that namespace.
 | 
						|
 | 
						|
For example, if a user creates:
 | 
						|
 | 
						|
```yaml
 | 
						|
metadata:
 | 
						|
  name: cron-tab.stable.example.com
 | 
						|
apiVersion: extensions/v1beta1
 | 
						|
kind: ThirdPartyResource
 | 
						|
description: "A specification of a Pod to run on a cron style schedule"
 | 
						|
versions:
 | 
						|
- name: v1
 | 
						|
- name: v2
 | 
						|
```
 | 
						|
 | 
						|
Then the API server will program in the new RESTful resource path:
 | 
						|
   * `/apis/stable.example.com/v1/namespaces/<namespace>/crontabs/...`
 | 
						|
 | 
						|
 | 
						|
Now that this schema has been created, a user can `POST`:
 | 
						|
 | 
						|
```json
 | 
						|
{
 | 
						|
   "metadata": {
 | 
						|
     "name": "my-new-cron-object"
 | 
						|
   },
 | 
						|
   "apiVersion": "stable.example.com/v1",
 | 
						|
   "kind": "CronTab",
 | 
						|
   "cronSpec": "* * * * /5",
 | 
						|
   "image":     "my-awesome-cron-image"
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
to: `/apis/stable.example.com/v1/namespaces/default/crontabs`
 | 
						|
 | 
						|
and the corresponding data will be stored into etcd by the APIServer, so that when the user issues:
 | 
						|
 | 
						|
```
 | 
						|
GET /apis/stable.example.com/v1/namespaces/default/crontabs/my-new-cron-object`
 | 
						|
```
 | 
						|
 | 
						|
And when they do that, they will get back the same data, but with additional Kubernetes metadata
 | 
						|
(e.g. `resourceVersion`, `createdTimestamp`) filled in.
 | 
						|
 | 
						|
Likewise, to list all resources, a user can issue:
 | 
						|
 | 
						|
```
 | 
						|
GET /apis/stable.example.com/v1/namespaces/default/crontabs
 | 
						|
```
 | 
						|
 | 
						|
and get back:
 | 
						|
 | 
						|
```json
 | 
						|
{
 | 
						|
   "apiVersion": "stable.example.com/v1",
 | 
						|
   "kind": "CronTabList",
 | 
						|
   "items": [
 | 
						|
     {
 | 
						|
       "metadata": {
 | 
						|
         "name": "my-new-cron-object"
 | 
						|
       },
 | 
						|
       "apiVersion": "stable.example.com/v1",
 | 
						|
       "kind": "CronTab",
 | 
						|
       "cronSpec": "* * * * /5",
 | 
						|
       "image":     "my-awesome-cron-image"
 | 
						|
    }
 | 
						|
   ]
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
Because all objects are expected to contain standard Kubernetes metadata fields, these
 | 
						|
list operations can also use label queries to filter requests down to specific subsets.
 | 
						|
 | 
						|
Likewise, clients can use watch endpoints to watch for changes to stored objects.
 | 
						|
 | 
						|
 | 
						|
## Storage
 | 
						|
 | 
						|
In order to store custom user data in a versioned fashion inside of etcd, we need to also introduce a
 | 
						|
`Codec`-compatible object for persistent storage in etcd.  This object is `ThirdPartyResourceData` and it contains:
 | 
						|
   * Standard API Metadata
 | 
						|
   * `Data`: The raw JSON data for this custom object.
 | 
						|
 | 
						|
### Storage key specification
 | 
						|
 | 
						|
Each custom object stored by the API server needs a custom key in storage, this is described below:
 | 
						|
 | 
						|
#### Definitions
 | 
						|
 | 
						|
   * `resource-namespace`: the namespace of the particular resource that is being stored
 | 
						|
   * `resource-name`: the name of the particular resource being stored
 | 
						|
   * `third-party-resource-namespace`: the namespace of the `ThirdPartyResource` resource that represents the type for the specific instance being stored
 | 
						|
   * `third-party-resource-name`: the name of the `ThirdPartyResource` resource that represents the type for the specific instance being stored
 | 
						|
 | 
						|
#### Key
 | 
						|
 | 
						|
Given the definitions above, the key for a specific third-party object is:
 | 
						|
 | 
						|
```
 | 
						|
${standard-k8s-prefix}/third-party-resources/${third-party-resource-namespace}/${third-party-resource-name}/${resource-namespace}/${resource-name}
 | 
						|
```
 | 
						|
 | 
						|
Thus, listing a third-party resource can be achieved by listing the directory:
 | 
						|
 | 
						|
```
 | 
						|
${standard-k8s-prefix}/third-party-resources/${third-party-resource-namespace}/${third-party-resource-name}/${resource-namespace}/
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
 | 
						|
[]()
 | 
						|
<!-- END MUNGE: GENERATED_ANALYTICS -->
 |