Repository navigation
Custom resource reflection for namespace offloading (OwnershipShared) #3330
Description
Describe the problem you are having (if any)
Liqo namespace offloading extends a namespace across clusters and reflects a fixed set of native Kubernetes resources (ConfigMaps, Secrets, Services, PVCs, etc.) through the Virtual Kubelet. It does not support user-defined Custom Resources (CRs).
This is a blocker for multi-cluster setups where:
- A consumer offloads a namespace to a provider (twin namespace).
- CRs are created or updated on the consumer.
- A controller on the provider reconciles the remote CR and writes its status.
- The consumer needs the desired
specpropagated remotely and the resultingstatusreflected locally.
Historically, Liqo supported peering-level CR replication through the CRD replicator, but that mechanism was removed and was not integrated with namespace offloading. There is currently no supported, generic way to reflect selected namespaced GVRs across an offloaded namespace pair.
Describe the solution you would like
Add generic, opt-in Custom Resource reflection to the Virtual Kubelet.
Operators configure arbitrary namespaced Group/Version/Resources (GVRs) through Helm:
offloading:
reflection:
customResources:
- group: example.io
version: v1
resource: widgets
workers: 2
type: AllowListThe configuration is propagated to VkOptionsTemplate. For every configured GVR, the Virtual Kubelet starts a dynamic, unstructured reflector when a namespace is activated through the existing NamespaceMap lifecycle.
Reflection follows OwnershipShared semantics:
spec: consumer/local → provider/remotestatus: provider/remote → consumer/local
Custom Resource reflection defaults to AllowList. Individual CR instances opt in with:
metadata:
annotations:
liqo.io/allow-reflection: "true"An empty customResources list means that Custom Resource reflection is disabled. No application-specific CRDs are hardcoded in Liqo.
Describe the user value of this feature
- Enables operators based on Custom Resources to work across offloaded namespaces.
- Preserves clear ownership: the consumer owns desired state, while the provider reconciles it and owns status.
- Reuses the existing Virtual Kubelet reflection model and namespace lifecycle.
- Supports arbitrary namespaced CRDs without coupling Liqo to a specific application or operator.
- Keeps the feature disabled by default and requires explicit GVR and per-object opt-in.
Describe your proposed solution
The implementation is centered on the Virtual Kubelet reflection subsystem rather than changes to NamespaceOffloading or new liqoctl flags.
Configuration and API
- Add a
customResourceslist toVkOptionsTemplate. - Expose it through the Helm value
offloading.reflection.customResources. - Each entry contains
group,version,resource,workers, and reflectiontype. - Do not add
customResourcestoNamespaceOffloading. - Do not add a
liqoctl --replicate-crflag.
Reflection
- Implement a generic reflector using dynamic Kubernetes clients and unstructured objects.
- Register one reflector for each configured GVR.
- Start and stop reflectors through the existing
NamespaceMap/ Virtual Kubelet namespace lifecycle. - Create or update the remote object from the local desired state.
- Propagate remote status back through the local status subresource.
- Preserve the normal Liqo reflection annotations, labels, policies, and cleanup behavior.
RBAC
- Generate local and remote Virtual Kubelet RBAC rules from the configured GVR list.
- Grant only the verbs required for reflection and status synchronization.
- Keep the default RBAC unchanged when the list is empty.
MVP scope and limitations
- OwnershipShared semantics only:
speclocal → remote andstatusremote → local. - Namespaced Custom Resources only; cluster-scoped resources are not supported.
- Compatible CRDs must already exist on both clusters; Liqo does not install CRDs.
- Default policy is
AllowListusingliqo.io/allow-reflection: "true". - Existing VirtualNodes may need to be recreated or re-peered after changing the configured GVR list so that configuration and RBAC are refreshed.
- The controller for a reflected type should run on one side only to prevent competing reconciliations.
- Remote changes to
specare overwritten by the local desired state. - Cross-resource references and hardcoded namespaces inside a CR are copied as-is and may require application-level handling.
Validation
The design has been validated with bidirectional peering and selected-name namespace mappings:
- Annotated CR instances were reflected from the consumer namespace to its remote twin.
- Provider-side status updates were reflected back to the local CR.
- Unannotated CR instances were not reflected under the default AllowList policy.
- No application-specific CRD types were required in the implementation.
Do you volunteer to implement this feature?
- I want to implement this feature
Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
[-]Custom resource replication for namespace offloading (RemoteToLocal)[/-][+]Custom resource replication for namespace offloading (Bidirectional + RemoteToLocal)[/+][-]Custom resource replication for namespace offloading (Bidirectional + RemoteToLocal)[/-][+]Custom resource replication for namespace offloading (OwnershipShared)[/+][-]Custom resource replication for namespace offloading (OwnershipShared)[/-][+]Custom resource reflection for namespace offloading (OwnershipShared)[/+]