Skip to content

Commit

Permalink
Merge pull request #2799 from fgiloux/slice-doc
Browse files Browse the repository at this point in the history
📖 APIExportEndpointSlice and Partition doc
  • Loading branch information
openshift-merge-robot authored Feb 21, 2023
2 parents 914ecda + 3651e34 commit 6434142
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 24 deletions.
72 changes: 72 additions & 0 deletions docs/content/en/concepts/partitions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
description: >
How to create shard partitions
---

# Partition API

`Partitions` and `PartitionSets` build an API that allows service providers and cluster administrators to create shard Partitions. These partitions can then be leveraged:
- for the deployment of the controllers of the service providers and other components. These APIs provide the information on shard topology required for the scheduling.
- for grouping APIExport endpoints of multiple shards in common buckets, that is `Partitions`. These buckets can the be used to achieve geo proximity: controllers should communicate with API servers of shards in the same region. They can also be leveraged for scalability and load distribution, that is to adapt the number of deployment/ processes to the load pattern specific to the controllers of a service provider.

## Partitions

The partitioning of `Shards` is done through labels and [label selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors).

Here is an example of a `Partition`

```yaml
kind: Partition
apiVersion: topology.kcp.io/v1alpha1
metadata:
name: cloud-region-gcp-europe-xdfgs
ownerReferences:
...
spec:
selector:
matchLabels:
cloud: gcp
region: europe
matchExpressions:
- key: country
operator: NotIn
values:
- LI
```
`Partitions` can be referenced in [`APIExportEndpointSlices`](./quickstart-tenancy-and-apis.md)

## PartitionSets

`PartitionSets` is an API for convenience. `PartitionSet` can be used to get `Partitions` automatically created based on dimensions that match the shard label keys. The `Partitions` are created in the same workspace as the `PartitionSet`. They can then be copied to the desired workspace for consumption, for instance, by an `APIExportEndpointSlice`.

Here is an example of a `PartitionSet`

```yaml
kind: PartitionSet
apiVersion: topology.kcp.io/v1alpha1
metadata:
name: cloud-region
spec:
dimensions:
- region
- cloud
selectors:
matchExpressions:
- key: region
operator: NotIn
values:
- Antarctica
- Greenland
- key: country
operator: NotIn
values:
- NK
status:
count: 10
...
```

It is to note that a `Partition` is created only if it matches at least one shard. With the provided example if there is no shard in the cloud provider `aliyun` in the region `europe` no `Partition` will be created for it.

An example of a `Partition` generated by this `PartitionSet` can be found above. The `dimensions` are translated into `matchLabels` with values specific to each `Partition`. An owner reference of the `Partition` will be set to the `PartitionSet`.
103 changes: 79 additions & 24 deletions docs/content/en/concepts/quickstart-tenancy-and-apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,33 @@ EOF
cowboy.wildwest.dev/one created
```

## Dig deeper into `APIExports`
## Managing permissions

Besides publishing APIs and reconciliating the related resources service providers' controllers may need access to core resources or resources exported by other services in the user workspaces as part of their duties. This access needs for security reason to get authorized. `permissionClaims` address this need.

A service provider wanting to access `ConfigMaps` needs to specify such a claim in the `APIExport`:

```yaml
spec:
...
permissionClaims:
- group: ""
resource: "configmaps"
```
Users can then authorize access to this resource type in their workspace by accepting the claim in the `APIBinding`:

```yaml
spec:
...
permissionClaims:
- group: ""
resource: "configmaps"
state: Accepted
```

There is the possibility to further limit the access claim to single resources.

## Dig deeper into APIExports

Switching back to the service provider persona:

Expand All @@ -263,25 +289,61 @@ metadata:
status:
...
identityHash: a6a0cc778bec8c4b844e6326965fbb740b6a9590963578afe07276e6a0d41e20
virtualWorkspaces:
- url: https://myhost:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev
```

We can see that our `APIExport` has two key attributes in its status - its identity (more on this below) and a "virtual
workspace" URL. You can think of this virtual workspace as behaving just like a workspace or cluster, except it searches
across all true workspaces for instances of the resource types provided by the `APIExport`. We can use API discovery to
see what resource types are available via this virtual workspace:
We can see that our `APIExport` has a key attribute in its status - its identity (more on this below).
This identity can be used in permissionClaims for referring to non-core resources.

## APIExportEndpointSlice

`APIExportEndpointSlices` allow service provider to retrieve the URL of service endpoints, acting as a sink for them. You can think of this endpoint as behaving just like a workspace or cluster, except it searches across all workspaces for instances of the resource types provided by the `APIExport`.
An `APIExportEndpointSlice` is created by a service provider, references a single `APIExport` and optionally a `Partition`.
`Partitions` are a mechanism for filtering service endpoints. Within a multi-sharded kcp, each shard will offer its own service endpoint URL for an `APIExport`. Service provider may decide to have multiple instances of their controller reconciliating, for instance, resources of shards in the same region. For that they may create an `APIExportEndpointSlice` in the same workspace where a controller instance is deployed. This `APIExportEndpointSlice` will then reference a specific `Partition` by its name in the same workspace filtering the service endpoints for a subset of shards. If an `APIExportEndpointSlice` does not reference a `Partition` all the available endpoints are populated in its `status`. More on `Partitions` [here](./partitions,md).

