CachedResource API¶
Warning
As of 0.29, this feature is of alpha-version quality. To use it, enable the CachedAPIs feature gate.
A CachedResource object replicates a user-defined resource from its workspace into kcp's cache server. It may be used as an APIExport virtual resource with the goal of distributing static, read-only resources to multiple clusters, in a scalable way.
Example user story:
- You, the service provider, run a cloud Cloud Co., including a compute service.
- You offer a service of provisioning and running VM instances: users create an
Instanceobject and voilà, they have a running VM!- But how do you design the API for configuring such a resource? How do you make your consumers know what configuration options are available, given the limited resources available in the cloud?
- You've decided to offer different packages for CPUs, memory, storage, GPUs; these are represented as CRDs, e.g.
cpuflavors.cloud.example.com,memflavors.cloud.example.com, withcpu-small,cpu-medium,cpu-large,mem-medium,mem-large,mem-xlargerespectively. - You've created a CachedResource for each flavor type.
- You offer the service through an APIExport containing the main
instances.cloud.example.comresource, as well as all flavors. These are exported as virtual resources.
- Consumers binding to your APIExport can list and get the available flavors from within their workspace (e.g. with
kubectl get cpuflavors), and refer to them in theirInstancespec. They cannot create, delete or otherwise modify the flavor objects in any way.
See an example usage at github.com/kcp-dev/kcp/tree/main/config/examples/virtualresources.
Resource replication¶
apiVersion: cache.kcp.io/v1alpha1
kind: CachedResource
metadata:
name: cpuflavors-v1
spec:
group: cloud.example.com
version: v1
resource: cpuflavors
The snippet above shows an example where all cpuflavors.v1.cloud.example.com objects in the workspace are replicated to the cache. There are some constraints on what resources may be replicated:
- There may be only one CachedResource for a particular group-version-resource triplet in the workspace.
- The resource must be cluster scoped.
- The resource must not be a built-in API or kcp system API belonging to
apis.kcp.iogroup. - The resource may be originating from a CRD or an APIBinding.
Once created, resource replication progress may be checked in CachedResource's status:
apiVersion: cache.kcp.io/v1alpha1
kind: CachedResource
metadata:
name: cpuflavors-v1
status:
conditions:
- lastTransitionTime: "2025-10-21T14:03:41Z"
status: "True"
type: IdentityValid
- lastTransitionTime: "2025-10-21T14:03:42Z"
status: "True"
type: ReplicationStarted
- lastTransitionTime: "2025-10-21T14:03:41Z"
status: "True"
type: ResourceValid
identityHash: cd2eb0837...
phase: Ready
resourceCounts:
cache: 8 # (1)
local: 8 # (2)
cacheresource count refers to the count of objects currently in cache for this CachedResource.localresource count refers to the count of objects the CachedResource currently sees in its workspace.
The objects a CachedResource is watching are always replicated in the direction from CachedResource's workspace into cache. Note that this means the only way to modify the in-cache copies is to modify the original objects. In-cache objects can be then projected into a workspace as a read-only API. This is done by creating a respective APIExport with CachedResource virtual resource, and binding to it.
flowchart TD
cacheServer["Cache server"]
subgraph provider["API Provider Workspace"]
cpuflavorsCRD["CPUFlavors CRD"]
cpuflavorCRs["CPUFlavor objects..."]
cpuflavorsCachedResource["CPUFlavors CachedResource"]
cpuflavorCRs -."From".-> cpuflavorsCRD
cpuflavorsCachedResource -.Watches.-> cpuflavorCRs
end
cpuflavorsCachedResource -."Replicates CPUFlavor objects into".-> cacheServer
You can optionally configure the following additional aspects of a CachedResource:
- its identity
- its endpoint slice
- resource selector
We'll talk about each of these next.
CachedResource identity¶
Similar to the APIExport identity concept, there may be many CachedResources with the same group-version-resource triplet across kcp instances. To differentiate between them and identify owners, a CachedResource object uses a unique identity key stored in a secret.
The identity key is considered a private key and should not be shared.
Hash calculated from that key, found at .status.identityHash, is considered a public key. APIExport's virtual resource definition expects this identity hash to be supplied when exporting a CachedResource.
By default, creating a CachedResource object triggers creation of an identity secret with a randomly generated key in its key data item. You can provide your own key by referencing your secret in the object's spec:
apiVersion: v1
kind: Secret
metadata:
name: my-cached-cpuflavors-identity
namespace: default
stringData:
key: "<Your identity key>"
---
apiVersion: cache.kcp.io/v1alpha1
kind: CachedResource
metadata:
name: cpuflavors-v1
spec:
identity:
secretRef:
name: my-cached-cpuflavors-identity
namespace: default
...
CachedResourceEndpointSlice¶
While CachedResources replicates their associated resources to the cache server, retrieval of these in-cache resources is done through the Replication virtual workspace. The Replication VW is an API server dedicated to CachedResources, and is able to access the resource's objects with read-only verbs get, list and watch.
The Replication VW endpoints are listed in CachedResourceEndpointSlice. This endpoint slice is compatible with APIExport's virtual resources and can be used as storage source.
With that said, the Replication VW is consumer-aware, and needs a valid APIExport and APIBinding(s) to operate. Therefore it is much more convenient to access the in-cache resources through regular APIBindings in a workspace and/or the APIExport VW rather than accessing them through the Replication VW. Consider the Replication VW just as an implementation detail of the CachedResource API, and when consuming it, use APIExports.
flowchart TD
cacheServer["Cache server"]
replicationVW["Replication VW"]
subgraph provider["API Provider Workspace"]
cpuflavorsCachedResource["CPUFlavors CachedResource"]
cpuflavorsCachedResourceEndpointSlice["CPUFlavors CachedResourceEndpointSlice"]
cpuflavorsCachedResourceEndpointSlice --> cpuflavorsCachedResource
end
replicationVW -."Reads from".-> cacheServer
cpuflavorsCachedResourceEndpointSlice -."Has an endpoint for".-> replicationVW
For convenience, creating a CachedResource triggers creation of a CachedResourceEndpointSlice object under the same name. This behaviour can be disabled by adding cachedresources.cache.kcp.io/skip-endpointslice annotation to the CachedResource object. You can create your own like so:
apiVersion: cache.kcp.io/v1alpha1
kind: CachedResourceEndpointSlice
metadata:
name: cpuflavors-v1
spec:
cachedResource:
name: cpuflavors-v1 # (1)
- Name of the CachedResource this endpoint slice is referencing. Currently, both CachedResource and CachedResourceEndpointSlice must be co-located in the same workspace. See https://github.com/kcp-dev/kcp/issues/3658
Selectors¶
CachedResource spec has an optional labelSelector field which can be used to shape the set of objects it picks up.
apiVersion: cache.kcp.io/v1alpha1
kind: CachedResource
metadata:
name: cpuflavors-v1
spec:
group: cloud.example.com
version: v1
resource: cpuflavors
labelSelector:
cloud.example.com/visibility: Public
Exporting CachedResources¶
You can project the replicated read-only objects of a CachedResource into a workspace using the standard APIExport-APIBinding relationship. Create an APIExport and define virtual resource for the associated CachedResourceEndpointSlice. Consumers can then bind to it.
apiVersion: apis.kcp.io/v1alpha2
kind: APIExport
metadata:
name: compute.cloud.example.com
spec:
resources:
- group: cloud.example.com
name: cpuflavors
schema: v250801.cpuflavors.cloud.example.com # (1)
storage:
virtual:
reference: # (2)
apiGroup: cache.kcp.io
kind: CachedResourceEndpointSlice
name: cpuflavors-v1
identityHash: cd2eb0837... # (3)
- Resource schema must match the schema used by the resource in the associated CachedResource.
- Reference to the CachedResourceEndpointSlice endpoint slice
cpuflavors-v1. - Identity hash of the
cpuflavors-v1CachedResource object.
A virtual storage definition needs (1) a reference to an endpoint slice object, and (2) a virtual resource identity. In the case of CachedResources, the endpoint slice is provided by CachedResourceEndpointSlice. For convenience, a matching CachedResourceEndpointSlice object is automatically created when creating a CachedResource. The identity hash must match the one set in CachedResource's .status.identityHash.
flowchart TD
subgraph provider["API Provider Workspace"]
export["CPUFlavors APIExport"]
schema["CPUFlavors APIResourceSchema"]
crd["CPUFlavors CRD"]
cpuflavorsCachedResourceEndpointSlice["CPUFlavors CachedResourceEndpointSlice"]
export --> schema
export --> cpuflavorsCachedResourceEndpointSlice
schema -."Is equivalent to".-> crd
end
subgraph consumer1["Consumer Workspace"]
binding["CPUFlavors APIBinding"]
boundCPUFlavorVirtualResources["CPUFlavor objects..."]
binding -."Projects CPUFlavors API from Replication VW".-> boundCPUFlavorVirtualResources
end
export --> binding
Note the APIResourceSchema referenced by the APIExport example above: the Replication VW follows that reference, and that schema is then used to serve the resource in consumers' workspaces. The provider must therefore ensure that it is kept in-sync with the schema of the original resource.