move setup konnectivity svc
move api-access to extend-kubernetes
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Extend Kubernetes"
|
||||
weight: 90
|
||||
---
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
---
|
||||
title: Configure the Aggregation Layer
|
||||
reviewers:
|
||||
- lavalamp
|
||||
- cheftako
|
||||
- chenopis
|
||||
content_type: task
|
||||
weight: 10
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
Configuring the [aggregation layer](/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) allows the Kubernetes apiserver to be extended with additional APIs, which are not part of the core Kubernetes APIs.
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
{{< note >}}
|
||||
There are a few setup requirements for getting the aggregation layer working in your environment to support mutual TLS auth between the proxy and extension apiservers. Kubernetes and the kube-apiserver have multiple CAs, so make sure that the proxy is signed by the aggregation layer CA and not by something else, like the master CA.
|
||||
{{< /note >}}
|
||||
|
||||
{{< caution >}}
|
||||
Reusing the same CA for different client types can negatively impact the cluster's ability to function. For more information, see [CA Reusage and Conflicts](#ca-reusage-and-conflicts).
|
||||
{{< /caution >}}
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
Unlike Custom Resource Definitions (CRDs), the Aggregation API involves another server - your Extension apiserver - in addition to the standard Kubernetes apiserver. The Kubernetes apiserver will need to communicate with your extension apiserver, and your extension apiserver will need to communicate with the Kubernetes apiserver. In order for this communication to be secured, the Kubernetes apiserver uses x509 certificates to authenticate itself to the extension apiserver.
|
||||
|
||||
This section describes how the authentication and authorization flows work, and how to configure them.
|
||||
|
||||
The high-level flow is as follows:
|
||||
|
||||
1. Kubernetes apiserver: authenticate the requesting user and authorize their rights to the requested API path.
|
||||
2. Kubernetes apiserver: proxy the request to the extension apiserver
|
||||
3. Extension apiserver: authenticate the request from the Kubernetes apiserver
|
||||
4. Extension apiserver: authorize the request from the original user
|
||||
5. Extension apiserver: execute
|
||||
|
||||
The rest of this section describes these steps in detail.
|
||||
|
||||
The flow can be seen in the following diagram.
|
||||
|
||||
.
|
||||
|
||||
The source for the above swimlanes can be found in the source of this document.
|
||||
|
||||
<!--
|
||||
Swimlanes generated at https://swimlanes.io with the source as follows:
|
||||
|
||||
-----BEGIN-----
|
||||
title: Welcome to swimlanes.io
|
||||
|
||||
|
||||
User -> kube-apiserver / aggregator:
|
||||
|
||||
note:
|
||||
1. The user makes a request to the Kube API server using any recognized credential (e.g. OIDC or client certs)
|
||||
|
||||
kube-apiserver / aggregator -> kube-apiserver / aggregator: authentication
|
||||
|
||||
note:
|
||||
2. The Kube API server authenticates the incoming request using any configured authentication methods (e.g. OIDC or client certs)
|
||||
|
||||
kube-apiserver / aggregator -> kube-apiserver / aggregator: authorization
|
||||
|
||||
note:
|
||||
3. The Kube API server authorizes the requested URL using any configured authorization method (e.g. RBAC)
|
||||
|
||||
kube-apiserver / aggregator -> aggregated apiserver:
|
||||
|
||||
note:
|
||||
4. The aggregator opens a connection to the aggregated API server using `--proxy-client-cert-file`/`--proxy-client-key-file` client certificate/key to secure the channel
|
||||
5. The aggregator sends the user info from step 1 to the aggregated API server as http headers, as defined by the following flags:
|
||||
* `--requestheader-username-headers`
|
||||
* `--requestheader-group-headers`
|
||||
* `--requestheader-extra-headers-prefix`
|
||||
|
||||
aggregated apiserver -> aggregated apiserver: authentication
|
||||
|
||||
note:
|
||||
6. The aggregated apiserver authenticates the incoming request using the auth proxy authentication method:
|
||||
* verifies the request has a recognized auth proxy client certificate
|
||||
* pulls user info from the incoming request's http headers
|
||||
|
||||
By default, it pulls the configuration information for this from a configmap in the kube-system namespace that is published by the kube-apiserver, containing the info from the `--requestheader-...` flags provided to the kube-apiserver (CA bundle to use, auth proxy client certificate names to allow, http header names to use, etc)
|
||||
|
||||
aggregated apiserver -> kube-apiserver / aggregator: authorization
|
||||
|
||||
note:
|
||||
7. The aggregated apiserver authorizes the incoming request by making a SubjectAccessReview call to the kube-apiserver
|
||||
|
||||
aggregated apiserver -> aggregated apiserver: admission
|
||||
|
||||
note:
|
||||
8. For mutating requests, the aggregated apiserver runs admission checks. by default, the namespace lifecycle admission plugin ensures namespaced resources are created in a namespace that exists in the kube-apiserver
|
||||
-----END-----
|
||||
-->
|
||||
|
||||
### Kubernetes Apiserver Authentication and Authorization
|
||||
|
||||
A request to an API path that is served by an extension apiserver begins the same way as all API requests: communication to the Kubernetes apiserver. This path already has been registered with the Kubernetes apiserver by the extension apiserver.
|
||||
|
||||
The user communicates with the Kubernetes apiserver, requesting access to the path. The Kubernetes apiserver uses standard authentication and authorization configured with the Kubernetes apiserver to authenticate the user and authorize access to the specific path.
|
||||
|
||||
For an overview of authenticating to a Kubernetes cluster, see ["Authenticating to a Cluster"](/docs/reference/access-authn-authz/authentication/). For an overview of authorization of access to Kubernetes cluster resources, see ["Authorization Overview"](/docs/reference/access-authn-authz/authorization/).
|
||||
|
||||
Everything to this point has been standard Kubernetes API requests, authentication and authorization.
|
||||
|
||||
The Kubernetes apiserver now is prepared to send the request to the extension apiserver.
|
||||
|
||||
### Kubernetes Apiserver Proxies the Request
|
||||
|
||||
The Kubernetes apiserver now will send, or proxy, the request to the extension apiserver that registered to handle the request. In order to do so, it needs to know several things:
|
||||
|
||||
1. How should the Kubernetes apiserver authenticate to the extension apiserver, informing the extension apiserver that the request, which comes over the network, is coming from a valid Kubernetes apiserver?
|
||||
2. How should the Kubernetes apiserver inform the extension apiserver of the username and group for which the original request was authenticated?
|
||||
|
||||
In order to provide for these two, you must configure the Kubernetes apiserver using several flags.
|
||||
|
||||
#### Kubernetes Apiserver Client Authentication
|
||||
|
||||
The Kubernetes apiserver connects to the extension apiserver over TLS, authenticating itself using a client certificate. You must provide the following to the Kubernetes apiserver upon startup, using the provided flags:
|
||||
|
||||
* private key file via `--proxy-client-key-file`
|
||||
* signed client certificate file via `--proxy-client-cert-file`
|
||||
* certificate of the CA that signed the client certificate file via `--requestheader-client-ca-file`
|
||||
* valid Common Name values (CNs) in the signed client certificate via `--requestheader-allowed-names`
|
||||
|
||||
The Kubernetes apiserver will use the files indicated by `--proxy-client-*-file` to authenticate to the extension apiserver. In order for the request to be considered valid by a compliant extension apiserver, the following conditions must be met:
|
||||
|
||||
1. The connection must be made using a client certificate that is signed by the CA whose certificate is in `--requestheader-client-ca-file`.
|
||||
2. The connection must be made using a client certificate whose CN is one of those listed in `--requestheader-allowed-names`.
|
||||
|
||||
{{< note >}}You can set this option to blank as `--requestheader-allowed-names=""`. This will indicate to an extension apiserver that _any_ CN is acceptable.
|
||||
{{< /note >}}
|
||||
|
||||
When started with these options, the Kubernetes apiserver will:
|
||||
|
||||
1. Use them to authenticate to the extension apiserver.
|
||||
2. Create a configmap in the `kube-system` namespace called `extension-apiserver-authentication`, in which it will place the CA certificate and the allowed CNs. These in turn can be retrieved by extension apiservers to validate requests.
|
||||
|
||||
Note that the same client certificate is used by the Kubernetes apiserver to authenticate against _all_ extension apiservers. It does not create a client certificate per extension apiserver, but rather a single one to authenticate as the Kubernetes apiserver. This same one is reused for all extension apiserver requests.
|
||||
|
||||
#### Original Request Username and Group
|
||||
|
||||
When the Kubernetes apiserver proxies the request to the extension apiserver, it informs the extension apiserver of the username and group with which the original request successfully authenticated. It provides these in http headers of its proxied request. You must inform the Kubernetes apiserver of the names of the headers to be used.
|
||||
|
||||
* the header in which to store the username via `--requestheader-username-headers`
|
||||
* the header in which to store the group via `--requestheader-group-headers`
|
||||
* the prefix to append to all extra headers via `--requestheader-extra-headers-prefix`
|
||||
|
||||
These header names are also placed in the `extension-apiserver-authentication` configmap, so they can be retrieved and used by extension apiservers.
|
||||
|
||||
### Extension Apiserver Authenticates the Request
|
||||
|
||||
The extension apiserver, upon receiving a proxied request from the Kubernetes apiserver, must validate that the request actually did come from a valid authenticating proxy, which role the Kubernetes apiserver is fulfilling. The extension apiserver validates it via:
|
||||
|
||||
1. Retrieve the following from the configmap in `kube-system`, as described above:
|
||||
* Client CA certificate
|
||||
* List of allowed names (CNs)
|
||||
* Header names for username, group and extra info
|
||||
2. Check that the TLS connection was authenticated using a client certificate which:
|
||||
* Was signed by the CA whose certificate matches the retrieved CA certificate.
|
||||
* Has a CN in the list of allowed CNs, unless the list is blank, in which case all CNs are allowed.
|
||||
* Extract the username and group from the appropriate headers
|
||||
|
||||
If the above passes, then the request is a valid proxied request from a legitimate authenticating proxy, in this case the Kubernetes apiserver.
|
||||
|
||||
Note that it is the responsibility of the extension apiserver implementation to provide the above. Many do it by default, leveraging the `k8s.io/apiserver/` package. Others may provide options to override it using command-line options.
|
||||
|
||||
In order to have permission to retrieve the configmap, an extension apiserver requires the appropriate role. There is a default role named `extension-apiserver-authentication-reader` in the `kube-system` namespace which can be assigned.
|
||||
|
||||
### Extension Apiserver Authorizes the Request
|
||||
|
||||
The extension apiserver now can validate that the user/group retrieved from the headers are authorized to execute the given request. It does so by sending a standard [SubjectAccessReview](/docs/reference/access-authn-authz/authorization/) request to the Kubernetes apiserver.
|
||||
|
||||
In order for the extension apiserver to be authorized itself to submit the `SubjectAccessReview` request to the Kubernetes apiserver, it needs the correct permissions. Kubernetes includes a default `ClusterRole` named `system:auth-delegator` that has the appropriate permissions. It can be granted to the extension apiserver's service account.
|
||||
|
||||
### Extension Apiserver Executes
|
||||
|
||||
If the `SubjectAccessReview` passes, the extension apiserver executes the request.
|
||||
|
||||
|
||||
## Enable Kubernetes Apiserver flags
|
||||
|
||||
Enable the aggregation layer via the following `kube-apiserver` flags. They may have already been taken care of by your provider.
|
||||
|
||||
--requestheader-client-ca-file=<path to aggregator CA cert>
|
||||
--requestheader-allowed-names=front-proxy-client
|
||||
--requestheader-extra-headers-prefix=X-Remote-Extra-
|
||||
--requestheader-group-headers=X-Remote-Group
|
||||
--requestheader-username-headers=X-Remote-User
|
||||
--proxy-client-cert-file=<path to aggregator proxy cert>
|
||||
--proxy-client-key-file=<path to aggregator proxy key>
|
||||
|
||||
### CA Reusage and Conflicts
|
||||
|
||||
The Kubernetes apiserver has two client CA options:
|
||||
|
||||
* `--client-ca-file`
|
||||
* `--requestheader-client-ca-file`
|
||||
|
||||
Each of these functions independently and can conflict with each other, if not used correctly.
|
||||
|
||||
* `--client-ca-file`: When a request arrives to the Kubernetes apiserver, if this option is enabled, the Kubernetes apiserver checks the certificate of the request. If it is signed by one of the CA certificates in the file referenced by `--client-ca-file`, then the request is treated as a legitimate request, and the user is the value of the common name `CN=`, while the group is the organization `O=`. See the [documentation on TLS authentication](/docs/reference/access-authn-authz/authentication/#x509-client-certs).
|
||||
* `--requestheader-client-ca-file`: When a request arrives to the Kubernetes apiserver, if this option is enabled, the Kubernetes apiserver checks the certificate of the request. If it is signed by one of the CA certificates in the file reference by `--requestheader-client-ca-file`, then the request is treated as a potentially legitimate request. The Kubernetes apiserver then checks if the common name `CN=` is one of the names in the list provided by `--requestheader-allowed-names`. If the name is allowed, the request is approved; if it is not, the request is not.
|
||||
|
||||
If _both_ `--client-ca-file` and `--requestheader-client-ca-file` are provided, then the request first checks the `--requestheader-client-ca-file` CA and then the `--client-ca-file`. Normally, different CAs, either root CAs or intermediate CAs, are used for each of these options; regular client requests match against `--client-ca-file`, while aggregation requests match against `--requestheader-client-ca-file`. However, if both use the _same_ CA, then client requests that normally would pass via `--client-ca-file` will fail, because the CA will match the CA in `--requestheader-client-ca-file`, but the common name `CN=` will **not** match one of the acceptable common names in `--requestheader-allowed-names`. This can cause your kubelets and other control plane components, as well as end-users, to be unable to authenticate to the Kubernetes apiserver.
|
||||
|
||||
For this reason, use different CA certs for the `--client-ca-file` option - to authorize control plane components and end-users - and the `--requestheader-client-ca-file` option - to authorize aggregation apiserver requests.
|
||||
|
||||
{{< warning >}}
|
||||
Do **not** reuse a CA that is used in a different context unless you understand the risks and the mechanisms to protect the CA's usage.
|
||||
{{< /warning >}}
|
||||
|
||||
If you are not running kube-proxy on a host running the API server, then you must make sure that the system is enabled with the following `kube-apiserver` flag:
|
||||
|
||||
--enable-aggregator-routing=true
|
||||
|
||||
|
||||
|
||||
### Register APIService objects
|
||||
|
||||
You can dynamically configure what client requests are proxied to extension
|
||||
apiserver. The following is an example registration:
|
||||
|
||||
```yaml
|
||||
|
||||
apiVersion: apiregistration.k8s.io/v1
|
||||
kind: APIService
|
||||
metadata:
|
||||
name: <name of the registration object>
|
||||
spec:
|
||||
group: <API group name this extension apiserver hosts>
|
||||
version: <API version this extension apiserver hosts>
|
||||
groupPriorityMinimum: <priority this APIService for this group, see API documentation>
|
||||
versionPriority: <prioritizes ordering of this version within a group, see API documentation>
|
||||
service:
|
||||
namespace: <namespace of the extension apiserver service>
|
||||
name: <name of the extension apiserver service>
|
||||
caBundle: <pem encoded ca cert that signs the server cert used by the webhook>
|
||||
```
|
||||
|
||||
The name of an APIService object must be a valid
|
||||
[path segment name](/docs/concepts/overview/working-with-objects/names#path-segment-names).
|
||||
|
||||
#### Contacting the extension apiserver
|
||||
|
||||
Once the Kubernetes apiserver has determined a request should be sent to an extension apiserver,
|
||||
it needs to know how to contact it.
|
||||
|
||||
The `service` stanza is a reference to the service for an extension apiserver.
|
||||
The service namespace and name are required. The port is optional and defaults to 443.
|
||||
|
||||
Here is an example of an extension apiserver that is configured to be called on port "1234",
|
||||
and to verify the TLS connection against the ServerName
|
||||
`my-service-name.my-service-namespace.svc` using a custom CA bundle.
|
||||
|
||||
```yaml
|
||||
apiVersion: apiregistration.k8s.io/v1
|
||||
kind: APIService
|
||||
...
|
||||
spec:
|
||||
...
|
||||
service:
|
||||
namespace: my-service-namespace
|
||||
name: my-service-name
|
||||
port: 1234
|
||||
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
|
||||
...
|
||||
```
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* [Setup an extension api-server](/docs/tasks/extend-kubernetes/setup-extension-api-server/) to work with the aggregation layer.
|
||||
* For a high level overview, see [Extending the Kubernetes API with the aggregation layer](/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/).
|
||||
* Learn how to [Extend the Kubernetes API Using Custom Resource Definitions](/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/).
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Use Custom Resources"
|
||||
weight: 10
|
||||
---
|
||||
|
||||
+965
@@ -0,0 +1,965 @@
|
||||
---
|
||||
title: Versions in CustomResourceDefinitions
|
||||
reviewers:
|
||||
- sttts
|
||||
- liggitt
|
||||
content_type: task
|
||||
weight: 30
|
||||
min-kubernetes-server-version: v1.16
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
This page explains how to add versioning information to
|
||||
[CustomResourceDefinitions](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#customresourcedefinition-v1beta1-apiextensions), to indicate the stability
|
||||
level of your CustomResourceDefinitions or advance your API to a new version with conversion between API representations. It also describes how to upgrade an object from one version to another.
|
||||
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}}
|
||||
|
||||
You should have a initial understanding of [custom resources](/docs/concepts/api-extension/custom-resources/).
|
||||
|
||||
{{< version-check >}}
|
||||
|
||||
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## Overview
|
||||
|
||||
The CustomResourceDefinition API provides a workflow for introducing and upgrading
|
||||
to new versions of a CustomResourceDefinition.
|
||||
|
||||
When a CustomResourceDefinition is created, the first version is set in the
|
||||
CustomResourceDefinition `spec.versions` list to an appropriate stability level
|
||||
and a version number. For example `v1beta1` would indicate that the first
|
||||
version is not yet stable. All custom resource objects will initially be stored
|
||||
at this version.
|
||||
|
||||
Once the CustomResourceDefinition is created, clients may begin using the
|
||||
`v1beta1` API.
|
||||
|
||||
Later it might be necessary to add new version such as `v1`.
|
||||
|
||||
Adding a new version:
|
||||
|
||||
1. Pick a conversion strategy. Since custom resource objects need to be able to
|
||||
be served at both versions, that means they will sometimes be served at a
|
||||
different version than their storage version. In order for this to be
|
||||
possible, the custom resource objects must sometimes be converted between the
|
||||
version they are stored at and the version they are served at. If the
|
||||
conversion involves schema changes and requires custom logic, a conversion
|
||||
webhook should be used. If there are no schema changes, the default `None`
|
||||
conversion strategy may be used and only the `apiVersion` field will be
|
||||
modified when serving different versions.
|
||||
1. If using conversion webhooks, create and deploy the conversion webhook. See
|
||||
the [Webhook conversion](#webhook-conversion) for more details.
|
||||
1. Update the CustomResourceDefinition to include the new version in the
|
||||
`spec.versions` list with `served:true`. Also, set `spec.conversion` field
|
||||
to the selected conversion strategy. If using a conversion webhook, configure
|
||||
`spec.conversion.webhookClientConfig` field to call the webhook.
|
||||
|
||||
Once the new version is added, clients may incrementally migrate to the new
|
||||
version. It is perfectly safe for some clients to use the old version while
|
||||
others use the new version.
|
||||
|
||||
Migrate stored objects to the new version:
|
||||
|
||||
1. See the [upgrade existing objects to a new stored version](#upgrade-existing-objects-to-a-new-stored-version) section.
|
||||
|
||||
It is safe for clients to use both the old and new version before, during and
|
||||
after upgrading the objects to a new stored version.
|
||||
|
||||
Removing an old version:
|
||||
|
||||
1. Ensure all clients are fully migrated to the new version. The kube-apiserver
|
||||
logs can reviewed to help identify any clients that are still accessing via
|
||||
the old version.
|
||||
1. Set `served` to `false` for the old version in the `spec.versions` list. If
|
||||
any clients are still unexpectedly using the old version they may begin reporting
|
||||
errors attempting to access the custom resource objects at the old version.
|
||||
If this occurs, switch back to using `served:true` on the old version, migrate the
|
||||
remaining clients to the new version and repeat this step.
|
||||
1. Ensure the [upgrade of existing objects to the new stored version](#upgrade-existing-objects-to-a-new-stored-version) step has been completed.
|
||||
1. Verify that the `stored` is set to `true` for the new version in the `spec.versions` list in the CustomResourceDefinition.
|
||||
1. Verify that the old version is no longer listed in the CustomResourceDefinition `status.storedVersions`.
|
||||
1. Remove the old version from the CustomResourceDefinition `spec.versions` list.
|
||||
1. Drop conversion support for the old version in conversion webhooks.
|
||||
|
||||
## Specify multiple versions
|
||||
|
||||
The CustomResourceDefinition API `versions` field can be used to support multiple versions of custom resources that you
|
||||
have developed. Versions can have different schemas, and conversion webhooks can convert custom resources between versions.
|
||||
Webhook conversions should follow the [Kubernetes API conventions](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md) wherever applicable.
|
||||
Specifically, See the [API change documentation](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md) for a set of useful gotchas and suggestions.
|
||||
|
||||
{{< note >}}
|
||||
In `apiextensions.k8s.io/v1beta1`, there was a `version` field instead of `versions`. The
|
||||
`version` field is deprecated and optional, but if it is not empty, it must
|
||||
match the first item in the `versions` field.
|
||||
{{< /note >}}
|
||||
|
||||
This example shows a CustomResourceDefinition with two versions. For the first
|
||||
example, the assumption is all versions share the same schema with no conversion
|
||||
between them. The comments in the YAML provide more context.
|
||||
|
||||
{{< tabs name="CustomResourceDefinition_versioning_example_1" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: crontabs.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1beta1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
# A schema is required
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
- name: v1
|
||||
served: true
|
||||
storage: false
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
# The conversion section is introduced in Kubernetes 1.13+ with a default value of
|
||||
# None conversion (strategy sub-field set to None).
|
||||
conversion:
|
||||
# None conversion assumes the same schema for all versions and only sets the apiVersion
|
||||
# field of custom resources to the proper value
|
||||
strategy: None
|
||||
# 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
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: crontabs.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1beta1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
- name: v1
|
||||
served: true
|
||||
storage: false
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
# The conversion section is introduced in Kubernetes 1.13+ with a default value of
|
||||
# None conversion (strategy sub-field set to None).
|
||||
conversion:
|
||||
# None conversion assumes the same schema for all versions and only sets the apiVersion
|
||||
# field of custom resources to the proper value
|
||||
strategy: None
|
||||
# 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
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
You can save the CustomResourceDefinition in a YAML file, then use
|
||||
`kubectl apply` to create it.
|
||||
|
||||
```shell
|
||||
kubectl apply -f my-versioned-crontab.yaml
|
||||
```
|
||||
|
||||
After creation, the API server starts to serve each enabled version at an HTTP
|
||||
REST endpoint. In the above example, the API versions are available at
|
||||
`/apis/example.com/v1beta1` and `/apis/example.com/v1`.
|
||||
|
||||
### Version priority
|
||||
|
||||
Regardless of the order in which versions are defined in a
|
||||
CustomResourceDefinition, the version with the highest priority is used by
|
||||
kubectl as the default version to access objects. The priority is determined
|
||||
by parsing the _name_ field to determine the version number, the stability
|
||||
(GA, Beta, or Alpha), and the sequence within that stability level.
|
||||
|
||||
The algorithm used for sorting the versions is designed to sort versions in the
|
||||
same way that the Kubernetes project sorts Kubernetes versions. Versions start with a
|
||||
`v` followed by a number, an optional `beta` or `alpha` designation, and
|
||||
optional additional numeric versioning information. Broadly, a version string might look
|
||||
like `v2` or `v2beta1`. Versions are sorted using the following algorithm:
|
||||
|
||||
- Entries that follow Kubernetes version patterns are sorted before those that
|
||||
do not.
|
||||
- For entries that follow Kubernetes version patterns, the numeric portions of
|
||||
the version string is sorted largest to smallest.
|
||||
- If the strings `beta` or `alpha` follow the first numeric portion, they sorted
|
||||
in that order, after the equivalent string without the `beta` or `alpha`
|
||||
suffix (which is presumed to be the GA version).
|
||||
- If another number follows the `beta`, or `alpha`, those numbers are also
|
||||
sorted from largest to smallest.
|
||||
- Strings that don't fit the above format are sorted alphabetically and the
|
||||
numeric portions are not treated specially. Notice that in the example below,
|
||||
`foo1` is sorted above `foo10`. This is different from the sorting of the
|
||||
numeric portion of entries that do follow the Kubernetes version patterns.
|
||||
|
||||
This might make sense if you look at the following sorted version list:
|
||||
|
||||
```none
|
||||
- v10
|
||||
- v2
|
||||
- v1
|
||||
- v11beta2
|
||||
- v10beta3
|
||||
- v3beta1
|
||||
- v12alpha1
|
||||
- v11alpha2
|
||||
- foo1
|
||||
- foo10
|
||||
```
|
||||
|
||||
For the example in [Specify multiple versions](#specify-multiple-versions), the
|
||||
version sort order is `v1`, followed by `v1beta1`. This causes the kubectl
|
||||
command to use `v1` as the default version unless the provided object specifies
|
||||
the version.
|
||||
|
||||
## Webhook conversion
|
||||
|
||||
{{< feature-state state="stable" for_k8s_version="v1.16" >}}
|
||||
|
||||
{{< note >}}
|
||||
Webhook conversion is available as beta since 1.15, and as alpha since Kubernetes 1.13. The
|
||||
`CustomResourceWebhookConversion` feature must be enabled, which is the case automatically for many clusters for beta features. Please refer to the [feature gate](/docs/reference/command-line-tools-reference/feature-gates/) documentation for more information.
|
||||
{{< /note >}}
|
||||
|
||||
The above example has a None conversion between versions which only sets the `apiVersion` field
|
||||
on conversion and does not change the rest of the object. The API server also supports webhook
|
||||
conversions that call an external service in case a conversion is required. For example when:
|
||||
|
||||
* custom resource is requested in a different version than stored version.
|
||||
* Watch is created in one version but the changed object is stored in another version.
|
||||
* custom resource PUT request is in a different version than storage version.
|
||||
|
||||
To cover all of these cases and to optimize conversion by the API server, the conversion requests may contain multiple objects in order to minimize the external calls. The webhook should perform these conversions independently.
|
||||
|
||||
### Write a conversion webhook server
|
||||
|
||||
Please refer to the implementation of the [custom resource conversion webhook
|
||||
server](https://github.com/kubernetes/kubernetes/tree/v1.15.0/test/images/crd-conversion-webhook/main.go)
|
||||
that is validated in a Kubernetes e2e test. The webhook handles the
|
||||
`ConversionReview` requests sent by the API servers, and sends back conversion
|
||||
results wrapped in `ConversionResponse`. Note that the request
|
||||
contains a list of custom resources that need to be converted independently without
|
||||
changing the order of objects.
|
||||
The example server is organized in a way to be reused for other conversions. Most of the common code are located in the [framework file](https://github.com/kubernetes/kubernetes/tree/v1.15.0/test/images/crd-conversion-webhook/converter/framework.go) that leaves only [one function](https://github.com/kubernetes/kubernetes/blob/v1.15.0/test/images/crd-conversion-webhook/converter/example_converter.go#L29-L80) to be implemented for different conversions.
|
||||
|
||||
{{< note >}}
|
||||
The example conversion webhook server leaves the `ClientAuth` field
|
||||
[empty](https://github.com/kubernetes/kubernetes/tree/v1.13.0/test/images/crd-conversion-webhook/config.go#L47-L48),
|
||||
which defaults to `NoClientCert`. This means that the webhook server does not
|
||||
authenticate the identity of the clients, supposedly API servers. If you need
|
||||
mutual TLS or other ways to authenticate the clients, see
|
||||
how to [authenticate API servers](/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers).
|
||||
{{< /note >}}
|
||||
|
||||
#### Permissible mutations
|
||||
|
||||
A conversion webhook must not mutate anything inside of `metadata` of the converted object other than `labels` and `annotations`. Attempted changes to `name`, `UID` and `namespace` are rejected and fail the request which caused the conversion. All other changes are just ignored.
|
||||
|
||||
### Deploy the conversion webhook service
|
||||
|
||||
Documentation for deploying the conversion webhook is the same as for the [admission webhook example service](/docs/reference/access-authn-authz/extensible-admission-controllers/#deploy_the_admission_webhook_service).
|
||||
The assumption for next sections is that the conversion webhook server is deployed to a service named `example-conversion-webhook-server` in `default` namespace and serving traffic on path `/crdconvert`.
|
||||
|
||||
{{< note >}}
|
||||
When the webhook server is deployed into the Kubernetes cluster as a
|
||||
service, it has to be exposed via a service on port 443 (The server
|
||||
itself can have an arbitrary port but the service object should map it to port 443).
|
||||
The communication between the API server and the webhook service may fail
|
||||
if a different port is used for the service.
|
||||
{{< /note >}}
|
||||
|
||||
### Configure CustomResourceDefinition to use conversion webhooks
|
||||
|
||||
The `None` conversion example can be extended to use the conversion webhook by modifying `conversion`
|
||||
section of the `spec`:
|
||||
|
||||
{{< tabs name="CustomResourceDefinition_versioning_example_2" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: crontabs.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: example.com
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1beta1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
# Each version can define it's own schema when there is no top-level
|
||||
# schema is defined.
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
hostPort:
|
||||
type: string
|
||||
- name: v1
|
||||
served: true
|
||||
storage: false
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
strategy: Webhook
|
||||
# webhook is required when strategy is `Webhook` and it configures the webhook endpoint to be called by API server.
|
||||
webhook:
|
||||
# conversionReviewVersions indicates what ConversionReview versions are understood/preferred by the webhook.
|
||||
# The first version in the list understood by the API server is sent to the webhook.
|
||||
# The webhook must respond with a ConversionReview object in the same version it received.
|
||||
conversionReviewVersions: ["v1","v1beta1"]
|
||||
clientConfig:
|
||||
service:
|
||||
namespace: default
|
||||
name: example-conversion-webhook-server
|
||||
path: /crdconvert
|
||||
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
|
||||
# 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
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
# name must match the spec fields below, and be in the form: <plural>.<group>
|
||||
name: crontabs.example.com
|
||||
spec:
|
||||
# group name to use for REST API: /apis/<group>/<version>
|
||||
group: example.com
|
||||
# prunes object fields that are not specified in OpenAPI schemas below.
|
||||
preserveUnknownFields: false
|
||||
# list of versions supported by this CustomResourceDefinition
|
||||
versions:
|
||||
- name: v1beta1
|
||||
# Each version can be enabled/disabled by Served flag.
|
||||
served: true
|
||||
# One and only one version must be marked as the storage version.
|
||||
storage: true
|
||||
# Each version can define it's own schema when there is no top-level
|
||||
# schema is defined.
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
hostPort:
|
||||
type: string
|
||||
- name: v1
|
||||
served: true
|
||||
storage: false
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
type: object
|
||||
properties:
|
||||
host:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
conversion:
|
||||
# a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources.
|
||||
strategy: Webhook
|
||||
# webhookClientConfig is required when strategy is `Webhook` and it configures the webhook endpoint to be called by API server.
|
||||
webhookClientConfig:
|
||||
service:
|
||||
namespace: default
|
||||
name: example-conversion-webhook-server
|
||||
path: /crdconvert
|
||||
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
|
||||
# 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
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
You can save the CustomResourceDefinition in a YAML file, then use
|
||||
`kubectl apply` to apply it.
|
||||
|
||||
```shell
|
||||
kubectl apply -f my-versioned-crontab-with-conversion.yaml
|
||||
```
|
||||
|
||||
Make sure the conversion service is up and running before applying new changes.
|
||||
|
||||
### Contacting the webhook
|
||||
|
||||
Once the API server has determined a request should be sent to a conversion webhook,
|
||||
it needs to know how to contact the webhook. This is specified in the `webhookClientConfig`
|
||||
stanza of the webhook configuration.
|
||||
|
||||
Conversion webhooks can either be called via a URL or a service reference,
|
||||
and can optionally include a custom CA bundle to use to verify the TLS connection.
|
||||
|
||||
### URL
|
||||
|
||||
`url` gives the location of the webhook, in standard URL form
|
||||
(`scheme://host:port/path`).
|
||||
|
||||
The `host` should not refer to a service running in the cluster; use
|
||||
a service reference by specifying the `service` field instead.
|
||||
The host might be resolved via external DNS in some apiservers
|
||||
(i.e., `kube-apiserver` cannot resolve in-cluster DNS as that would
|
||||
be a layering violation). `host` may also be an IP address.
|
||||
|
||||
Please note that using `localhost` or `127.0.0.1` as a `host` is
|
||||
risky unless you take great care to run this webhook on all hosts
|
||||
which run an apiserver which might need to make calls to this
|
||||
webhook. Such installs are likely to be non-portable, i.e., not easy
|
||||
to turn up in a new cluster.
|
||||
|
||||
The scheme must be "https"; the URL must begin with "https://".
|
||||
|
||||
Attempting to use a user or basic auth (for example "user:password@") is not allowed.
|
||||
Fragments ("#...") and query parameters ("?...") are also not allowed.
|
||||
|
||||
Here is an example of a conversion webhook configured to call a URL
|
||||
(and expects the TLS certificate to be verified using system trust roots, so does not specify a caBundle):
|
||||
|
||||
{{< tabs name="CustomResourceDefinition_versioning_example_3" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
...
|
||||
spec:
|
||||
...
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
url: "https://my-webhook.example.com:9443/my-webhook-path"
|
||||
...
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
...
|
||||
spec:
|
||||
...
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhookClientConfig:
|
||||
url: "https://my-webhook.example.com:9443/my-webhook-path"
|
||||
...
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Service Reference
|
||||
|
||||
The `service` stanza inside `webhookClientConfig` is a reference to the service for a conversion webhook.
|
||||
If the webhook is running within the cluster, then you should use `service` instead of `url`.
|
||||
The service namespace and name are required. The port is optional and defaults to 443.
|
||||
The path is optional and defaults to "/".
|
||||
|
||||
Here is an example of a webhook that is configured to call a service on port "1234"
|
||||
at the subpath "/my-path", and to verify the TLS connection against the ServerName
|
||||
`my-service-name.my-service-namespace.svc` using a custom CA bundle.
|
||||
|
||||
{{< tabs name="CustomResourceDefinition_versioning_example_4" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
apiVersion: apiextensions.k8s.io/v1b
|
||||
kind: CustomResourceDefinition
|
||||
...
|
||||
spec:
|
||||
...
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
clientConfig:
|
||||
service:
|
||||
namespace: my-service-namespace
|
||||
name: my-service-name
|
||||
path: /my-path
|
||||
port: 1234
|
||||
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
|
||||
...
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
...
|
||||
spec:
|
||||
...
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhookClientConfig:
|
||||
service:
|
||||
namespace: my-service-namespace
|
||||
name: my-service-name
|
||||
path: /my-path
|
||||
port: 1234
|
||||
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
|
||||
...
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
## Webhook request and response
|
||||
|
||||
### Request
|
||||
|
||||
Webhooks are sent a POST request, with `Content-Type: application/json`,
|
||||
with a `ConversionReview` API object in the `apiextensions.k8s.io` API group
|
||||
serialized to JSON as the body.
|
||||
|
||||
Webhooks can specify what versions of `ConversionReview` objects they accept
|
||||
with the `conversionReviewVersions` field in their CustomResourceDefinition:
|
||||
|
||||
{{< tabs name="conversionReviewVersions" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
...
|
||||
spec:
|
||||
...
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
webhook:
|
||||
conversionReviewVersions: ["v1", "v1beta1"]
|
||||
...
|
||||
```
|
||||
|
||||
`conversionReviewVersions` is a required field when creating
|
||||
`apiextensions.k8s.io/v1` custom resource definitions.
|
||||
Webhooks are required to support at least one `ConversionReview`
|
||||
version understood by the current and previous API server.
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
...
|
||||
spec:
|
||||
...
|
||||
conversion:
|
||||
strategy: Webhook
|
||||
conversionReviewVersions: ["v1", "v1beta1"]
|
||||
...
|
||||
```
|
||||
|
||||
If no `conversionReviewVersions` are specified, the default when creating
|
||||
`apiextensions.k8s.io/v1beta1` custom resource definitions is `v1beta1`.
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
API servers send the first `ConversionReview` version in the `conversionReviewVersions` list they support.
|
||||
If none of the versions in the list are supported by the API server, the custom resource definition will not be allowed to be created.
|
||||
If an API server encounters a conversion webhook configuration that was previously created and does not support any of the `ConversionReview`
|
||||
versions the API server knows how to send, attempts to call to the webhook will fail.
|
||||
|
||||
This example shows the data contained in an `ConversionReview` object
|
||||
for a request to convert `CronTab` objects to `example.com/v1`:
|
||||
|
||||
|
||||
{{< tabs name="ConversionReview_request" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
{
|
||||
"apiVersion": "apiextensions.k8s.io/v1",
|
||||
"kind": "ConversionReview",
|
||||
"request": {
|
||||
# Random uid uniquely identifying this conversion call
|
||||
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
|
||||
|
||||
# The API group and version the objects should be converted to
|
||||
"desiredAPIVersion": "example.com/v1",
|
||||
|
||||
# The list of objects to convert.
|
||||
# May contain one or more objects, in one or more versions.
|
||||
"objects": [
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1beta1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-04T14:03:02Z",
|
||||
"name": "local-crontab",
|
||||
"namespace": "default",
|
||||
"resourceVersion": "143",
|
||||
"uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
|
||||
},
|
||||
"hostPort": "localhost:1234"
|
||||
},
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1beta1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-03T13:02:01Z",
|
||||
"name": "remote-crontab",
|
||||
"resourceVersion": "12893",
|
||||
"uid": "359a83ec-b575-460d-b553-d859cedde8a0"
|
||||
},
|
||||
"hostPort": "example.com:2345"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
{
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
||||
"kind": "ConversionReview",
|
||||
"request": {
|
||||
# Random uid uniquely identifying this conversion call
|
||||
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
|
||||
|
||||
# The API group and version the objects should be converted to
|
||||
"desiredAPIVersion": "example.com/v1",
|
||||
|
||||
# The list of objects to convert.
|
||||
# May contain one or more objects, in one or more versions.
|
||||
"objects": [
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1beta1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-04T14:03:02Z",
|
||||
"name": "local-crontab",
|
||||
"namespace": "default",
|
||||
"resourceVersion": "143",
|
||||
"uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
|
||||
},
|
||||
"hostPort": "localhost:1234"
|
||||
},
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1beta1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-03T13:02:01Z",
|
||||
"name": "remote-crontab",
|
||||
"resourceVersion": "12893",
|
||||
"uid": "359a83ec-b575-460d-b553-d859cedde8a0"
|
||||
},
|
||||
"hostPort": "example.com:2345"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
### Response
|
||||
|
||||
Webhooks respond with a 200 HTTP status code, `Content-Type: application/json`,
|
||||
and a body containing a `ConversionReview` object (in the same version they were sent),
|
||||
with the `response` stanza populated, serialized to JSON.
|
||||
|
||||
If conversion succeeds, a webhook should return a `response` stanza containing the following fields:
|
||||
* `uid`, copied from the `request.uid` sent to the webhook
|
||||
* `result`, set to `{"status":"Success"}`
|
||||
* `convertedObjects`, containing all of the objects from `request.objects`, converted to `request.desiredVersion`
|
||||
|
||||
Example of a minimal successful response from a webhook:
|
||||
|
||||
{{< tabs name="ConversionReview_response_success" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
{
|
||||
"apiVersion": "apiextensions.k8s.io/v1",
|
||||
"kind": "ConversionReview",
|
||||
"response": {
|
||||
# must match <request.uid>
|
||||
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
|
||||
"result": {
|
||||
"status": "Success"
|
||||
},
|
||||
# Objects must match the order of request.objects, and have apiVersion set to <request.desiredAPIVersion>.
|
||||
# kind, metadata.uid, metadata.name, and metadata.namespace fields must not be changed by the webhook.
|
||||
# metadata.labels and metadata.annotations fields may be changed by the webhook.
|
||||
# All other changes to metadata fields by the webhook are ignored.
|
||||
"convertedObjects": [
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-04T14:03:02Z",
|
||||
"name": "local-crontab",
|
||||
"namespace": "default",
|
||||
"resourceVersion": "143",
|
||||
"uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
|
||||
},
|
||||
"host": "localhost",
|
||||
"port": "1234"
|
||||
},
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-03T13:02:01Z",
|
||||
"name": "remote-crontab",
|
||||
"resourceVersion": "12893",
|
||||
"uid": "359a83ec-b575-460d-b553-d859cedde8a0"
|
||||
},
|
||||
"host": "example.com",
|
||||
"port": "2345"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
{
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
||||
"kind": "ConversionReview",
|
||||
"response": {
|
||||
# must match <request.uid>
|
||||
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
|
||||
"result": {
|
||||
"status": "Failed"
|
||||
},
|
||||
# Objects must match the order of request.objects, and have apiVersion set to <request.desiredAPIVersion>.
|
||||
# kind, metadata.uid, metadata.name, and metadata.namespace fields must not be changed by the webhook.
|
||||
# metadata.labels and metadata.annotations fields may be changed by the webhook.
|
||||
# All other changes to metadata fields by the webhook are ignored.
|
||||
"convertedObjects": [
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-04T14:03:02Z",
|
||||
"name": "local-crontab",
|
||||
"namespace": "default",
|
||||
"resourceVersion": "143",
|
||||
"uid": "3415a7fc-162b-4300-b5da-fd6083580d66"
|
||||
},
|
||||
"host": "localhost",
|
||||
"port": "1234"
|
||||
},
|
||||
{
|
||||
"kind": "CronTab",
|
||||
"apiVersion": "example.com/v1",
|
||||
"metadata": {
|
||||
"creationTimestamp": "2019-09-03T13:02:01Z",
|
||||
"name": "remote-crontab",
|
||||
"resourceVersion": "12893",
|
||||
"uid": "359a83ec-b575-460d-b553-d859cedde8a0"
|
||||
},
|
||||
"host": "example.com",
|
||||
"port": "2345"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
If conversion fails, a webhook should return a `response` stanza containing the following fields:
|
||||
* `uid`, copied from the `request.uid` sent to the webhook
|
||||
* `result`, set to `{"status":"Failed"}`
|
||||
|
||||
{{< warning >}}
|
||||
Failing conversion can disrupt read and write access to the custom resources,
|
||||
including the ability to update or delete the resources. Conversion failures
|
||||
should be avoided whenever possible, and should not be used to enforce validation
|
||||
constraints (use validation schemas or webhook admission instead).
|
||||
{{< /warning >}}
|
||||
|
||||
Example of a response from a webhook indicating a conversion request failed, with an optional message:
|
||||
{{< tabs name="ConversionReview_response_failure" >}}
|
||||
{{% tab name="apiextensions.k8s.io/v1" %}}
|
||||
```yaml
|
||||
{
|
||||
"apiVersion": "apiextensions.k8s.io/v1",
|
||||
"kind": "ConversionReview",
|
||||
"response": {
|
||||
"uid": "<value from request.uid>",
|
||||
"result": {
|
||||
"status": "Failed",
|
||||
"message": "hostPort could not be parsed into a separate host and port"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="apiextensions.k8s.io/v1beta1" %}}
|
||||
```yaml
|
||||
{
|
||||
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
|
||||
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
||||
"kind": "ConversionReview",
|
||||
"response": {
|
||||
"uid": "<value from request.uid>",
|
||||
"result": {
|
||||
"status": "Failed",
|
||||
"message": "hostPort could not be parsed into a separate host and port"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
## Writing, reading, and updating versioned CustomResourceDefinition objects
|
||||
|
||||
When an object is written, it is persisted at the version designated as the
|
||||
storage version at the time of the write. If the storage version changes,
|
||||
existing objects are never converted automatically. However, newly-created
|
||||
or updated objects are written at the new storage version. It is possible for an
|
||||
object to have been written at a version that is no longer served.
|
||||
|
||||
When you read an object, you specify the version as part of the path. If you
|
||||
specify a version that is different from the object's persisted version,
|
||||
Kubernetes returns the object to you at the version you requested, but the
|
||||
persisted object is neither changed on disk, nor converted in any way
|
||||
(other than changing the `apiVersion` string) while serving the request.
|
||||
You can request an object at any version that is currently served.
|
||||
|
||||
If you update an existing object, it is rewritten at the version that is
|
||||
currently the storage version. This is the only way that objects can change from
|
||||
one version to another.
|
||||
|
||||
To illustrate this, consider the following hypothetical series of events:
|
||||
|
||||
1. The storage version is `v1beta1`. You create an object. It is persisted in
|
||||
storage at version `v1beta1`
|
||||
2. You add version `v1` to your CustomResourceDefinition and designate it as
|
||||
the storage version.
|
||||
3. You read your object at version `v1beta1`, then you read the object again at
|
||||
version `v1`. Both returned objects are identical except for the apiVersion
|
||||
field.
|
||||
4. You create a new object. It is persisted in storage at version `v1`. You now
|
||||
have two objects, one of which is at `v1beta1`, and the other of which is at
|
||||
`v1`.
|
||||
5. You update the first object. It is now persisted at version `v1` since that
|
||||
is the current storage version.
|
||||
|
||||
### Previous storage versions
|
||||
|
||||
The API server records each version which has ever been marked as the storage
|
||||
version in the status field `storedVersions`. Objects may have been persisted
|
||||
at any version that has ever been designated as a storage version. No objects
|
||||
can exist in storage at a version that has never been a storage version.
|
||||
|
||||
## Upgrade existing objects to a new stored version
|
||||
|
||||
When deprecating versions and dropping support, select a storage upgrade
|
||||
procedure.
|
||||
|
||||
*Option 1:* Use the Storage Version Migrator
|
||||
|
||||
1. Run the [storage Version migrator](https://github.com/kubernetes-sigs/kube-storage-version-migrator)
|
||||
2. Remove the old version from the CustomResourceDefinition `status.storedVersions` field.
|
||||
|
||||
*Option 2:* Manually upgrade the existing objects to a new stored version
|
||||
|
||||
The following is an example procedure to upgrade from `v1beta1` to `v1`.
|
||||
|
||||
1. Set `v1` as the storage in the CustomResourceDefinition file and apply it
|
||||
using kubectl. The `storedVersions` is now `v1beta1, v1`.
|
||||
2. Write an upgrade procedure to list all existing objects and write them with
|
||||
the same content. This forces the backend to write objects in the current
|
||||
storage version, which is `v1`.
|
||||
2. Remove `v1beta1` from the CustomResourceDefinition `status.storedVersions` field.
|
||||
|
||||
|
||||
+1461
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: Use an HTTP Proxy to Access the Kubernetes API
|
||||
content_type: task
|
||||
weight: 40
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
This page shows how to use an HTTP proxy to access the Kubernetes API.
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
If you do not already have an application running in your cluster, start
|
||||
a Hello world application by entering this command:
|
||||
|
||||
```shell
|
||||
kubectl run node-hello --image=gcr.io/google-samples/node-hello:1.0 --port=8080
|
||||
```
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## Using kubectl to start a proxy server
|
||||
|
||||
This command starts a proxy to the Kubernetes API server:
|
||||
|
||||
kubectl proxy --port=8080
|
||||
|
||||
## Exploring the Kubernetes API
|
||||
|
||||
When the proxy server is running, you can explore the API using `curl`, `wget`,
|
||||
or a browser.
|
||||
|
||||
Get the API versions:
|
||||
|
||||
curl http://localhost:8080/api/
|
||||
|
||||
The output should look similar to this:
|
||||
|
||||
{
|
||||
"kind": "APIVersions",
|
||||
"versions": [
|
||||
"v1"
|
||||
],
|
||||
"serverAddressByClientCIDRs": [
|
||||
{
|
||||
"clientCIDR": "0.0.0.0/0",
|
||||
"serverAddress": "10.0.2.15:8443"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Get a list of pods:
|
||||
|
||||
curl http://localhost:8080/api/v1/namespaces/default/pods
|
||||
|
||||
The output should look similar to this:
|
||||
|
||||
{
|
||||
"kind": "PodList",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"resourceVersion": "33074"
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"metadata": {
|
||||
"name": "kubernetes-bootcamp-2321272333-ix8pt",
|
||||
"generateName": "kubernetes-bootcamp-2321272333-",
|
||||
"namespace": "default",
|
||||
"uid": "ba21457c-6b1d-11e6-85f7-1ef9f1dab92b",
|
||||
"resourceVersion": "33003",
|
||||
"creationTimestamp": "2016-08-25T23:43:30Z",
|
||||
"labels": {
|
||||
"pod-template-hash": "2321272333",
|
||||
"run": "kubernetes-bootcamp"
|
||||
},
|
||||
...
|
||||
}
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
Learn more about [kubectl proxy](/docs/reference/generated/kubectl/kubectl-commands#proxy).
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: Set up an Extension API Server
|
||||
reviewers:
|
||||
- lavalamp
|
||||
- cheftako
|
||||
- chenopis
|
||||
content_type: task
|
||||
weight: 15
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
Setting up an extension API server to work with the aggregation layer allows the Kubernetes apiserver to be extended with additional APIs, which are not part of the core Kubernetes APIs.
|
||||
|
||||
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}}
|
||||
|
||||
* You must [configure the aggregation layer](/docs/tasks/extend-kubernetes/configure-aggregation-layer/) and enable the apiserver flags.
|
||||
|
||||
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## Setup an extension api-server to work with the aggregation layer
|
||||
|
||||
The following steps describe how to set up an extension-apiserver *at a high level*. These steps apply regardless if you're using YAML configs or using APIs. An attempt is made to specifically identify any differences between the two. For a concrete example of how they can be implemented using YAML configs, you can look at the [sample-apiserver](https://github.com/kubernetes/sample-apiserver/blob/master/README.md) in the Kubernetes repo.
|
||||
|
||||
Alternatively, you can use an existing 3rd party solution, such as [apiserver-builder](https://github.com/kubernetes-sigs/apiserver-builder-alpha/blob/master/README.md), which should generate a skeleton and automate all of the following steps for you.
|
||||
|
||||
1. Make sure the APIService API is enabled (check `--runtime-config`). It should be on by default, unless it's been deliberately turned off in your cluster.
|
||||
1. You may need to make an RBAC rule allowing you to add APIService objects, or get your cluster administrator to make one. (Since API extensions affect the entire cluster, it is not recommended to do testing/development/debug of an API extension in a live cluster.)
|
||||
1. Create the Kubernetes namespace you want to run your extension api-service in.
|
||||
1. Create/get a CA cert to be used to sign the server cert the extension api-server uses for HTTPS.
|
||||
1. Create a server cert/key for the api-server to use for HTTPS. This cert should be signed by the above CA. It should also have a CN of the Kube DNS name. This is derived from the Kubernetes service and be of the form `<service name>.<service name namespace>.svc`
|
||||
1. Create a Kubernetes secret with the server cert/key in your namespace.
|
||||
1. Create a Kubernetes deployment for the extension api-server and make sure you are loading the secret as a volume. It should contain a reference to a working image of your extension api-server. The deployment should also be in your namespace.
|
||||
1. Make sure that your extension-apiserver loads those certs from that volume and that they are used in the HTTPS handshake.
|
||||
1. Create a Kubernetes service account in your namespace.
|
||||
1. Create a Kubernetes cluster role for the operations you want to allow on your resources.
|
||||
1. Create a Kubernetes cluster role binding from the service account in your namespace to the cluster role you just created.
|
||||
1. Create a Kubernetes cluster role binding from the service account in your namespace to the `system:auth-delegator` cluster role to delegate auth decisions to the Kubernetes core API server.
|
||||
1. Create a Kubernetes role binding from the service account in your namespace to the `extension-apiserver-authentication-reader` role. This allows your extension api-server to access the `extension-apiserver-authentication` configmap.
|
||||
1. Create a Kubernetes apiservice. The CA cert above should be base64 encoded, stripped of new lines and used as the spec.caBundle in the apiservice. This should not be namespaced. If using the [kube-aggregator API](https://github.com/kubernetes/kube-aggregator/), only pass in the PEM encoded CA bundle because the base 64 encoding is done for you.
|
||||
1. Use kubectl to get your resource. When run, kubectl should return "No resources found.". This message
|
||||
indicates that everything worked but you currently have no objects of that resource type created.
|
||||
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
|
||||
* Walk through the steps to [configure the API aggregation layer](/docs/tasks/extend-kubernetes/configure-aggregation-layer/) and enable the apiserver flags.
|
||||
* For a high level overview, see [Extending the Kubernetes API with the aggregation layer](/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/).
|
||||
* Learn how to [Extend the Kubernetes API using Custom Resource Definitions](/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/).
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: Set up Konnectivity service
|
||||
content_type: task
|
||||
weight: 70
|
||||
---
|
||||
|
||||
<!-- overview -->
|
||||
|
||||
The Konnectivity service provides a TCP level proxy for the control plane to cluster
|
||||
communication.
|
||||
|
||||
## {{% heading "prerequisites" %}}
|
||||
|
||||
{{< include "task-tutorial-prereqs.md" >}}
|
||||
|
||||
<!-- steps -->
|
||||
|
||||
## Configure the Konnectivity service
|
||||
|
||||
The following steps require an egress configuration, for example:
|
||||
|
||||
{{< codenew file="admin/konnectivity/egress-selector-configuration.yaml" >}}
|
||||
|
||||
You need to configure the API Server to use the Konnectivity service
|
||||
and direct the network traffic to the cluster nodes:
|
||||
|
||||
1. Create an egress configuration file such as `admin/konnectivity/egress-selector-configuration.yaml`.
|
||||
1. Set the `--egress-selector-config-file` flag of the API Server to the path of
|
||||
your API Server egress configuration file.
|
||||
|
||||
Next, you need to deploy the Konnectivity server and agents.
|
||||
[kubernetes-sigs/apiserver-network-proxy](https://github.com/kubernetes-sigs/apiserver-network-proxy)
|
||||
is a reference implementation.
|
||||
|
||||
Deploy the Konnectivity server on your control plane node. The provided
|
||||
`konnectivity-server.yaml` manifest assumes
|
||||
that the Kubernetes components are deployed as a {{< glossary_tooltip text="static Pod"
|
||||
term_id="static-pod" >}} in your cluster. If not, you can deploy the Konnectivity
|
||||
server as a DaemonSet.
|
||||
|
||||
{{< codenew file="admin/konnectivity/konnectivity-server.yaml" >}}
|
||||
|
||||
Then deploy the Konnectivity agents in your cluster:
|
||||
|
||||
{{< codenew file="admin/konnectivity/konnectivity-agent.yaml" >}}
|
||||
|
||||
Last, if RBAC is enabled in your cluster, create the relevant RBAC rules:
|
||||
|
||||
{{< codenew file="admin/konnectivity/konnectivity-rbac.yaml" >}}
|
||||
Reference in New Issue
Block a user