```shell
$ kubectl apply -f - <<EOF
kind: APIExportEndpointSlice
apiVersion: apis.kcp.io/v1alpha1
metadata:
name: cowboys
spec:
export:
path: root:wildwest:cowboys-service
name: cowboy
# optional
partition: cloud-region-gcp-europe-xdfgs
EOF
apiexportendpointslice.apis.kcp.io/cowboys created
```

Looking at the status populated by the controller

```shell
$ kubectl get APIExportEndpointSlice/cowboys -o yaml
kind: APIExportEndpointSlice
apiVersion: apis.kcp.io/v1alpha1
metadata:
name: cowboys
...
status:
endpoints
- url: https://host1:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev
- url: https://host2:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev
...
```

We can use API discovery to see what resource types are available via the endpoint URL:

```shell
$ kubectl --server='https://myhost:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev/clusters/*/' api-resources
$ kubectl --server='https://host1:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev/clusters/*/' api-resources
NAME SHORTNAMES APIVERSION NAMESPACED KIND
cowboys wildwest.dev/v1alpha1 true Cowboy
```

The question is ... can we see the instance created by the consumer?

```shell
$ kubectl --server='https://myhost:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev/clusters/*/' get -A cowboys \
$ kubectl --server='https://host1:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev/clusters/*/' get -A cowboys \
-o custom-columns='WORKSPACE:.metadata.annotations.kcp\.dev/cluster,NAME:.metadata.name'
WORKSPACE NAME
root:users:zu:yc:kcp-admin:test-consumer one
Expand All @@ -293,13 +355,11 @@ Yay!

Q: Why is there a new `APIResourceSchema` resource type that appears to be very similar to `CustomResourceDefinition`?

A: FIXME
A: An APIResourceSchema defines a single custom API type. It is almost identical to a CRD, but creating an APIResourceSchema instance does not add a usable API to the server. By intentionally decoupling the schema definition from serving, API owners can be more explicit about API evolution.

Q: Why do I have to append `/clusters/*/` to the `APIExport` virtual workspace URL?
Q: Why do I have to append `/clusters/*/` to the `APIExport` service endpoint URL?

A: The URL represents the base path of a virtual kcp API server. With a standard kcp API server, workspaces live under
the `/clusters/` path, so `/clusters/*/` represents a wildcard search across all workspaces via this virtual API
server.
A: The URL represents the base path of a virtual kcp API server. With a standard kcp API server, workspaces live under the `/clusters/` path, so `/clusters/*/` represents a wildcard search across all workspaces via this virtual API server.

Q: How should we understand an `APIExport` `identityHash`?

Expand All @@ -309,19 +369,14 @@ some way of securely distinguishing them.
Each `APIExport` is allocated a randomized private secret - this is currently just a large random number - and a public
identity - just a SHA256 hash of the private secret - which securely identifies this `APIExport` from others.

This is important because an `APIExport` makes a virtual workspace available to interact with all instances of a
particular `APIResourceShema`, and we want to make sure that users are clear on which service provider `APIExports` they
are trusting and only the owners of those `APIExport` have access to their resources via virtual workspaces.
This is important because an `APIExport` makes service endpoints available to interact with all instances of a particular `APIResourceShema`, and we want to make sure that users are clear on which service provider `APIExports` they are trusting and only the owners of those `APIExport` have access to their resources via the service endpoints.

Q: Why do you have to use `--all-namespaces` with the apiexport virtual workspace?
Q: Why do you have to use `--all-namespaces` with the `APIExport` service endpoint?

A: Think of this virtual workspace as representing a wildcard listing across all workspaces. It doesn't make sense to
look at a specific namespace across all workspaces, so you have to list across all namespaces too.
A: Think of this endpoint as representing a wildcard listing across all workspaces. It doesn't make sense to look at a specific namespace across all workspaces, so you have to list across all namespaces too.

Q: If I attempt to use an `APIExport` virtual workspace before there are any `APIBindings` I get the "Error from server
(NotFound): Unable to list ...: the server could not find the requested resource". Is this a bug?
Q: If I attempt to use an `APIExport` endpoint before there are any `APIBindings` I get the "Error from server (NotFound): Unable to list ...: the server could not find the requested resource". Is this a bug?

A: It is a bug. See <https://github.com/kcp-dev/kcp/issues/1183>

When fixed, we expect the `APIExport` behavior will change such that there will be no virtual workspace URLs until an
`APIBinding` is created.
When fixed, we expect the `APIExport` behavior will change such that an empty list is returned instead of the error.

0 comments on commit 6434142

Please sign in to comment.