Skip to content

Commit 6434142

Browse files
Merge pull request #2799 from fgiloux/slice-doc
📖 APIExportEndpointSlice and Partition doc
2 parents 914ecda + 3651e34 commit 6434142

File tree

2 files changed

+151
-24
lines changed

2 files changed

+151
-24
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
description: >
3+
How to create shard partitions
4+
---
5+
6+
# Partition API
7+
8+
`Partitions` and `PartitionSets` build an API that allows service providers and cluster administrators to create shard Partitions. These partitions can then be leveraged:
9+
- 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.
10+
- 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.
11+
12+
## Partitions
13+
14+
The partitioning of `Shards` is done through labels and [label selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors).
15+
16+
Here is an example of a `Partition`
17+
18+
```yaml
19+
kind: Partition
20+
apiVersion: topology.kcp.io/v1alpha1
21+
metadata:
22+
name: cloud-region-gcp-europe-xdfgs
23+
ownerReferences:
24+
...
25+
spec:
26+
selector:
27+
matchLabels:
28+
cloud: gcp
29+
region: europe
30+
matchExpressions:
31+
- key: country
32+
operator: NotIn
33+
values:
34+
- LI
35+
```
36+
37+
`Partitions` can be referenced in [`APIExportEndpointSlices`](./quickstart-tenancy-and-apis.md)
38+
39+
## PartitionSets
40+
41+
`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`.
42+
43+
Here is an example of a `PartitionSet`
44+
45+
```yaml
46+
kind: PartitionSet
47+
apiVersion: topology.kcp.io/v1alpha1
48+
metadata:
49+
name: cloud-region
50+
spec:
51+
dimensions:
52+
- region
53+
- cloud
54+
selectors:
55+
matchExpressions:
56+
- key: region
57+
operator: NotIn
58+
values:
59+
- Antarctica
60+
- Greenland
61+
- key: country
62+
operator: NotIn
63+
values:
64+
- NK
65+
status:
66+
count: 10
67+
...
68+
```
69+
70+
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.
71+
72+
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`.

docs/content/en/concepts/quickstart-tenancy-and-apis.md

Lines changed: 79 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,33 @@ EOF
247247
cowboy.wildwest.dev/one created
248248
```
249249

250-
## Dig deeper into `APIExports`
250+
## Managing permissions
251+
252+
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.
253+
254+
A service provider wanting to access `ConfigMaps` needs to specify such a claim in the `APIExport`:
255+
256+
```yaml
257+
spec:
258+
...
259+
permissionClaims:
260+
- group: ""
261+
resource: "configmaps"
262+
```
263+
Users can then authorize access to this resource type in their workspace by accepting the claim in the `APIBinding`:
264+
265+
```yaml
266+
spec:
267+
...
268+
permissionClaims:
269+
- group: ""
270+
resource: "configmaps"
271+
state: Accepted
272+
```
273+
274+
There is the possibility to further limit the access claim to single resources.
275+
276+
## Dig deeper into APIExports
251277

252278
Switching back to the service provider persona:
253279

@@ -263,25 +289,61 @@ metadata:
263289
status:
264290
...
265291
identityHash: a6a0cc778bec8c4b844e6326965fbb740b6a9590963578afe07276e6a0d41e20
266-
virtualWorkspaces:
267-
- url: https://myhost:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev
268292
```
269293

270-
We can see that our `APIExport` has two key attributes in its status - its identity (more on this below) and a "virtual
271-
workspace" URL. You can think of this virtual workspace as behaving just like a workspace or cluster, except it searches
272-
across all true workspaces for instances of the resource types provided by the `APIExport`. We can use API discovery to
273-
see what resource types are available via this virtual workspace:
294+
We can see that our `APIExport` has a key attribute in its status - its identity (more on this below).
295+
This identity can be used in permissionClaims for referring to non-core resources.
296+
297+
## APIExportEndpointSlice
298+
299+
`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`.
300+
An `APIExportEndpointSlice` is created by a service provider, references a single `APIExport` and optionally a `Partition`.
301+
`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).
302+
303+
```shell
304+
$ kubectl apply -f - <<EOF
305+
kind: APIExportEndpointSlice
306+
apiVersion: apis.kcp.io/v1alpha1
307+
metadata:
308+
name: cowboys
309+
spec:
310+
export:
311+
path: root:wildwest:cowboys-service
312+
name: cowboy
313+
# optional
314+
partition: cloud-region-gcp-europe-xdfgs
315+
EOF
316+
apiexportendpointslice.apis.kcp.io/cowboys created
317+
```
318+
319+
Looking at the status populated by the controller
320+
321+
```shell
322+
$ kubectl get APIExportEndpointSlice/cowboys -o yaml
323+
kind: APIExportEndpointSlice
324+
apiVersion: apis.kcp.io/v1alpha1
325+
metadata:
326+
name: cowboys
327+
...
328+
status:
329+
endpoints
330+
- url: https://host1:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev
331+
- url: https://host2:6443/services/apiexport/root:wildwest:cowboys-service/wildwest.dev
332+
...
333+
```
334+
335+
We can use API discovery to see what resource types are available via the endpoint URL:
274336

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

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

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

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

296-
A: FIXME
358+
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.
297359

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

300-
A: The URL represents the base path of a virtual kcp API server. With a standard kcp API server, workspaces live under
301-
the `/clusters/` path, so `/clusters/*/` represents a wildcard search across all workspaces via this virtual API
302-
server.
362+
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.
303363

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

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

312-
This is important because an `APIExport` makes a virtual workspace available to interact with all instances of a
313-
particular `APIResourceShema`, and we want to make sure that users are clear on which service provider `APIExports` they
314-
are trusting and only the owners of those `APIExport` have access to their resources via virtual workspaces.
372+
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.
315373

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

318-
A: Think of this virtual workspace as representing a wildcard listing across all workspaces. It doesn't make sense to
319-
look at a specific namespace across all workspaces, so you have to list across all namespaces too.
376+
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.
320377

321-
Q: If I attempt to use an `APIExport` virtual workspace before there are any `APIBindings` I get the "Error from server
322-
(NotFound): Unable to list ...: the server could not find the requested resource". Is this a bug?
378+
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?
323379

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

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

0 commit comments

Comments
 (0)